Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
b862395
Fix PHPUnit 9 deprecations.
kevindecapite Jun 26, 2025
c2b8fdd
vendor/bin/phpunit --migrate-configuration
kevindecapite Jun 26, 2025
b427932
Fix CakePHP 4.x deprecations.
kevindecapite Jun 26, 2025
728ba22
Upgrade to new fixture management per CakePHP 4.3.0.
kevindecapite Jun 27, 2025
d2862c0
Refactor match() to switch in JsonApiListenerTest.
kevindecapite Jun 27, 2025
c35b6a9
Use actions/cache@v4 in GitHub workflow ci.yml.
kevindecapite Jun 27, 2025
be0deb2
Make PHP 8.1 lowest-supported version.
kevindecapite Jun 27, 2025
d7939c3
Set composer.json requirements:
kevindecapite Jun 30, 2025
373cf25
Change type declarations and method signatures per Cake 5 upgrade.
kevindecapite Jun 30, 2025
857a997
ORM: fetchTable() instead of ProxyTrait::_table(); orderBy() instead …
kevindecapite Jun 30, 2025
0188935
Remove RequestHandler component from test_app controllers.
kevindecapite Jun 30, 2025
3ccf903
Update tests/bootstrap.php per Cake 5 upgrade.
kevindecapite Jun 30, 2025
6847552
Update PaginationListener.
kevindecapite Jun 30, 2025
5c4e201
Add missing use statements for Cake functions.
kevindecapite Jun 30, 2025
3d5a764
Add missing routes to test_app routes.
kevindecapite Jun 30, 2025
3661893
Change JsonApiListener::_getSingleEntity() return to support entity v…
kevindecapite Jun 30, 2025
0620078
Refactor tests per PHPUnit 10.5.5 upgrade.
kevindecapite Jun 30, 2025
5df1c30
Fix PHPUnit 10 deprecations.
kevindecapite Jun 30, 2025
80c215b
Remove psalm from GH workflow.
kevindecapite Jun 30, 2025
5256734
Apply codesniffer checks & fixes; manual fixes as needed.
kevindecapite Jun 30, 2025
23c8820
Fix phpstan issues.
kevindecapite Jun 30, 2025
5c4ded2
composer require laravel-json-api/neomerx-json-api:^5.0.2
kevindecapite Jun 30, 2025
a9d937c
Fix type declaration breakages from codesniffer cleanup.
kevindecapite Jun 30, 2025
de4117b
composer require friendsofcake/crud:^7.2.0
kevindecapite Jun 30, 2025
026e417
Use SelectQuery instead if Query in JsonApiListener.
kevindecapite Jun 30, 2025
3108fbb
Re-use InstanceConfigTrait in JsonApiView to make getConfig() public …
kevindecapite Jun 30, 2025
eaff92b
Add _cake_core_ cache config to tests/bootstrap.php for BC.
kevindecapite Jun 30, 2025
fceb68a
Define many-to-many CountriesLanguages through model in test_app.
kevindecapite Jun 30, 2025
f6d94fb
Replace switch with match() in JsonApiListenerTest.
kevindecapite Jun 30, 2025
7522a88
Rename plugin to CrudJsonApiPlugin.
kevindecapite Jun 30, 2025
d143d75
Remove ModelAwareTrait from JsonApiExceptionRendererTest.
kevindecapite Jun 30, 2025
a146267
Use fully qualified names where appropriate.
kevindecapite Jun 30, 2025
a0a1bee
Make entity return check sensible in JsonApiListener::_getSingleEntit…
kevindecapite Jul 1, 2025
df37bbc
Fix CS errors
ADmad Jul 1, 2025
a5f76b5
Fix phpstan errors
ADmad Jul 1, 2025
7695d33
Fix CS errors
ADmad Jul 1, 2025
a67d5be
Update CI config
ADmad Jul 1, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 12 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ on:

