diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..49d2492 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,84 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + tests: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php-version: ['8.0', '8.1', '8.2', '8.3'] + + name: PHP ${{ matrix.php-version }} + + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: mbstring, intl, pdo_sqlite + coverage: none + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer update --prefer-dist --no-interaction --no-progress + + - name: Run test suite + run: vendor/bin/phpunit + + code-quality: + runs-on: ubuntu-latest + name: Code Quality + + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + extensions: mbstring, intl + coverage: none + tools: cs2pr + + - name: Get composer cache directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies + run: composer update --prefer-dist --no-interaction --no-progress + + - name: Run PHPStan + run: vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr + continue-on-error: true + + - name: Run PHP CS Fixer + run: vendor/bin/php-cs-fixer fix --dry-run --diff --verbose + continue-on-error: true diff --git a/.gitignore b/.gitignore index c6cf386..f30e48b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,7 @@ composer.phar composer.lock .php_cs.cache +.php-cs-fixer.cache +.phpunit.result.cache .DS_Store Thumbs.db \ No newline at end of file diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..8d8e761 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,15 @@ +setStrict() + ->setRule('general_phpdoc_annotation_remove', ['annotations' => ['author']]) + ->getFinder() + ->in(__DIR__) + ->exclude('vendor'); + +return $config; diff --git a/README.md b/README.md index 9e90969..09bd57c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Total Downloads](https://img.shields.io/packagist/dt/riesenia/cakephp-fetchable.svg?style=flat-square)](https://packagist.org/packages/riesenia/cakephp-fetchable) [![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE) -This plugin is for CakePHP 3.x and contains behavior that handles fetching entities +This plugin is for CakePHP 4.x and contains behavior that handles fetching entities from cache / memory storage. Relevant for tables that contain moderate number of rows and are used commonly in many parts of application. diff --git a/composer.json b/composer.json index 448d757..abf909f 100644 --- a/composer.json +++ b/composer.json @@ -11,15 +11,15 @@ } ], "require": { - "php": ">=7.1", - "cakephp/orm": "^3.5" + "php": ">=8.0", + "cakephp/orm": "^4.0" }, "require-dev": { - "cakephp/cakephp": "^3.5", - "friendsofphp/php-cs-fixer": "~2.0", - "phpstan/phpstan": "~0.11", - "phpunit/phpunit": "^5.7.14|^6.0", - "rshop/php-cs-fixer-config": "~2.0" + "cakephp/cakephp": "^4.0", + "friendsofphp/php-cs-fixer": "^3.0", + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": "^8.5|^9.3", + "rshop/php-cs-fixer-config": "^3.0" }, "autoload": { "psr-4": { diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..9196e82 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,8 @@ +parameters: + level: 6 + paths: + - src + bootstrapFiles: + - tests/bootstrap.php + ignoreErrors: + - '#Access to an undefined property Cake\\ORM\\Table::\$[a-zA-Z0-9_]+\.#' diff --git a/phpunit.xml b/phpunit.xml index 49364f7..76907f7 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -3,7 +3,6 @@ colors="true" processIsolation="false" stopOnFailure="false" - syntaxCheck="false" bootstrap="./tests/bootstrap.php" > @@ -13,26 +12,20 @@ - + ./tests/TestCase - - - - - - - + + + - - + + ./src/ - - + + - \ No newline at end of file + diff --git a/src/Model/Behavior/FetchableBehavior.php b/src/Model/Behavior/FetchableBehavior.php index 754424b..f24f389 100644 --- a/src/Model/Behavior/FetchableBehavior.php +++ b/src/Model/Behavior/FetchableBehavior.php @@ -5,7 +5,6 @@ * Licensed under the MIT License * (c) RIESENIA.com */ - declare(strict_types=1); namespace Fetchable\Model\Behavior; @@ -28,10 +27,7 @@ class FetchableBehavior extends Behavior /** @var array */ private $_cache; - /** - * {@inheritdoc} - */ - public function initialize(array $config) + public function initialize(array $config): void { // key is set automatically if (!isset($config['key'])) { @@ -43,8 +39,6 @@ public function initialize(array $config) /** * Fetch data. - * - * @return array */ public function fetch(): array { @@ -58,7 +52,7 @@ public function fetch(): array return $this->_cache[$key]; } - if (($data = Cache::read($key, $this->getConfig('cache'))) === false) { + if (!($data = Cache::read($key, $this->getConfig('cache')))) { $data = []; $find = $this->_table->find($this->getConfig('finder')); @@ -83,8 +77,6 @@ public function fetch(): array * Fetch entity. * * @param int|string $id - * - * @return EntityInterface */ public function fetchEntity($id): EntityInterface { @@ -100,8 +92,6 @@ public function fetchEntity($id): EntityInterface /** * Get primary key value for entity. * - * @param EntityInterface $entity - * * @return int|string */ protected function _getPrimaryValue(EntityInterface $entity) diff --git a/tests/Fixture/I18nFixture.php b/tests/Fixture/I18nFixture.php index 9a589ff..49212e1 100644 --- a/tests/Fixture/I18nFixture.php +++ b/tests/Fixture/I18nFixture.php @@ -5,7 +5,6 @@ * Licensed under the MIT License * (c) RIESENIA.com */ - declare(strict_types=1); namespace Fetchable\Test\Fixture; @@ -23,53 +22,25 @@ class I18nFixture extends TestFixture * @var string */ public $table = 'i18n'; - /** - * Fields. - * - * @var array - */ - // @codingStandardsIgnoreStart + public $fields = [ - 'id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], - 'locale' => ['type' => 'string', 'length' => 6, 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], - 'model' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], - 'foreign_key' => ['type' => 'integer', 'length' => 10, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null], - 'field' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], - 'content' => ['type' => 'text', 'length' => null, 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null], + 'id' => ['type' => 'integer', 'null' => false, 'autoIncrement' => true], + 'locale' => ['type' => 'string', 'length' => 6, 'null' => false], + 'model' => ['type' => 'string', 'length' => 255, 'null' => false], + 'foreign_key' => ['type' => 'integer', 'null' => false], + 'field' => ['type' => 'string', 'length' => 255, 'null' => false], + 'content' => ['type' => 'text', 'null' => true], '_indexes' => [ - 'model' => ['type' => 'index', 'columns' => ['model', 'foreign_key', 'field'], 'length' => []], + 'model' => ['type' => 'index', 'columns' => ['model', 'foreign_key', 'field']] ], '_constraints' => [ - 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], - 'locale' => ['type' => 'unique', 'columns' => ['locale', 'model', 'foreign_key', 'field'], 'length' => []], - ], - '_options' => [ - 'engine' => 'InnoDB', - 'collation' => 'utf8_general_ci' - ], + 'primary' => ['type' => 'primary', 'columns' => ['id']], + 'locale' => ['type' => 'unique', 'columns' => ['locale', 'model', 'foreign_key', 'field']] + ] ]; - /** - * Records. - * - * @var array - */ public $records = [ - [ - 'id' => 1, - 'locale' => 'sk_SK', - 'model' => 'Statuses', - 'foreign_key' => 1, - 'field' => 'name', - 'content' => 'First status - sk' - ], - [ - 'id' => 2, - 'locale' => 'sk_SK', - 'model' => 'StatusProperties', - 'foreign_key' => 1, - 'field' => 'name', - 'content' => 'Property 1 - sk' - ], + ['id' => 1, 'locale' => 'sk_SK', 'model' => 'Statuses', 'foreign_key' => 1, 'field' => 'name', 'content' => 'First status - sk'], + ['id' => 2, 'locale' => 'sk_SK', 'model' => 'StatusProperties', 'foreign_key' => 1, 'field' => 'name', 'content' => 'Property 1 - sk'] ]; } diff --git a/tests/Fixture/StatusPropertiesFixture.php b/tests/Fixture/StatusPropertiesFixture.php index 7381f8e..23b801b 100644 --- a/tests/Fixture/StatusPropertiesFixture.php +++ b/tests/Fixture/StatusPropertiesFixture.php @@ -5,7 +5,6 @@ * Licensed under the MIT License * (c) RIESENIA.com */ - declare(strict_types=1); namespace Fetchable\Test\Fixture; @@ -16,22 +15,15 @@ class StatusPropertiesFixture extends TestFixture { public $fields = [ 'id' => ['type' => 'integer'], - 'status_id' => ['type' => 'integer', 'default' => null, 'null' => true], - 'name' => ['type' => 'string', 'default' => null, 'null' => true], + 'status_id' => ['type' => 'integer', 'null' => true], + 'name' => ['type' => 'string', 'length' => 255, 'null' => true], '_constraints' => [ 'primary' => ['type' => 'primary', 'columns' => ['id']] ] ]; + public $records = [ - [ - 'id' => 1, - 'status_id' => 1, - 'name' => 'First property' - ], - [ - 'id' => 2, - 'status_id' => 1, - 'name' => 'Second property' - ] + ['id' => 1, 'status_id' => 1, 'name' => 'First property'], + ['id' => 2, 'status_id' => 1, 'name' => 'Second property'] ]; } diff --git a/tests/Fixture/StatusesFixture.php b/tests/Fixture/StatusesFixture.php index eef5408..cf2cf06 100644 --- a/tests/Fixture/StatusesFixture.php +++ b/tests/Fixture/StatusesFixture.php @@ -5,7 +5,6 @@ * Licensed under the MIT License * (c) RIESENIA.com */ - declare(strict_types=1); namespace Fetchable\Test\Fixture; @@ -16,19 +15,14 @@ class StatusesFixture extends TestFixture { public $fields = [ 'id' => ['type' => 'integer'], - 'name' => ['type' => 'string', 'default' => null, 'null' => true], + 'name' => ['type' => 'string', 'length' => 255, 'null' => true], '_constraints' => [ 'primary' => ['type' => 'primary', 'columns' => ['id']] ] ]; + public $records = [ - [ - 'id' => 1, - 'name' => 'First status' - ], - [ - 'id' => 2, - 'name' => 'Second status' - ] + ['id' => 1, 'name' => 'First status'], + ['id' => 2, 'name' => 'Second status'] ]; } diff --git a/tests/TestCase/Model/Behavior/FetchableBehaviorTest.php b/tests/TestCase/Model/Behavior/FetchableBehaviorTest.php index dada140..25efc27 100644 --- a/tests/TestCase/Model/Behavior/FetchableBehaviorTest.php +++ b/tests/TestCase/Model/Behavior/FetchableBehaviorTest.php @@ -5,7 +5,6 @@ * Licensed under the MIT License * (c) RIESENIA.com */ - declare(strict_types=1); namespace Fetchable\Test\TestCase\Model\Behavior; @@ -31,6 +30,11 @@ class FetchableBehaviorTest extends TestCase 'plugin.Fetchable.I18n' ]; + /** + * @var \TestApp\Model\Table\StatusesTable + */ + protected $Statuses; + /** * Test fetch. */ @@ -86,14 +90,35 @@ public function testI18nFetch() $this->assertEquals('Property 1 - sk', $statuses[1]['status_properties'][0]['name']); } + /** + * setUpBeforeClass method - Create fixture tables. + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + $connection = \Cake\Datasource\ConnectionManager::get('test'); + + // Create fixture tables + $fixtures = [ + new \Fetchable\Test\Fixture\StatusesFixture(), + new \Fetchable\Test\Fixture\StatusPropertiesFixture(), + new \Fetchable\Test\Fixture\I18nFixture() + ]; + + foreach ($fixtures as $fixture) { + $fixture->create($connection); + } + } + /** * setUp method. */ - public function setUp() + public function setUp(): void { parent::setUp(); - $this->Statuses = TableRegistry::get('Statuses', [ + $this->Statuses = TableRegistry::getTableLocator()->get('Statuses', [ 'className' => 'TestApp\Model\Table\StatusesTable' ]); } @@ -101,7 +126,7 @@ public function setUp() /** * tearDown method. */ - public function tearDown() + public function tearDown(): void { unset($this->Statuses); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 46c2e93..5deaa43 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -5,7 +5,6 @@ * Licensed under the MIT License * (c) RIESENIA.com */ - declare(strict_types=1); use Cake\Cache\Cache; @@ -85,22 +84,23 @@ ConnectionManager::setConfig('test', [ 'className' => 'Cake\Database\Connection', - 'driver' => \getenv('db_class'), - 'dsn' => \getenv('db_dsn'), - 'database' => \getenv('db_database'), - 'username' => \getenv('db_login'), - 'password' => \getenv('db_password'), - 'timezone' => 'UTC' + 'driver' => \getenv('db_class') ?: 'Cake\Database\Driver\Sqlite', + 'database' => \getenv('db_database') ?: ':memory:', + 'username' => \getenv('db_login') ?: null, + 'password' => \getenv('db_password') ?: null, + 'timezone' => 'UTC', + 'quoteIdentifiers' => false, + 'cacheMetadata' => false ]); Log::setConfig([ 'debug' => [ 'engine' => 'Cake\Log\Engine\FileLog', 'levels' => ['notice', 'info', 'debug'], - 'file' => 'debug', + 'file' => 'debug' ], 'error' => [ 'engine' => 'Cake\Log\Engine\FileLog', 'levels' => ['warning', 'error', 'critical', 'alert', 'emergency'], - 'file' => 'error', + 'file' => 'error' ] ]); diff --git a/tests/test_app/TestApp/Model/Table/StatusPropertiesTable.php b/tests/test_app/TestApp/Model/Table/StatusPropertiesTable.php index 0e0f41c..44b3195 100644 --- a/tests/test_app/TestApp/Model/Table/StatusPropertiesTable.php +++ b/tests/test_app/TestApp/Model/Table/StatusPropertiesTable.php @@ -5,7 +5,6 @@ * Licensed under the MIT License * (c) RIESENIA.com */ - declare(strict_types=1); namespace TestApp\Model\Table; @@ -14,7 +13,7 @@ class StatusPropertiesTable extends Table { - public function initialize(array $config) + public function initialize(array $config): void { parent::initialize($config); diff --git a/tests/test_app/TestApp/Model/Table/StatusesTable.php b/tests/test_app/TestApp/Model/Table/StatusesTable.php index 30329c4..1caef61 100644 --- a/tests/test_app/TestApp/Model/Table/StatusesTable.php +++ b/tests/test_app/TestApp/Model/Table/StatusesTable.php @@ -5,7 +5,6 @@ * Licensed under the MIT License * (c) RIESENIA.com */ - declare(strict_types=1); namespace TestApp\Model\Table; @@ -15,7 +14,7 @@ class StatusesTable extends Table { - public function initialize(array $config) + public function initialize(array $config): void { parent::initialize($config);