Skip to content

Commit 266333b

Browse files
committed
Merge branch 'master' into 3/select-field-options
2 parents 12f8e52 + 8d1a2ac commit 266333b

83 files changed

Lines changed: 913 additions & 133 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/compile.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Magento 2 DI compilation
2+
on: ['push', 'pull_request']
3+
4+
jobs:
5+
compile:
6+
name: Magento 2 DI compilation
7+
#runs-on: self-hosted
8+
runs-on: ubuntu-latest
9+
strategy:
10+
matrix:
11+
magento_version: ['2.4.5-p14', '2.4.7-p4', '2.4.7-p7', '2.4.8', '2.4.8-p1', '2.4.8-p2', '2.4.8-p3']
12+
container:
13+
image: yireo/magento2installed:${{ matrix.magento_version }}
14+
steps:
15+
- name: Checkout sources
16+
uses: actions/checkout@v4
17+
18+
- name: Configure Yireo GitLab
19+
run: |
20+
test -n "${{ secrets.GITLAB_TOKEN }}" || exit 0
21+
cd /tmp/magento
22+
composer config gitlab-domains gitlab.yireo.com
23+
composer config --global --auth http-basic.gitlab.yireo.com yireo "${{ secrets.GITLAB_TOKEN }}"
24+
composer config repositories.loki-third-party composer https://gitlab.yireo.com/api/v4/group/loki-third-party/-/packages/composer/packages.json
25+
composer config repositories.loki-checkout composer https://gitlab.yireo.com/api/v4/group/loki-checkout/-/packages/composer/packages.json
26+
27+
- name: Add module source
28+
run: |
29+
COMPOSER_NAME=$(grep '^COMPOSER_NAME=' .module.ini | cut -d= -f2- | tr -d '"')
30+
cp -R ${GITHUB_WORKSPACE} /tmp/magento/package-source
31+
cd /tmp/magento
32+
composer config repositories.local-source path package-source/
33+
composer require --prefer-source ${COMPOSER_NAME}:@dev
34+
35+
- name: Run Magento 2 compilation
36+
run: |
37+
cd /tmp/magento
38+
bin/magento module:enable --all
39+
php -dmemory_limit=-1 bin/magento setup:di:compile
40+

.github/workflows/integration-tests.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
image: yireo/magento2installed:2.4.8-p3
1111
services:
1212
mysql:
13-
image: mysql:8.0
13+
image: yireo/mariadb:10
1414
env:
1515
MYSQL_ROOT_PASSWORD: root
1616
MYSQL_USER: magento2
@@ -30,8 +30,11 @@ jobs:
3030
- name: Checkout sources
3131
uses: actions/checkout@v4
3232

33-
- name: Enable log_bin_trust_function_creators
34-
run: mysql -h mysql -uroot -proot -e "SET GLOBAL log_bin_trust_function_creators=1;"
33+
- name: Apply patch for reporting memory under Alpine
34+
run: cd /tmp/magento && curl -fsSL https://patch-diff.githubusercontent.com/raw/magento/magento2/pull/39216.diff | git apply
35+
36+
- name: Apply patch for changing MySQL client configuration
37+
run: cd /tmp/magento && curl -fsSL https://patch-diff.githubusercontent.com/raw/magento/magento2/pull/40410.diff | git apply
3538

3639
- name: Configure GitLab
3740
run: |
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php // phpcs:ignoreFile
2+
3+
return [
4+
'client-mariadb' => [
5+
'disable-ssl',
6+
],
7+
];
8+

.github/workflows/static-tests.yml

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,26 @@ name: Magento 2 Static Tests
22
on: ['push', 'pull_request']
33