jobs:
testsuite:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
php-version: [ '7.4', '8.0', '8.1' ]
php-version: [ '8.1', '8.2', '8.3', '8.4' ]
db-type: [ mysql ]
prefer-lowest: ['']
include:
- php-version: '7.4'
- php-version: '8.1'
db-type: 'mysql'
prefer-lowest: 'prefer-lowest'

Expand Down Expand Up @@ -49,7 +49,7 @@ jobs:
run: echo "::set-output name=date::$(date +'%Y-%m')"

- name: Cache composer dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ steps.key-date.outputs.date }}-${{ hashFiles('composer.json') }}
Expand All @@ -62,35 +62,22 @@ jobs:
composer update
fi

- name: Configure PHPUnit matcher
if: matrix.php-version == '7.4' && matrix.db-type == 'mysql'
uses: mheap/phpunit-matcher-action@v1

- name: Run PHPUnit
run: |
if [[ ${{ matrix.db-type }} == 'mysql' && ${{ matrix.php-version }} != '7.2' ]]; then export DB_URL='mysql://root:[email protected]/cakephp?init[]=SET sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"'; fi
if [[ ${{ matrix.db-type }} == 'mysql' && ${{ matrix.php-version }} == '7.2' ]]; then export DB_URL='mysql://root:[email protected]/cakephp?encoding=utf8'; fi
if [[ ${{ matrix.db-type }} == 'mysql' && ${{ matrix.php-version }} == '7.4' ]]; then
vendor/bin/phpunit --coverage-clover=coverage.xml --verbose
else
vendor/bin/phpunit
fi

- name: Code Coverage Report
if: success() && matrix.php-version == '7.4' && matrix.db-type == 'mysql'
uses: codecov/codecov-action@v3
export DB_URL='mysql://root:[email protected]/cakephp?init[]=SET sql_mode = "STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"'
vendor/bin/phpunit --display-incomplete --display-skipped --display-warnings --display-deprecations

coding-standard:
name: Coding Standard
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
php-version: '8.1'
extensions: mbstring, intl, apcu
coverage: none

Expand All @@ -103,7 +90,7 @@ jobs:
run: echo "::set-output name=date::$(date +'%Y-%m')"

- name: Cache composer dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ steps.key-date.outputs.date }}-${{ hashFiles('composer.json') }}
Expand All @@ -116,15 +103,15 @@ jobs:

static-analysis:
name: Static Analysis
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04

steps:
- uses: actions/checkout@v3

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '7.4'
php-version: '8.1'
extensions: mbstring, intl, apcu
coverage: none
tools: cs2pr
Expand All @@ -138,16 +125,13 @@ jobs:
run: echo "::set-output name=date::$(date +'%Y-%m')"

- name: Cache composer dependencies
uses: actions/cache@v1
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ steps.key-date.outputs.date }}-${{ hashFiles('composer.json') }}

- name: composer install
run: composer stan-setup

- name: Run psalm
run: vendor/bin/psalm.phar --output-format=github

