diff --git a/.editorconfig b/.editorconfig
index a84f86c..41e9eef 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -15,4 +15,7 @@ end_of_line = crlf
[*.yml]
indent_style = space
-indent_size = 2
\ No newline at end of file
+indent_size = 2
+
+[*.neon]
+indent_style = tab
diff --git a/.gitattributes b/.gitattributes
index 17493ec..931f1a3 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,7 +2,9 @@
.editorconfig export-ignore
.gitattributes export-ignore
.gitignore export-ignore
-.semver export-ignore
+.github export-ignore
phpunit.xml.dist export-ignore
-.travis.yml export-ignore
tests export-ignore
+psalm.xml export-ignore
+psalm-baseline.xml export-ignore
+phpstan.neon export-ignore
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..1b40453
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,21 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - '*'
+
+permissions:
+ contents: read
+
+jobs:
+ testsuite:
+ uses: ADmad/.github/.github/workflows/testsuite-with-db.yml@master
+ secrets:
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
+
+ cs-stan:
+ uses: ADmad/.github/.github/workflows/cs-stan.yml@master
diff --git a/.gitignore b/.gitignore
index 364f9bd..e8bd129 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
/composer.lock
/plugins
/vendor
+.phpunit.cache
+.phpunit.result.cache
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 33a5876..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,56 +0,0 @@
-language: php
-
-php:
- - 5.6
- - 7.4
-
-services:
- - mysql
- - postgresql
-
-env:
- matrix:
- - DB=mysql db_dsn='mysql://root@127.0.0.1/cakephp_test'
- - DB=pgsql db_dsn='postgres://postgres@127.0.0.1/cakephp_test'
- - DB=sqlite db_dsn='sqlite:///:memory:'
-
- global:
- - DEFAULT=1
-
-matrix:
- fast_finish: true
-
- include:
- - php: 7.2
- env: PHPCS=1 DEFAULT=0
-
- - php: 7.2
- env: PHPSTAN=1 DEFAULT=0
-
- - php: 5.6
- env: PREFER_LOWEST=1
-
-before_script:
- - if [[ $TRAVIS_PHP_VERSION != 7.4 ]]; then phpenv config-rm xdebug.ini; fi
-
- - if [[ $PREFER_LOWEST != 1 ]]; then composer install --no-interaction; fi
- - if [[ $PREFER_LOWEST = 1 ]]; then composer update --no-interaction --prefer-lowest --prefer-stable; fi
-
- - if [[ $DB = 'mysql' ]]; then mysql -e 'CREATE DATABASE cakephp_test;'; fi
- - if [[ $DB = 'pgsql' ]]; then psql -c 'CREATE DATABASE cakephp_test;' -U postgres; fi
-
- - if [[ $PHPCS = 1 ]]; then composer require cakephp/cakephp-codesniffer:"^3.0"; fi
-
-script:
- - if [[ $DEFAULT = 1 && $TRAVIS_PHP_VERSION != 7.4 ]]; then vendor/bin/phpunit; fi
- - if [[ $DEFAULT = 1 && $TRAVIS_PHP_VERSION = 7.4 ]]; then vendor/bin/phpunit --coverage-clover=clover.xml; fi
-
- - if [[ $PHPCS = 1 ]]; then vendor/bin/phpcs -n -p --extensions=php --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests; fi
-
- - if [[ $PHPSTAN = 1 ]]; then composer require --dev phpstan/phpstan:^0.12 && vendor/bin/phpstan analyse -l 5 src; fi
-
-after_success:
- - if [[ $DEFAULT = 1 && $TRAVIS_PHP_VERSION = 7.4 ]]; then bash <(curl -s https://codecov.io/bash); fi
-
-notifications:
- email: false
diff --git a/LICENSE.txt b/LICENSE.txt
index 5137da5..d7be439 100644
--- a/LICENSE.txt
+++ b/LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright (c) 2015 Use Muffin
+Copyright (c) 2015-Present Use Muffin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 4ed6593..e2bdef6 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,8 @@
# Orderly
-[](https://travis-ci.org/UseMuffin/Orderly)
-[](https://codecov.io/github/UseMuffin/Orderly)
+[](https://github.com/UseMuffin/Orderly/actions/workflows/ci.yml?query=branch%3Amaster)
+[](https://app.codecov.io/gh/UseMuffin/Orderly)
[](https://packagist.org/packages/muffin/orderly)
[](LICENSE)
@@ -11,20 +12,19 @@ Allows setting default order for your tables.
Using [Composer][composer]:
-```
+```sh
composer require muffin/orderly
```
Then load the plugin using the console command:
-```
+```sh
bin/cake plugin load Muffin/Orderly
```
## What is does
-Orderly allow you to set default `ORDER` clause for your table queries, similar
-to the functionality provided by `Model::$order` property of CakePHP 2.x.
+Orderly allow you to set default `ORDER` clause for your table's `SELECT` queries.
## Usage
@@ -38,7 +38,7 @@ $this->addBehavior('Muffin/Orderly.Orderly');
$this->addBehavior('Muffin/Orderly.Orderly', ['order' => $this->aliasField('field_name')]);
```
-Value for `order` key can any valid value that `\Cake\ORM\Query::order()` takes.
+Value for `order` key can any valid value that `\Cake\ORM\Query\SelectQuery::orderBy()` takes.
The default order clause will only be applied to the primary query and when no
custom order clause has already been set for the query.
@@ -48,7 +48,7 @@ condition using `callback` option. The order will be applied if callback returns
```php
$this->addBehavior('Muffin/Orderly.Orderly', [
'order' => ['Alias.field_name' => 'DESC'],
- 'callback' => function (\Cake\ORM\Query $query, \ArrayObject $options, $primary) {
+ 'callback' => function (SelectQuery $query, ArrayObject $options, bool $primary) {
//return a boolean
}
]);
@@ -61,13 +61,13 @@ on return value of their respective callbacks:
$this->addBehavior('Muffin/Orderly.Orderly', [
[
'order' => ['Alias.field_name' => 'DESC'],
- 'callback' => function (\Cake\ORM\Query $query, \ArrayObject $options, $primary) {
+ 'callback' => function (SelectQuery $query, ArrayObject $options, bool $primary) {
//return a boolean
}
],
[
'order' => ['Alias.another_field'],
- 'callback' => function (\Cake\ORM\Query $query, \ArrayObject $options, $primary) {
+ 'callback' => function (SelectQuery $query, ArrayObject $options, bool $primary) {
//return a boolean
}
],
@@ -97,4 +97,4 @@ Copyright (c) 2015-Present, [Use Muffin][muffin] and licensed under [The MIT Lic
[composer]:http://getcomposer.org
[mit]:http://www.opensource.org/licenses/mit-license.php
[muffin]:http://usemuffin.com
-[standards]:http://book.cakephp.org/3/en/contributing/cakephp-coding-conventions.html
+[standards]:http://book.cakephp.org/5/en/contributing/cakephp-coding-conventions.html
diff --git a/composer.json b/composer.json
index 3f49c56..f1743d9 100644
--- a/composer.json
+++ b/composer.json
@@ -1,6 +1,6 @@
{
"name": "muffin/orderly",
- "description": "Default ordering (behavior) for CakePHP 3",
+ "description": "Default ordering (behavior) for CakePHP",
"type": "cakephp-plugin",
"keywords": [
"cakephp",
@@ -30,12 +30,11 @@
"source": "https://github.com/usemuffin/orderly"
},
"require": {
- "cakephp/orm": "^3.4"
+ "cakephp/orm": "^5.0"
},
"require-dev": {
- "cakephp/cakephp": "^3.4",
- "cakephp/chronos": "^1.1",
- "phpunit/phpunit": "^5.7.14|^6.0"
+ "cakephp/cakephp": "^5.0",
+ "phpunit/phpunit": "^10.5.58 || ^11.5.3 || ^12.4"
},
"autoload": {
"psr-4": {
@@ -47,5 +46,11 @@
"Muffin\\Orderly\\Test\\": "tests",
"Cake\\Test\\Fixture\\": "vendor/cakephp/cakephp/tests/Fixture"
}
+ },
+ "config": {
+ "sort-packages": true,
+ "allow-plugins": {
+ "dealerdirect/phpcodesniffer-composer-installer": true
+ }
}
}
diff --git a/phpcs.xml b/phpcs.xml
new file mode 100644
index 0000000..e39be6f
--- /dev/null
+++ b/phpcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+ src/
+ tests/
+
\ No newline at end of file
diff --git a/phpstan.neon b/phpstan.neon
new file mode 100644
index 0000000..4ee867a
--- /dev/null
+++ b/phpstan.neon
@@ -0,0 +1,9 @@
+parameters:
+ level: 7
+ treatPhpDocTypesAsCertain: false
+ bootstrapFiles:
+ - tests/bootstrap.php
+ paths:
+ - src
+ ignoreErrors:
+ - identifier: missingType.generics
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 00aa220..288487c 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -1,30 +1,19 @@
-
-
+
./tests/
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
./src/
-
-
+
+
diff --git a/psalm.xml b/psalm.xml
new file mode 100644
index 0000000..442fe0f
--- /dev/null
+++ b/psalm.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Model/Behavior/OrderlyBehavior.php b/src/Model/Behavior/OrderlyBehavior.php
index 9ad71a5..cdff8e7 100644
--- a/src/Model/Behavior/OrderlyBehavior.php
+++ b/src/Model/Behavior/OrderlyBehavior.php
@@ -1,20 +1,22 @@
$config Config
* @return void
*/
- public function initialize(array $config)
+ public function initialize(array $config): void
{
parent::initialize($config);
@@ -22,15 +24,15 @@ public function initialize(array $config)
}
/**
- * Add default order clause to query as necessary.
+ * Add the default order clause to the query as necessary.
*
- * @param \Cake\Event\Event $event Event
- * @param \Cake\ORM\Query $query Query
+ * @param \Cake\Event\EventInterface $event Event
+ * @param \Cake\ORM\Query\SelectQuery $query Query
* @param \ArrayObject $options Options
* @param bool $primary Boolean indicating whether it's primary query.
* @return void
*/
- public function beforeFind(Event $event, Query $query, ArrayObject $options, $primary)
+ public function beforeFind(EventInterface $event, SelectQuery $query, ArrayObject $options, bool $primary): void
{
if ($query->clause('order')) {
return;
@@ -42,7 +44,7 @@ public function beforeFind(Event $event, Query $query, ArrayObject $options, $pr
empty($config['callback'])
|| call_user_func($config['callback'], $query, $options, $primary)
) {
- $query->order($config['order']);
+ $query->orderBy($config['order']);
}
}
}
@@ -50,19 +52,24 @@ public function beforeFind(Event $event, Query $query, ArrayObject $options, $pr
/**
* Normalize configuration.
*
- * @param mixed $orders Orders config
+ * @param array $orders Orders config
* @return void
*/
- protected function _normalizeConfig($orders)
+ protected function _normalizeConfig(array $orders): void
{
- if (empty($orders)) {
+ unset($orders['className']);
+
+ if ($orders === []) {
$orders = [[]];
} elseif (isset($orders['order']) || isset($orders['callback'])) {
$orders = [$orders];
}
$default = [
- 'order' => $this->_table->aliasField($this->_table->getDisplayField()),
+ 'order' => array_map(
+ $this->_table->aliasField(...),
+ (array)$this->_table->getDisplayField(),
+ ),
'callback' => null,
];
diff --git a/src/OrderlyPlugin.php b/src/OrderlyPlugin.php
new file mode 100644
index 0000000..3d4f572
--- /dev/null
+++ b/src/OrderlyPlugin.php
@@ -0,0 +1,37 @@
+Table = TableRegistry::get('Posts');
+ $this->Table = $this->getTableLocator()->get('Posts');
}
- public function tearDown()
+ public function tearDown(): void
{
parent::tearDown();
- TableRegistry::clear();
- unset($this->Table, $this->Behavior);
+ $this->getTableLocator()->clear();
+ unset($this->Table);
}
public function testInitialize()
@@ -33,13 +38,13 @@ public function testInitialize()
$expected = [
[
- 'order' => $this->Table->aliasField($this->Table->getDisplayField()),
+ 'order' => ['Posts.title'],
'callback' => null,
],
];
$this->assertEquals(
$expected,
- $this->Table->behaviors()->Orderly->getConfig()['orders']
+ $this->Table->behaviors()->Orderly->getConfig()['orders'],
);
$this->Table->removeBehavior('Orderly');
@@ -53,7 +58,7 @@ public function testInitialize()
];
$this->assertEquals(
$expected,
- $this->Table->behaviors()->Orderly->getConfig()['orders']
+ $this->Table->behaviors()->Orderly->getConfig()['orders'],
);
$callback = function () {
@@ -64,13 +69,13 @@ public function testInitialize()
$expected = [
[
- 'order' => 'Posts.title',
+ 'order' => ['Posts.title'],
'callback' => $callback,
],
];
$this->assertEquals(
$expected,
- $this->Table->behaviors()->Orderly->getConfig()['orders']
+ $this->Table->behaviors()->Orderly->getConfig()['orders'],
);
$this->Table->removeBehavior('Orderly');
@@ -81,7 +86,7 @@ public function testInitialize()
$expected = [
[
- 'order' => 'Posts.title',
+ 'order' => ['Posts.title'],
'callback' => null,
],
[
@@ -91,7 +96,7 @@ public function testInitialize()
];
$this->assertEquals(
$expected,
- $this->Table->behaviors()->Orderly->getConfig()['orders']
+ $this->Table->behaviors()->Orderly->getConfig()['orders'],
);
}
@@ -102,7 +107,7 @@ public function testBeforeFind()
$event = new Event('Model.beforeFind', $this);
$query = $this->Table->query();
- $behavior->beforeFind($event, $query, new \ArrayObject(), true);
+ $behavior->beforeFind($event, $query, new ArrayObject(), true);
$this->assertEquals(1, count($query->clause('order')));
}
@@ -113,8 +118,8 @@ public function testBeforeFindQueryWithOrder()
$event = new Event('Model.beforeFind', $this);
$query = $this->Table->find()
- ->order('author_id');
- $behavior->beforeFind($event, $query, new \ArrayObject(), true);
+ ->orderBy('author_id');
+ $behavior->beforeFind($event, $query, new ArrayObject(), true);
$this->assertEquals(1, count($query->clause('order')));
}
@@ -147,24 +152,24 @@ public function testCallback()
$event = new Event('Model.beforeFind', $this);
$query = $this->Table->find();
- $behavior->beforeFind($event, $query, new \ArrayObject(['field' => null]), true);
+ $behavior->beforeFind($event, $query, new ArrayObject(['field' => null]), true);
$this->assertNull($query->clause('order'));
$valueBinder = new ValueBinder();
- $behavior->beforeFind($event, $query, new \ArrayObject(['field' => 'first']), true);
+ $behavior->beforeFind($event, $query, new ArrayObject(['field' => 'first']), true);
$orderClause = $query->clause('order');
$this->assertCount(1, $orderClause);
$this->assertEquals('ORDER BY first', $orderClause->sql($valueBinder));
$query = $this->Table->find();
- $behavior->beforeFind($event, $query, new \ArrayObject(['field' => 'second']), true);
+ $behavior->beforeFind($event, $query, new ArrayObject(['field' => 'second']), true);
$orderClause = $query->clause('order');
$this->assertCount(1, $orderClause);
$this->assertEquals('ORDER BY second', $orderClause->sql($valueBinder));
$query = $this->Table->find();
- $behavior->beforeFind($event, $query, new \ArrayObject(['field' => '_all_']), true);
+ $behavior->beforeFind($event, $query, new ArrayObject(['field' => '_all_']), true);
$orderClause = $query->clause('order');
$this->assertCount(2, $orderClause);
$this->assertEquals('ORDER BY first, second', $orderClause->sql($valueBinder));
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index c6dc570..a66fd87 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -1,4 +1,6 @@
'posts',
+ 'columns' => [
+ 'id' => [
+ 'type' => 'integer',
+ ],
+ 'author_id' => [
+ 'type' => 'integer',
+ 'null' => false,
+ ],
+ 'title' => [
+ 'type' => 'string',
+ 'null' => false,
+ ],
+ 'body' => 'text',
+ 'published' => [
+ 'type' => 'string',
+ 'length' => 1,
+ 'default' => 'N',
+ ],
+ ],
+ 'constraints' => [
+ 'primary' => [
+ 'type' => 'primary',
+ 'columns' => [
+ 'id',
+ ],
+ ],
+ ],
+ ],
+];