44
jobs:
5-
static-tests:
6-
name: Magento 2 Static Tests
7-
#runs-on: self-hosted
5+
phpcs:
6+
name: Magento PHPCS
7+
runs-on: ubuntu-latest
8+
container:
9+
image: yireo/magento2installed:2.4.8-p3
10+
steps:
11+
- name: Checkout sources
12+
uses: actions/checkout@v4
13+
14+
- name: Run Magento 2 PHPCS Tests
15+
run: |
16+
PHPCS_LEVEL=${{ env.PHPCS_LEVEL }}
17+
test -z "$PHPCS_LEVEL" && PHPCS_LEVEL=$(jq -r '.phpcs_severity // 10' MODULE.json)
18+
test -z "$PHPCS_LEVEL" && PHPCS_LEVEL=10
19+
echo "Testing for PHPCS severity $PHPCS_LEVEL"
20+
cd /tmp/magento
21+
php vendor/bin/phpcs --standard=Magento2 --ignore=Test/,node_modules/ --colors --extensions=php,phtml --severity=$PHPCS_LEVEL ${GITHUB_WORKSPACE}
22+
23+
phpstan:
24+
name: Magento PHPStan
825
runs-on: ubuntu-latest
926
container:
1027
image: yireo/magento2installed:2.4.8-p3
@@ -16,22 +33,30 @@ jobs:
1633
run: |
1734
test -n "${{ secrets.GITLAB_TOKEN }}" || exit 0
1835
cd /tmp/magento
36+
composer config gitlab-domains gitlab.yireo.com
1937
composer config --auth gitlab-token.gitlab.yireo.com ${{ secrets.GITLAB_TOKEN }}
2038
composer config repositories.loki-checkout composer https://gitlab.yireo.com/api/v4/group/loki-checkout/-/packages/composer/packages.json
2139
2240
- name: Add module source
2341
run: |
2442
export COMPOSER_NAME=`cat .module.ini | grep COMPOSER_NAME | cut -f2 -d= | tr -d '"'`
43+
export COMPOSER_DEV_REQUIREMENTS=`jq -r '.["require-dev"] // {} | to_entries | map("\(.key):\(.value)") | join(" ")' composer.json`
2544
cp -R ${GITHUB_WORKSPACE} /tmp/magento/package-source
2645
cd /tmp/magento
2746
composer config repositories.local-source path package-source/
2847
composer config --no-plugins allow-plugins true
48+
composer remove --dev magento/magento-coding-standard
49+
test -z "$COMPOSER_DEV_REQUIREMENTS" || composer require --dev $COMPOSER_DEV_REQUIREMENTS
50+
composer require --dev --prefer-source -- phpstan/phpstan:^2.0 bitexpert/phpstan-magento:^0.42 phpstan/extension-installer
2951
composer require --prefer-source -- ${COMPOSER_NAME}:@dev yireo/magento2-integration-test-helper
30-
composer require --dev --prefer-source -- phpstan/phpstan bitexpert/phpstan-magento phpstan/extension-installer
3152
3253
- name: Run Magento 2 PHPStan Tests
3354
run: |
3455
export COMPOSER_NAME=`cat .module.ini | grep COMPOSER_NAME | cut -f2 -d= | tr -d '"'`
35-
export LEVEL=`echo '<?= json_decode(file_get_contents("MODULE.json"), true)["phpstan_level"];' | php`
36-
php -d memory_limit=4G /tmp/magento/vendor/bin/phpstan analyse --level $LEVEL ${GITHUB_WORKSPACE}
56+
export PHPSTAN_LEVEL=$(jq -r '.phpstan_level // 1' MODULE.json)
57+
test -z "$PHPSTAN_LEVEL" && PHPSTAN_LEVEL=1
58+
test -f /tmp/magento/phpstan.neon || echo 'parameters:' > /tmp/magento/phpstan.neon
59+
echo "Testing for PHPStan level $PHPSTAN_LEVEL"
60+
cd /tmp/magento
61+
php -d memory_limit=4G vendor/bin/phpstan analyse --level $PHPSTAN_LEVEL ${GITHUB_WORKSPACE}
3762

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased]
88

9+
## [0.5.1] - 23 January 2026
10+
### Fixed
11+
- Do not escape JSON
12+
- Make sure visible-flag of columns defaults to true
13+
14+
## [0.5.0] - 21 January 2026
15+
### Added
16+
- Finalize `entity_select`, add type `product_select` and `customer_select`
17+
18+
### Fixed
19+
- Allow fields defined in XML layout only (without provider)
20+
21+
## [0.4.4] - 12 January 2026
22+
### Fixed
23+
- Add new GitHub Action workflows
24+
- Copy generic CI/CD files
25+
- Implement required fields in a simple way
26+
- Implement filtering for array grids
27+
- Allow using `searchable_fields` to *restrict* which fields are searched by the ArrayHandler
28+
929
## [0.4.3] - 30 December 2025
1030
### Fixed
1131
- Default unknown field types to `input`