- name: Run phpstan
run: vendor/bin/phpstan.phar analyse --error-format=checkstyle ./src | cs2pr
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ vendor/
composer.lock
tmp
.phpunit.result.cache
.phpunit.cache
25 changes: 10 additions & 15 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@
}
],
"require": {
"php": ">=7.4.0",
"cakephp/cakephp": "^4.4.1",
"friendsofcake/crud": "^6.0",
"laravel-json-api/neomerx-json-api": "^5.0"
"php": ">=8.1.0",
"cakephp/cakephp": "^5.0.0",
"friendsofcake/crud": "^7.2.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"laravel-json-api/neomerx-json-api": "^5.0.2"
},
"require-dev": {
"phpunit/phpunit": "~8.5 || ^9.3",
"friendsofcake/cakephp-test-utilities": "^2.0.1",
"friendsofcake/search": "^6.2.2",
"cakephp/cakephp-codesniffer": "^4.0",
"dms/phpunit-arraysubset-asserts": "^0.4.0"
"phpunit/phpunit": "^10.5.5 || ^11.1.3 || ^12.0.9",
"friendsofcake/cakephp-test-utilities": "^3.0.0",
"friendsofcake/search": "^7.0.0",
"cakephp/cakephp-codesniffer": "^5.1",
"dms/phpunit-arraysubset-asserts": "^0.5.0"
},
"autoload": {
"psr-4": {
Expand All @@ -65,13 +65,8 @@
"scripts": {
"cs-check": "phpcs -p --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/",
"cs-fix": "phpcbf --standard=vendor/cakephp/cakephp-codesniffer/CakePHP src/ tests/",
"stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:~1.8.0 psalm/phar:~4.26.0 && mv composer.backup composer.json",
"stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:~2.1.17 && mv composer.backup composer.json",
"phpstan": "phpstan analyse --memory-limit=3G src/",
"psalm": "psalm.phar --show-info=false",
"stan": [
"@phpstan",
"@psalm"
],
"test": "phpunit"
},
"config": {
Expand Down
5 changes: 0 additions & 5 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,3 @@ parameters:
message: "#^Access to an undefined property Cake\\\\Controller\\\\Controller\\:\\:\\$Crud\\.$#"
count: 1
path: src/Listener/PaginationListener.php

-
message: "#^Call to an undefined method Cake\\\\Datasource\\\\EntityInterface\\:\\:visibleProperties\\(\\)\\.$#"
count: 1
path: src/Schema/JsonApi/DynamicEntitySchema.php
5 changes: 3 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ parameters:
level: 6
paths:
- src
checkMissingIterableValueType: false
checkGenericClassInNonGenericObjectType: false
universalObjectCratesClasses:
- Crud\Event\Subject
bootstrapFiles:
- vendor/cakephp/cakephp/src/Core/Exception/CakeException.php
ignoreErrors:
- identifier: missingType.iterableValue
- identifier: missingType.generics
48 changes: 22 additions & 26 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,28 +1,24 @@
<?xml version="1.0"?>
<phpunit
colors="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="./tests/bootstrap.php">

<testsuites>
<testsuite name="Crud">
<directory>./tests/</directory>
</testsuite>
</testsuites>

<listeners>
<listener class="\Cake\TestSuite\Fixture\FixtureInjector">
<arguments>
<object class="\Cake\TestSuite\Fixture\FixtureManager" />
</arguments>
</listener>
</listeners>

<filter>
<whitelist>
<directory suffix=".php">./src/</directory>
<directory suffix=".ctp">./src/</directory>
</whitelist>
</filter>

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
colors="true"
processIsolation="false"
stopOnFailure="false"
bootstrap="./tests/bootstrap.php"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd"
cacheDirectory=".phpunit.cache"
>
<extensions>
<bootstrap class="Cake\TestSuite\Fixture\Extension\PHPUnitExtension"/>
</extensions>
<testsuites>
<testsuite name="Crud">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory suffix=".php">./src/</directory>
</include>
</source>
</phpunit>
19 changes: 0 additions & 19 deletions psalm.xml

This file was deleted.

31 changes: 16 additions & 15 deletions src/Action/RelationshipsAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
use Crud\Traits\SerializeTrait;
use Crud\Traits\ViewTrait;
use Crud\Traits\ViewVarTrait;
use function Cake\Core\pluginSplit;
use function Cake\I18n\__;

/**
* Class RelationshipViewAction
Expand All @@ -47,7 +49,7 @@ class RelationshipsAction extends BaseAction
*
* @var array
*/
protected $_defaultConfig = [
protected array $_defaultConfig = [
'enabled' => true,
'scope' => 'entity',
'findMethod' => 'all',
Expand Down Expand Up @@ -150,7 +152,7 @@ public function checkAllowed(): void
protected function _findRelations(Subject $subject): EntityInterface
{
$relationName = $this->_request()->getParam('type');
$table = $this->_table();
$table = $this->_controller()->fetchTable();
$association = $table->getAssociation($relationName);
$targetTable = $association->getTarget();

Expand Down Expand Up @@ -188,7 +190,7 @@ protected function _findRelations(Subject $subject): EntityInterface
->where(
[
$table->aliasField($primaryKey) => $foreignKeyParam,
]
],
)
->contain([
$relationName => [
Expand All @@ -202,7 +204,7 @@ protected function _findRelations(Subject $subject): EntityInterface
'association' => $association,
'repository' => $table,
'query' => $primaryQuery,
]
],
);
$this->_trigger('beforeFind', $subject);
$entity = $subject->query->first();
Expand Down Expand Up @@ -239,7 +241,7 @@ protected function _get(): void
*
* @return void
*/
protected function _delete()
protected function _delete(): void
{
$subject = $this->_subject();
$request = $this->_request();
Expand Down Expand Up @@ -272,7 +274,7 @@ protected function _delete()
$idsToDelete = (array)Hash::extract($data, '{n}.id');
$foreignRecords = $entity->$property;
$entity->$property = [];
foreach ($foreignRecords as $key => $foreignRecord) {
foreach ($foreignRecords as $foreignRecord) {
if (!in_array($foreignRecord->id, $idsToDelete, false)) {
$entity->{$property}[] = $foreignRecord;
}
Expand All @@ -284,7 +286,7 @@ protected function _delete()
$association->setSaveStrategy('replace');
}
$saveMethod = $this->saveMethod();
if ($this->_table()->$saveMethod($entity, $this->saveOptions())) {
if ($this->_controller()->fetchTable()->$saveMethod($entity, $this->saveOptions())) {
$this->_success($subject);

return;
Expand All @@ -298,7 +300,7 @@ protected function _delete()
*
* @return void
*/
protected function _post()
protected function _post(): void
{
$subject = $this->_subject();
$request = $this->_request();
Expand Down Expand Up @@ -333,7 +335,7 @@ protected function _post()
$this->_trigger('beforeSave', $subject);

$saveMethod = $this->saveMethod();
if ($this->_table()->$saveMethod($entity, $this->saveOptions())) {
if ($this->_controller()->fetchTable()->$saveMethod($entity, $this->saveOptions())) {
$this->_success($subject);

return;
Expand All @@ -347,7 +349,7 @@ protected function _post()
*
* @return void
*/
protected function _patch()
protected function _patch(): void
{
$subject = $this->_subject();
$request = $this->_request();
Expand All @@ -363,7 +365,6 @@ protected function _patch()

if (in_array($association->type(), [Association::MANY_TO_ONE, Association::ONE_TO_ONE], true)) {
//Set the relationship to the corresponding entity
/** @psalm-suppress TypeDoesNotContainNull */
if (array_key_exists('id', $data)) {
$entity->{$property} = $foreignTable->get($data['id']);
} elseif ($data === null) {
Expand All @@ -382,7 +383,7 @@ protected function _patch()
$association->setSaveStrategy('replace');
}
$saveMethod = $this->saveMethod();
if ($this->_table()->$saveMethod($entity, $this->saveOptions())) {
if ($this->_controller()->fetchTable()->$saveMethod($entity, $this->saveOptions())) {
$this->_success($subject);

return;
Expand Down Expand Up @@ -442,21 +443,21 @@ protected function getForeignRecords(array $data, Association $association): arr
->where(
[
$association->aliasField($associationPrimaryKey) . ' in' => $idsToAdd,
]
],
)
->all();

if (count($idsToAdd) !== count($foreignRecords)) {
$foundIds = $foreignRecords->extract(
static function ($record) {
return $record->id;
}
},
)
->toArray();
$missingIds = array_diff($idsToAdd, $foundIds);

throw new RecordNotFoundException(
__('Not all requested records could be found. Missing IDs are {0}', implode(', ', $missingIds))
__('Not all requested records could be found. Missing IDs are {0}', implode(', ', $missingIds)),
);
}

Expand Down
Loading
Loading