Component/Form/FormRepository.php

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ public function getItem(): ?DataObject
4646
}
4747
}
4848

49-
$item = $this->getFactory()->create();
49+
try {
50+
$item = $this->getFactory()->create();
51+
} catch (RuntimeException $e) {
52+
return null;
53+
}
54+
5055
$resourceModel = $this->getResourceModel();
5156
if ($resourceModel) {
5257
// @todo: Move this into separate class TableSchema (or use core)
@@ -136,13 +141,17 @@ public function getProvider(): object
136141
return $provider;
137142
}
138143

144+
if (empty($provider)) {
145+
throw new RuntimeException('No provider for block "'.$this->getBlock()->getNameInLayout().'"');
146+
}
147+
139148
$provider = $this->objectManager->get($provider);
140149

141150
if (is_object($provider)) {
142151
return $provider;
143152
}
144153

145-
throw new \RuntimeException('Empty grid provider for block "'.$this->getBlock()->getNameInLayout().'"');
154+
throw new RuntimeException('Empty grid provider for block "'.$this->getBlock()->getNameInLayout().'"');
146155
}
147156

148157
private function getFactory(): object
@@ -195,9 +204,15 @@ public function getModel(): ?object
195204

196205
public function getResourceModel(): ?AbstractDb
197206
{
207+
try {
208+
$providerHandler = $this->getProviderHandler();
209+
} catch (RuntimeException $e) {
210+
return null;
211+
}
212+
198213
$resourceModelClass = $this->getBlock()->getResourceModel();
199214
if (empty($resourceModelClass)) {
200-
$resourceModelClass = $this->getProviderHandler()->getResourceModelClass($this->getProvider());
215+
$resourceModelClass = $providerHandler->getResourceModelClass($this->getProvider());
201216
}
202217

203218
if (empty($resourceModelClass)) {
@@ -206,11 +221,11 @@ public function getResourceModel(): ?AbstractDb
206221

207222
$resourceModel = $this->objectManager->get($resourceModelClass);
208223
if (empty($resourceModel)) {
209-
throw new \RuntimeException('Unable to instantiate resource model from class "'.$resourceModelClass.'"');
224+
throw new RuntimeException('Unable to instantiate resource model from class "'.$resourceModelClass.'"');
210225
}
211226

212227
if (false === $resourceModel instanceof AbstractDb) {
213-
throw new \RuntimeException(
228+
throw new RuntimeException(
214229
'Resource model "'.$resourceModelClass.'" is not an instance of '.AbstractDb::class
215230
);
216231
}

Component/Form/FormViewModel.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,25 @@ public function getFieldsets(): array
119119
foreach ($fields as $field) {
120120
$fieldsetCode = (string)$field->getFieldset();
121121

122+
if (isset($fieldDefinitions[$field->getCode()])) {
123+
unset($fieldDefinitions[$field->getCode()]);
124+
}
125+
126+
if (!empty($fieldsetCode) && array_key_exists($fieldsetCode, $fieldsets)) {
127+
$fieldsets[$fieldsetCode]->addField($field);
128+
continue;
129+
}
130+
131+
$fieldsets['base']->addField($field);
132+
}
133+
134+
foreach ($fieldDefinitions as $fieldDefinitionName => $fieldDefinition) {
135+
if (!isset($fieldDefinition['code'])) {
136+
$fieldDefinition['code'] = $fieldDefinitionName;
137+
}
138+
139+
$field = $this->fieldFactory->create($this->getBlock(), $fieldDefinition);
140+
122141
if (!empty($fieldsetCode) && array_key_exists($fieldsetCode, $fieldsets)) {
123142
$fieldsets[$fieldsetCode]->addField($field);
124143
continue;
@@ -142,10 +161,6 @@ public function getFields(): array
142161
(array)$this->getBlock()->getFields(),
143162
);
144163

145-
if (empty($fields)) {
146-
return $fields;
147-
}
148-
149164
return $fields;
150165
}
151166

Component/Grid/GridRepository.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ public function getProvider()
7171
return $provider;
7272
}
7373

74+
if (empty($provider)) {
75+
throw new RuntimeException('No provider for block "'.$this->getBlock()->getNameInLayout().'"');
76+
}
77+
7478
$provider = $this->objectManager->get($provider);
7579

7680
if (!empty($provider)) {

Component/Grid/GridViewModel.php

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,16 @@
22

33
namespace Loki\AdminComponents\Component\Grid;
44

5-
use Hyva\Admin\ViewModel\HyvaGrid\GridFilterInterface;
65
use Loki\AdminComponents\Grid\Column\Column;
7-
use Loki\AdminComponents\Grid\Filter\Filter;
86
use Loki\AdminComponents\Grid\Filter\FilterFactory;
97
use Loki\AdminComponents\Grid\Filter\StaticFilterInterface;
108
use Loki\AdminComponents\Grid\MassAction\MassActionFactory;
119
use Loki\AdminComponents\Grid\State\FilterState;
1210
use Loki\AdminComponents\Ui\ButtonInterface;
13-
use Magento\Framework\Data\OptionSourceInterface;
1411
use Magento\Framework\DataObject;
1512
use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
1613
use Magento\Framework\ObjectManagerInterface;
1714
use Magento\Framework\UrlFactory;
18-
use Loki\AdminComponents\Form\Field\Field;
1915
use Loki\AdminComponents\Form\Field\FieldFactory;
2016
use Loki\AdminComponents\Grid\Cell\CellAction;
2117
use Loki\AdminComponents\Grid\Cell\CellActionFactory;
@@ -25,11 +21,9 @@
2521
use Loki\AdminComponents\Grid\MassAction\MassActionInterface;
2622
use Loki\AdminComponents\Grid\State;
2723
use Loki\AdminComponents\Grid\StateManager;
28-
use Loki\AdminComponents\Ui\Button;
2924
use Loki\AdminComponents\Ui\ButtonFactory;
3025
use Loki\Components\Component\ComponentViewModel;
3126
use Loki\Components\Util\CamelCaseConvertor;
32-
use RuntimeException;
3327

3428
/**
3529
* @method GridRepository getRepository()
@@ -98,6 +92,12 @@ public function getItems(): array
9892
return $this->items[$this->getNamespace()];
9993
}
10094

95+
// @todo: Move this to child-class EntitySelectViewModel
96+
public function getCurrentItem(int|string $currentId)
97+
{
98+
return $this->getRepository()->getProviderHandler()->getItem($this->getRepository()->getProvider(), $currentId);
99+
}
100+
101101
public function applyStaticFilters(): void
102102
{
103103
$staticFilters = (array)$this->getBlock()->getStaticFilters();
@@ -179,12 +179,14 @@ public function getColumnPositions(): array
179179
*/
180180
public function getAvailableColumns(): array
181181
{
182-
$columns = $this->columnLoader->getColumns($this->getNamespace());
182+
$columns = $this->columnLoader->getColumnsFromNamespace($this->getNamespace());
183183
if (!empty($columns)) {
184184
return $columns;
185185
}
186186

187-
$columns = $this->getRepository()->getProviderHandler()->getColumns($this->getRepository()->getProvider());
187+
$providerHandler = $this->getRepository()->getProviderHandler();
188+
$provider = $this->getRepository()->getProvider();
189+
$columns = $providerHandler->getColumns($provider);
188190
if (!empty($columns)) {
189191
return $columns;
190192
}
@@ -195,6 +197,10 @@ public function getAvailableColumns(): array
195197
}
196198

197199
$item = array_shift($items);
200+
if (false === $item instanceof DataObject) {
201+
return [];
202+
}
203+
198204
$itemData = $item->getData();
199205
$columns = [];
200206
foreach (array_keys($itemData) as $columnName) {
@@ -210,8 +216,8 @@ public function getAvailableColumns(): array
210216
public function getColumns(): array
211217
{
212218
$columns = $this->getAvailableColumns();
213-
214219
$columnsFromBlock = $this->columnLoader->getColumnsFromBlock($this->block);
220+
215221
if (!empty($columnsFromBlock)) {
216222
foreach ($columnsFromBlock as $columnFromBlock) {
217223
foreach ($columns as $column) {
@@ -227,6 +233,13 @@ public function getColumns(): array
227233
return $this->columnLoader->sortColumns($columns);
228234
}
229235

236+
public function getVisibleColumns(): array
237+
{
238+
return array_filter($this->getColumns(), function(Column $column) {
239+
return $column->isVisible();
240+
});
241+
}
242+
230243
public function getIndexUrl(): string
231244
{
232245
$indexUrl = $this->getBlock()->getData('index_url');

0 commit comments

Comments
 (0)