From 381746e804b3cc3b29562ac155925431e77a6b0f Mon Sep 17 00:00:00 2001 From: Dalibor Korpar Date: Thu, 14 Jul 2022 10:18:27 +0200 Subject: [PATCH] php 8.1 compatibility, switch to github actions --- .coveralls.yml | 4 + .github/.kodiak.toml | 10 + .github/workflows/main.yml | 260 ++++++++++++++++++++ .travis.yml | 50 ---- Makefile | 24 ++ composer.json | 32 +-- phpstan.neon | 5 +- phpunit.xml | 8 + ruleset.xml | 3 +- src/Entity/Column.php | 25 +- src/Entity/Entity.php | 105 ++------ src/Factory/GeneratorPdoFactory.php | 3 +- src/Generator/Config.php | 160 ++++-------- src/Generator/Generator.php | 36 ++- src/Generator/Helper.php | 7 +- src/Repository/IRepository.php | 5 + src/Repository/PdoRepository.php | 13 +- tests/EntityTest.php | 2 +- tests/Generator/GeneratorTest.php | 115 ++++----- tests/Generator/HelperTest.php | 4 +- tests/TestEntities/PhpDocPropertyEntity.php | 19 +- tests/TestEntities/UserEntity.php | 27 +- tests/phpunit.xml | 13 - 23 files changed, 494 insertions(+), 436 deletions(-) create mode 100644 .coveralls.yml create mode 100644 .github/.kodiak.toml create mode 100644 .github/workflows/main.yml delete mode 100644 .travis.yml create mode 100644 Makefile create mode 100644 phpunit.xml delete mode 100644 tests/phpunit.xml diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 0000000..8450382 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1,4 @@ +# for php-coveralls +service_name: github-actions +coverage_clover: coverage.xml +json_path: coverage.json diff --git a/.github/.kodiak.toml b/.github/.kodiak.toml new file mode 100644 index 0000000..60c34b6 --- /dev/null +++ b/.github/.kodiak.toml @@ -0,0 +1,10 @@ +version = 1 + +[merge] +automerge_label = "automerge" +blacklist_title_regex = "^WIP.*" +blacklist_labels = ["WIP"] +method = "rebase" +delete_branch_on_merge = true +notify_on_conflict = true +optimistic_updates = false diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..01ea241 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,260 @@ +name: "build" + +on: + pull_request: + paths-ignore: + - ".docs/**" + push: + branches: + - "master" + schedule: + - cron: "0 8 * * 1" # At 08:00 on Monday + +env: + extensions: "json, mbstring, pcov" + cache-version: "1" + composer-version: "v2" + composer-install: "composer update --no-interaction --no-progress --no-suggest --prefer-dist --prefer-stable" + +jobs: + qa: + name: "Quality assurance" + runs-on: "${{ matrix.operating-system }}" + + strategy: + matrix: + php-version: ["8.0"] + operating-system: ["ubuntu-latest"] + fail-fast: false + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Setup PHP cache environment" + id: "extcache" + uses: "shivammathur/cache-extensions@v1" + with: + php-version: "${{ matrix.php-version }}" + extensions: "${{ env.extensions }}" + key: "${{ env.cache-version }}" + + - name: "Cache PHP extensions" + uses: "actions/cache@v2" + with: + path: "${{ steps.extcache.outputs.dir }}" + key: "${{ steps.extcache.outputs.key }}" + restore-keys: "${{ steps.extcache.outputs.key }}" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + php-version: "${{ matrix.php-version }}" + extensions: "${{ env.extensions }}" + tools: "composer:${{ env.composer-version }} " + + - name: "Setup problem matchers for PHP" + run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"' + + - name: "Get Composer cache directory" + id: "composercache" + run: 'echo "::set-output name=dir::$(composer config cache-files-dir)"' + + - name: "Cache PHP dependencies" + uses: "actions/cache@v2" + with: + path: "${{ steps.composercache.outputs.dir }}" + key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}" + restore-keys: "${{ runner.os }}-composer-" + + - name: "Validate Composer" + run: "composer validate" + + - name: "Install dependencies" + run: "${{ env.composer-install }}" + + - name: "Coding Standard" + run: "make cs" + tests: + name: "Tests" + runs-on: "${{ matrix.operating-system }}" + strategy: + matrix: + php-version: ["8.1"] + operating-system: ["ubuntu-latest"] + composer-args: [ "" ] + include: + - php-version: "8.0" + operating-system: "ubuntu-latest" + composer-args: "--ignore-platform-reqs" + fail-fast: false + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Setup PHP cache environment" + id: "extcache" + uses: "shivammathur/cache-extensions@v1" + with: + php-version: "${{ matrix.php-version }}" + extensions: "${{ env.extensions }}" + key: "${{ env.cache-version }}" + + - name: "Cache PHP extensions" + uses: "actions/cache@v2" + with: + path: "${{ steps.extcache.outputs.dir }}" + key: "${{ steps.extcache.outputs.key }}" + restore-keys: "${{ steps.extcache.outputs.key }}" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + php-version: "${{ matrix.php-version }}" + extensions: "${{ env.extensions }}" + tools: "composer:${{ env.composer-version }} " + + - name: "Setup problem matchers for PHP" + run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"' + + - name: "Get Composer cache directory" + id: "composercache" + run: 'echo "::set-output name=dir::$(composer config cache-files-dir)"' + + - name: "Cache PHP dependencies" + uses: "actions/cache@v2" + with: + path: "${{ steps.composercache.outputs.dir }}" + key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}" + restore-keys: "${{ runner.os }}-composer-" + + - name: "Install dependencies" + run: "${{ env.composer-install }} ${{ matrix.composer-args }}" + + - name: "Setup problem matchers for PHPUnit" + run: 'echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"' + + - name: "Tests" + run: "vendor/bin/phpunit" + + static-analysis: + name: "Static analysis" + runs-on: "${{ matrix.operating-system }}" + + strategy: + matrix: + php-version: ["8.1"] + operating-system: ["ubuntu-latest"] + fail-fast: false + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Setup PHP cache environment" + id: "extcache" + uses: "shivammathur/cache-extensions@v1" + with: + php-version: "${{ matrix.php-version }}" + extensions: "${{ env.extensions }}" + key: "${{ env.cache-version }}" + + - name: "Cache PHP extensions" + uses: "actions/cache@v2" + with: + path: "${{ steps.extcache.outputs.dir }}" + key: "${{ steps.extcache.outputs.key }}" + restore-keys: "${{ steps.extcache.outputs.key }}" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + php-version: "${{ matrix.php-version }}" + extensions: "${{ env.extensions }}" + tools: "composer:${{ env.composer-version }} " + + - name: "Setup problem matchers for PHP" + run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"' + + - name: "Get Composer cache directory" + id: "composercache" + run: 'echo "::set-output name=dir::$(composer config cache-files-dir)"' + + - name: "Cache PHP dependencies" + uses: "actions/cache@v2" + with: + path: "${{ steps.composercache.outputs.dir }}" + key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}" + restore-keys: "${{ runner.os }}-composer-" + + - name: "Install dependencies" + run: "${{ env.composer-install }}" + + - name: "PHPStan" + run: "make phpstan" + + tests-code-coverage: + name: "Tests with code coverage" + runs-on: "${{ matrix.operating-system }}" + + strategy: + matrix: + php-version: ["8.1"] + operating-system: ["ubuntu-latest"] + fail-fast: false + + steps: + - name: "Checkout" + uses: "actions/checkout@v2" + + - name: "Setup PHP cache environment" + id: "extcache" + uses: "shivammathur/cache-extensions@v1" + with: + php-version: "${{ matrix.php-version }}" + extensions: "${{ env.extensions }}" + key: "${{ env.cache-version }}" + + - name: "Cache PHP extensions" + uses: "actions/cache@v2" + with: + path: "${{ steps.extcache.outputs.dir }}" + key: "${{ steps.extcache.outputs.key }}" + restore-keys: "${{ steps.extcache.outputs.key }}" + + - name: "Install PHP" + uses: "shivammathur/setup-php@v2" + with: + php-version: "${{ matrix.php-version }}" + extensions: "${{ env.extensions }}" + tools: "composer:${{ env.composer-version }} " + + - name: "Setup problem matchers for PHP" + run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"' + + - name: "Get Composer cache directory" + id: "composercache" + run: 'echo "::set-output name=dir::$(composer config cache-files-dir)"' + + - name: "Cache PHP dependencies" + uses: "actions/cache@v2" + with: + path: "${{ steps.composercache.outputs.dir }}" + key: "${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}" + restore-keys: "${{ runner.os }}-composer-" + + - name: "Install dependencies" + run: "${{ env.composer-install }}" + + - name: "Tests" + run: "make coverage" + + - name: "Coveralls.io" + env: + CI_NAME: github + CI: true + COVERALLS_REPO_TOKEN: "${{ secrets.GITHUB_TOKEN }}" + run: | + wget https://github.com/php-coveralls/php-coveralls/releases/download/v2.1.0/php-coveralls.phar + php php-coveralls.phar --verbose --config .coveralls.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index eb6d665..0000000 --- a/.travis.yml +++ /dev/null @@ -1,50 +0,0 @@ -language: php -php: - - 7.1 - - 7.2 - - 7.3 - - 7.4 - - 8.0 -install: - - travis_retry composer install --no-progress --prefer-dist - -script: - - vendor/bin/phpunit --configuration tests/phpunit.xml tests --coverage-clover=coverage.xml - -after_success: - - bash <(curl -s https://codecov.io/bash) - -jobs: - include: - - env: title="Lowest Dependencies 7.1" - php: 7.1 - install: - - travis_retry composer update --no-progress --prefer-dist --prefer-lowest - script: - - composer run-script tests - - - stage: Quality Assurance - php: 7.1 - script: - - composer run-script qa - - - stage: Phpstan - php: 7.1 - script: - - composer run-script phpstan-install - - composer run-script phpstan - - - stage: Outdated Dependencies - if: branch = master AND type = cron - php: 7.1 - script: - - composer outdated --direct --strict - - allow_failures: - - stage: Test Coverage - -sudo: false - -cache: - directories: - - $HOME/.composer/cache diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a276737 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +.PHONY: qa cs csf phpstan tests coverage + +all: + @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs + +vendor: composer.json composer.lock + composer install + +qa: phpstan cs + +cs: vendor + vendor/bin/codesniffer src tests + +csf: vendor + vendor/bin/codefixer src tests + +phpstan: vendor + vendor/bin/phpstan analyse -l max -c phpstan.neon src + +tests: vendor + vendor/bin/phpunit + +coverage: vendor + vendor/bin/phpunit --coverage-clover=coverage.xml \ No newline at end of file diff --git a/composer.json b/composer.json index 4d13128..1081ec9 100644 --- a/composer.json +++ b/composer.json @@ -27,34 +27,10 @@ "doctrine/inflector": "^2.0" }, "require-dev": { - "ninjify/qa": ">=0.8", - "phpunit/phpunit": ">=9.0" - }, - "scripts": { - "qa": [ - "codesniffer src tests", - "linter src tests" - ], - "codefixer": [ - "codefixer" - ], - "tests": [ - "phpunit --configuration tests/phpunit.xml tests/" - ], - "coverage": [ - "phpunit --configuration tests/phpunit.xml tests --coverage-clover=coverage.xml" - ], - "phpstan-install": [ - "mkdir -p temp/phpstan", - "composer require -d temp/phpstan phpstan/phpstan:^0.11", - "composer require -d temp/phpstan phpstan/phpstan-dibi:^0.11", - "composer require -d temp/phpstan phpstan/phpstan-deprecation-rules:^0.11", - "composer require -d temp/phpstan phpstan/phpstan-nette:^0.11", - "composer require -d temp/phpstan phpstan/phpstan-strict-rules:^0.11" - ], - "phpstan": [ - "temp/phpstan/vendor/bin/phpstan analyse -l 2 -c phpstan.neon src --memory-limit 1024M" - ] + "contributte/qa": "^0.1", + "phpunit/phpunit": ">=9.0", + "phpstan/phpstan-deprecation-rules": "^1.0", + "phpstan/phpstan-strict-rules": "^1.0" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/phpstan.neon b/phpstan.neon index 1720449..bad1cbe 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,8 +1,7 @@ includes: - - temp/phpstan/vendor/phpstan/phpstan-nette/extension.neon - - temp/phpstan/vendor/phpstan/phpstan-nette/rules.neon - - temp/phpstan/vendor/phpstan/phpstan-strict-rules/rules.neon + - vendor/phpstan/phpstan-strict-rules/rules.neon parameters: ignoreErrors: - '#Variable property access on \$[a-zA-Z0-9_]+#' + checkGenericClassInNonGenericObjectType: false diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..a0b92d3 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,8 @@ + + + + + src/ + + + diff --git a/ruleset.xml b/ruleset.xml index fbeb9a4..21c02d0 100644 --- a/ruleset.xml +++ b/ruleset.xml @@ -1,7 +1,6 @@ - - + diff --git a/src/Entity/Column.php b/src/Entity/Column.php index aead2e2..95893ef 100644 --- a/src/Entity/Column.php +++ b/src/Entity/Column.php @@ -5,54 +5,43 @@ class Column extends Entity { - /** @var string */ - protected $Field; + protected string $Field; - /** @var string */ - protected $Type; + protected string $Type; - /** @var string */ - protected $Null; + protected string $Null; - /** @var string */ - protected $Key; + protected ?string $Key; - /** @var string */ - protected $Default; + protected string|int|null $Default; - /** @var string */ - protected $Extra; + protected ?string $Extra; public function getField(): string { return $this->Field; } - public function getType(): string { return $this->Type; } - public function isNullable(): bool { return $this->Null === 'YES'; } - public function getKey(): ?string { return $this->Key; } - - public function getDefault(): ?string + public function getDefault(): string|int|null { return $this->Default; } - public function getExtra(): ?string { return $this->Extra; diff --git a/src/Entity/Entity.php b/src/Entity/Entity.php index b5339cb..99dcefa 100644 --- a/src/Entity/Entity.php +++ b/src/Entity/Entity.php @@ -2,106 +2,49 @@ namespace DodoIt\EntityGenerator\Entity; -use ArrayAccess; -use ArrayIterator; -use Countable; -use Exception; -use IteratorAggregate; - -class Entity implements ArrayAccess, IteratorAggregate, Countable +class Entity { - public const TABLE = null; - - /** @var mixed[] */ - protected $data; - - /** @var mixed[] */ - private $modifications = []; - - public function __construct(array $arr = []) - { - $this->data = $arr; - - foreach ($arr as $k => $v) { - $this->$k = $v; - } - } - - - public function _getModifications(): array - { - return $this->modifications; - } - - - public function tableName(): ?string - { - return self::TABLE; - } - /** - * @return int + * @param array|\Iterator|null $arr */ - public function count() - { - return count($this->data); - } - - - public function toArray(): array + public function __construct(array|\Iterator|null $arr = []) { - return $this->data; + $this->loadFromArray($arr); } /** - * @return ArrayIterator + * @return array */ - public function getIterator() + public function toArray(): array { - return new ArrayIterator($this->data); - } + $ref = new \ReflectionClass($this); - /** - * @param string $nm - * @param mixed $val - * @return void - */ - public function offsetSet($nm, $val) - { - $this->data[$nm] = $val; - $this->modifications[$nm] = $val; - $this->$nm = $val; - } + $result = []; + foreach ($ref->getProperties() as $property) { + if (isset($this->{$property->getName()})) { + $result[$property->getName()] = $this->{$property->getName()}; + } + } - /** - * @param string $nm - * @return void - */ - public function offsetGet($nm) - { - throw new Exception('You should never access entity as array'); + return $result; } - /** - * @param string $nm - * @return void + * @param array|\Iterator|null $arr */ - public function offsetExists($nm) + public function loadFromArray(array|\Iterator|null $arr): void { - throw new Exception('You should never access entity as array'); - } - + if ($arr === null) { + return; + } - /** - * @param string $nm - * @return void - */ - public function offsetUnset($nm) - { - throw new Exception('You should never access entity as array'); + foreach ($arr as $k => $v) { + if (property_exists($this, $k)) { + $this->$k = $v; + } + } } } diff --git a/src/Factory/GeneratorPdoFactory.php b/src/Factory/GeneratorPdoFactory.php index dd03912..4fae603 100644 --- a/src/Factory/GeneratorPdoFactory.php +++ b/src/Factory/GeneratorPdoFactory.php @@ -20,9 +20,8 @@ public function __construct(PDO $pdo) public function create(Config $config): Generator { $repository = new PdoRepository($this->pdo); - $generator = new Generator($repository, $config); - return $generator; + return new Generator($repository, $config); } } diff --git a/src/Generator/Config.php b/src/Generator/Config.php index fbb52d6..9e63239 100644 --- a/src/Generator/Config.php +++ b/src/Generator/Config.php @@ -7,31 +7,14 @@ class Config { - public function __construct(?array $config = null) - { - if ($config === null) { - return; - } - - foreach ($config as $key => $value) { - $this->$key = $value; - } - } - - /** - * @var string - */ - public $namespace = 'App\\Models\Entities'; + public string $namespace = 'App\\Models\Entities'; - /** - * @var string - */ - public $path = './'; + public string $path = './'; /** - * @var string[] + * @var array */ - public $typeMapping = [ + public array $typeMapping = [ 'int' => ['int', 'bigint', 'mediumint', 'smallint' ], 'float' => ['decimal', 'float'], 'bool' => ['bit', 'tinyint'], @@ -42,160 +25,103 @@ public function __construct(?array $config = null) /** * @var string[] */ - public $replacements = []; + public array $replacements = []; /** * set to true to generate new entities and completelly ignore old ones - * - * @var bool */ - public $rewrite = false; + public bool $rewrite = false; /** * set to null to skip table constant - * - * @var string|null */ - public $tableConstant = 'TABLE_NAME'; + public ?string $tableConstant = 'TABLE_NAME'; /** * generate mapping array where key is entity property name and value is table column name - * - * @var bool */ - public $generateMapping = false; + public bool $generateMapping = false; /** * Generate primary key constant, value of constant is name of field which is primary - * - * @var string|null */ - public $primaryKeyConstant; + public ?string $primaryKeyConstant = null; - /** - * @var string - */ - public $prefix = ''; + public string $prefix = ''; - /** - * @var string - */ - public $suffix = 'Entity'; + public string $suffix = 'Entity'; - /** - * @var bool - */ - public $addDeclareStrictTypes = false; + public bool $addDeclareStrictTypes = false; - /** - * @var string - */ - public $extends = Entity::class; + public ?string $extends = Entity::class; - /** - * @var bool - */ - public $generateGetters = true; + public bool $generateGetters = true; - /** - * @var bool - */ - public $generateSetters = true; + public bool $generateSetters = true; - /** - * @var string - */ - public $getterVisibility = 'public'; + public string $getterVisibility = 'public'; /** * Add trait to generated entity (use TraitName;) - * - * @var string|null */ - public $addTrait; + public ?string $addTrait = null; - /** - * @var string - */ - public $getterBody = 'return $this->__FIELD__;'; + public string $getterBody = 'return $this->__FIELD__;'; - /** - * @var string - */ - public $setterVisibility = 'public'; + public string $setterVisibility = 'public'; - /** - * @var string - */ - public $setterBody = '$this[\'__FIELD__\'] = $value;' . "\n" . 'return $this;'; + public string $setterBody = '$this[\'__FIELD__\'] = $value;' . "\n" . 'return $this;'; - /** - * @var bool - */ - public $generateColumnConstant = true; + public bool $generateColumnConstant = true; - /** - * @var string - */ - public $columnConstantPrefix = 'COL_'; + public string $columnConstantPrefix = 'COL_'; - /** - * @var bool - */ - public $generateProperties = true; + public bool $generateProperties = true; - /** - * @var bool - */ - public $strictlyTypedProperties = false; + public bool $strictlyTypedProperties = false; - /** - * @var bool - */ - public $addPropertyVarComment = true; + public bool $addPropertyVarComment = true; - /** - * @var string - */ - public $propertyVisibility = 'protected'; + public string $propertyVisibility = 'protected'; - /** - * @var bool - */ - public $generatePhpDocProperties = false; + public bool $generatePhpDocProperties = false; + + public string $phpDocProperty = '@property'; /** - * @var string + * @param array $config */ - public $phpDocProperty = '@property'; + public function __construct(?array $config = null) + { + if ($config === null) { + return; + } + + foreach ($config as $key => $value) { + $this->$key = $value; + } + } /** - * @param string $name - * @return void * @throws \Exception */ - public function __get($name) + public function __get(string $name): mixed { throw new \Exception('Configuration "' . $name . '" does not exist!'); } /** - * @param string $name - * @param mixed $value - * @return void * @throws \Exception */ - public function __set($name, $value) + public function __set(string $name, mixed $value): void { throw new \Exception('Configuration "' . $name . '" does not exist!'); } /** - * @param string $name - * @return void * @throws \Exception */ - public function __isset($name) + public function __isset(string $name): bool { throw new \Exception('Configuration "' . $name . '" does not exist!'); } diff --git a/src/Generator/Generator.php b/src/Generator/Generator.php index dbd97ad..dd20b2f 100644 --- a/src/Generator/Generator.php +++ b/src/Generator/Generator.php @@ -7,7 +7,6 @@ use DodoIt\EntityGenerator\Entity\Column; use DodoIt\EntityGenerator\Repository\IRepository; use Exception; -use Nette\NotSupportedException; use Nette\PhpGenerator\ClassType; use Nette\PhpGenerator\PhpFile; use Nette\SmartObject; @@ -32,7 +31,6 @@ public function __construct(IRepository $repository, Config $config) $this->inflector = InflectorFactory::create()->build(); } - public function generate(?string $table = null, ?string $query = null): void { if ($query !== null) { @@ -60,16 +58,12 @@ public function generate(?string $table = null, ?string $query = null): void } } - public function generateEntity(string $table): void { $file = new PhpFile(); + if ($this->config->addDeclareStrictTypes) { - if (!method_exists($file, 'setStrictTypes')) { - throw new NotSupportedException('You have set addDeclareStrictTypes but have phpgenerator dependency <3.2.0!'); - } else { - $file->setStrictTypes($this->config->addDeclareStrictTypes); - } + $file->setStrictTypes($this->config->addDeclareStrictTypes); } $namespace = $file->addNamespace($this->config->namespace); @@ -93,7 +87,7 @@ public function generateEntity(string $table): void $entity->addConstant($this->config->tableConstant, $table)->setVisibility('public'); } - if ($this->config->extends !== NULL) { + if ($this->config->extends !== null) { $entity->setExtends($this->config->extends); } @@ -124,7 +118,6 @@ public function generateEntity(string $table): void file_put_contents($this->config->path . '/' . $shortClassName . '.php', $file->__toString()); } - protected function getClassName(string $table): string { return $this->config->prefix . Helper::camelize($table, $this->config->replacements) . $this->config->suffix; @@ -141,7 +134,6 @@ protected function validateColumnName(string $table, Column $column): void } } - protected function generateColumn(ClassType $entity, Column $column): void { $type = $this->getColumnType($column); @@ -155,12 +147,8 @@ protected function generateColumn(ClassType $entity, Column $column): void } if ($this->config->strictlyTypedProperties) { - if (!method_exists($property, 'setType')) { - throw new NotSupportedException('You have set strictlyTypedProperties but have phpgenerator dependency <3.3.0!'); - } else { $property->setType($type); $property->setNullable($column->isNullable()); - } } } @@ -185,15 +173,15 @@ protected function generateColumn(ClassType $entity, Column $column): void } } - protected function getColumnType(Column $column): string { $dbColumnType = $column->getType(); if (Strings::contains($dbColumnType, '(')) { - $dbColumnType = Strings::lower(Strings::before($dbColumnType, '(')); + $dbColumnType = Strings::lower(Strings::before($dbColumnType, '(') ?? 'string'); } + /** @var array $typeMapping */ $typeMapping = Helper::multiArrayFlip($this->config->typeMapping); if (isset($typeMapping[$dbColumnType])) { @@ -238,14 +226,22 @@ private function cloneEntityFromExistingEntity(ClassType $entity, ClassType $fro } } - private function getMethodBody(string $class, string $name): string { $func = new ReflectionMethod($class, $name); - $startLine = $func->getStartLine() + 1; - $length = $func->getEndLine() - $startLine - 1; + $startLine = $func->getStartLine() + 1; //@phpstan-ignore-line + $length = $func->getEndLine() - $startLine - 1; //@phpstan-ignore-line + + if ($func->getFileName() === false) { + throw new Exception('Cannot get generated entity filename!'); + } $source = file($func->getFileName()); + + if ($source === false) { + throw new Exception('Cannot open generated entity file!'); + } + $bodyLines = array_slice($source, $startLine, $length); $body = ''; diff --git a/src/Generator/Helper.php b/src/Generator/Helper.php index 92c2339..f578d0e 100644 --- a/src/Generator/Helper.php +++ b/src/Generator/Helper.php @@ -2,14 +2,13 @@ namespace DodoIt\EntityGenerator\Generator; -use Doctrine\Common\Inflector\Inflector; use Doctrine\Inflector\InflectorFactory; class Helper { /** - * @param mixed[] $array + * @param mixed[][] $array * @return mixed[] */ public static function multiArrayFlip(array $array): array @@ -25,6 +24,10 @@ public static function multiArrayFlip(array $array): array return $result; } + /** + * @param array $replacements + * @param non-empty-string $separator + */ public static function camelize(string $input, array $replacements = [], string $separator = '_'): string { $words = explode($separator, $input); diff --git a/src/Repository/IRepository.php b/src/Repository/IRepository.php index aaae06c..b9aa89e 100644 --- a/src/Repository/IRepository.php +++ b/src/Repository/IRepository.php @@ -2,6 +2,8 @@ namespace DodoIt\EntityGenerator\Repository; +use DodoIt\EntityGenerator\Entity\Column; + interface IRepository { @@ -10,6 +12,9 @@ interface IRepository */ public function getTables(): array; + /** + * @return Column[] + */ public function getTableColumns(string $table): array; public function createViewFromQuery(string $name, string $query): void; diff --git a/src/Repository/PdoRepository.php b/src/Repository/PdoRepository.php index 1b15e02..ae8e61c 100644 --- a/src/Repository/PdoRepository.php +++ b/src/Repository/PdoRepository.php @@ -15,13 +15,12 @@ public function __construct(PDO $db) $this->db = $db; } - /** * @return string[] */ public function getTables(): array { - return $this->db->query('SHOW TABLES')->fetchAll(PDO::FETCH_COLUMN, 0); + return $this->db->query('SHOW TABLES')->fetchAll(PDO::FETCH_COLUMN, 0); //@phpstan-ignore-line } /** @@ -30,21 +29,19 @@ public function getTables(): array public function getTableColumns(string $table): array { $query = $this->db->query('SHOW COLUMNS FROM `' . $table . '`'); - $query->setFetchMode(PDO::FETCH_CLASS, Column::class); + $query->setFetchMode(PDO::FETCH_CLASS, Column::class); //@phpstan-ignore-line - return $query->fetchAll(); + return $query->fetchAll(); //@phpstan-ignore-line } - public function createViewFromQuery(string $name, string $query): void { - $this->db->query('CREATE VIEW `' . $name . '` AS ' . $query)->execute(); + $this->db->query('CREATE VIEW `' . $name . '` AS ' . $query)->execute(); //@phpstan-ignore-line } - public function dropView(string $name): void { - $this->db->query('DROP VIEW `' . $name . '`')->execute(); + $this->db->query('DROP VIEW `' . $name . '`')->execute(); //@phpstan-ignore-line } } diff --git a/tests/EntityTest.php b/tests/EntityTest.php index e929d82..61e7817 100644 --- a/tests/EntityTest.php +++ b/tests/EntityTest.php @@ -34,7 +34,7 @@ public function test_getModifications(): void $this->assertInstanceOf(DateTime::class, $entity->getLastLogin()); $this->assertEquals('user', $entity->getUsername()); - $modifications = $entity->_getModifications(); + $modifications = $entity->toArray(); $this->assertEquals([ 'username' => 'user', 'active' => 1, diff --git a/tests/Generator/GeneratorTest.php b/tests/Generator/GeneratorTest.php index a62dde8..1457393 100644 --- a/tests/Generator/GeneratorTest.php +++ b/tests/Generator/GeneratorTest.php @@ -15,67 +15,18 @@ class GeneratorTest extends TestCase { - /** - * @var Config - */ - private $config; + private Config $config; - /** - * @var IRepository|MockObject - */ - private $repository; + private IRepository|MockObject $repository; /** * @var Column[] */ - private $tableColumns = []; + private array $tableColumns = []; - /** - * @var Generator - */ - private $generator; - - protected function setUp(): void - { - $this->tableColumns[] = new Column([ - 'Field' => 'id', - 'Type' => 'int(11)', - 'Null' => 'NO', - 'Key' => 'PRI', - 'Default' => null, - 'Extra' => 'auto_increment', - ]); - $this->tableColumns[] = new Column([ - 'Field' => 'title', - 'Type' => 'varchar(25)', - 'Null' => 'YES', - 'Key' => null, - 'Default' => null, - 'Extra' => null, - ]); - $this->tableColumns[] = new Column([ - 'Field' => 'published', - 'Type' => 'tinyint(1)', - 'Null' => 'NO', - 'Key' => null, - 'Default' => 1, - 'Extra' => null, - ]); - $this->tableColumns[] = new Column([ - 'Field' => 'created_at', - 'Type' => 'datetime', - 'Null' => 'YES', - 'Key' => null, - 'Default' => 1, - 'Extra' => null, - ]); - $this->config = new Config(); - $this->config->namespace = 'DodoIt\EntityGenerator\Tests\TestEntities'; - $this->repository = $this->getMockForAbstractClass(IRepository::class); - $this->generator = new Generator($this->repository, $this->config); - } + private Generator $generator; - public function testGenerateEntity_WithPropertiesOnly_ShouldGenerateOnlyProperties() + public function testGenerateEntity_WithPropertiesOnly_ShouldGenerateOnlyProperties(): void { $this->config->generateProperties = true; $this->config->generateGetters = false; @@ -97,7 +48,7 @@ public function testGenerateEntity_WithPropertiesOnly_ShouldGenerateOnlyProperti unlink($entityFile); } - public function testGenerateEntity_WithRewriteFalseAndPhpDocProperties_ShouldNotReGenerate() + public function testGenerateEntity_WithRewriteFalseAndPhpDocProperties_ShouldNotReGenerate(): void { //we've put published as integer intentionally in PhpDocPropertyEntity so if we don't rewrite this should stay int and not become bool $this->config->generatePhpDocProperties = true; @@ -111,7 +62,7 @@ public function testGenerateEntity_WithRewriteFalseAndPhpDocProperties_ShouldNot $this->assertNotFalse(strpos($string, 'property int $published')); } - public function testGenerateEntity_WithMappingAndPhpDocProperties_ShouldGenerateMapping() + public function testGenerateEntity_WithMappingAndPhpDocProperties_ShouldGenerateMapping(): void { $this->config->generatePhpDocProperties = false; $this->config->generateProperties = false; @@ -136,7 +87,7 @@ public function testGenerateEntity_WithMappingAndPhpDocProperties_ShouldGenerate unlink($entityFile); } - public function testGenerateEntity_WithGenerateConstant_ShouldGenerateConstants() + public function testGenerateEntity_WithGenerateConstant_ShouldGenerateConstants(): void { //we've put published as integer intentionally in PhpDocPropertyEntity so if we don't rewrite this should stay int and not become bool $this->config->generatePhpDocProperties = false; @@ -157,7 +108,7 @@ public function testGenerateEntity_WithGenerateConstant_ShouldGenerateConstants( unlink($entityFile); } - public function testGenerate_WithTableName_ShouldGenerateOnlyThatTable() + public function testGenerate_WithTableName_ShouldGenerateOnlyThatTable(): void { $this->config->path = __DIR__ . '/../TestEntities'; $entityFile = $this->config->path . '/TestEntity.php'; @@ -170,7 +121,7 @@ public function testGenerate_WithTableName_ShouldGenerateOnlyThatTable() unlink($entityFile); } - public function testGenerate_WithoutParameters_ShouldGenerateEntitiesForWholeTable() + public function testGenerate_WithoutParameters_ShouldGenerateEntitiesForWholeTable(): void { $this->config->path = __DIR__ . '/../TestEntities'; @@ -187,7 +138,7 @@ public function testGenerate_WithoutParameters_ShouldGenerateEntitiesForWholeTab unlink($entityFile); } - public function testGenerate_WithQuery_ShouldGenerateEntityFromQuery() + public function testGenerate_WithQuery_ShouldGenerateEntityFromQuery(): void { $this->config->path = __DIR__ . '/../TestEntities'; @@ -201,7 +152,7 @@ public function testGenerate_WithQuery_ShouldGenerateEntityFromQuery() unlink($entityFile); } - public function testGenerateEntity_WithStrictlyTypedProperties_ShouldGenerateStrictlyTypedProperties() + public function testGenerateEntity_WithStrictlyTypedProperties_ShouldGenerateStrictlyTypedProperties(): void { //we've put published as integer intentionally in PhpDocPropertyEntity so if we don't rewrite this should stay int and not become bool $this->config->generatePhpDocProperties = false; @@ -216,9 +167,11 @@ public function testGenerateEntity_WithStrictlyTypedProperties_ShouldGenerateStr $this->config->generateSetters = false; $this->config->path = __DIR__ . '/../TestEntities'; $file = new PhpFile(); + if (!method_exists($file, 'setStrictTypes')) { $this->expectException(NotSupportedException::class); $this->generator->generateEntity('strictly_typed'); + return; } @@ -238,4 +191,44 @@ public function testGenerateEntity_WithStrictlyTypedProperties_ShouldGenerateStr unlink($entityFile); } + protected function setUp(): void + { + $this->tableColumns[] = new Column([ + 'Field' => 'id', + 'Type' => 'int(11)', + 'Null' => 'NO', + 'Key' => 'PRI', + 'Default' => null, + 'Extra' => 'auto_increment', + ]); + $this->tableColumns[] = new Column([ + 'Field' => 'title', + 'Type' => 'varchar(25)', + 'Null' => 'YES', + 'Key' => null, + 'Default' => null, + 'Extra' => null, + ]); + $this->tableColumns[] = new Column([ + 'Field' => 'published', + 'Type' => 'tinyint(1)', + 'Null' => 'NO', + 'Key' => null, + 'Default' => 1, + 'Extra' => null, + ]); + $this->tableColumns[] = new Column([ + 'Field' => 'created_at', + 'Type' => 'datetime', + 'Null' => 'YES', + 'Key' => null, + 'Default' => 1, + 'Extra' => null, + ]); + $this->config = new Config(); + $this->config->namespace = 'DodoIt\EntityGenerator\Tests\TestEntities'; + $this->repository = $this->getMockForAbstractClass(IRepository::class); + $this->generator = new Generator($this->repository, $this->config); + } + } diff --git a/tests/Generator/HelperTest.php b/tests/Generator/HelperTest.php index bc11ed7..d5b3e83 100644 --- a/tests/Generator/HelperTest.php +++ b/tests/Generator/HelperTest.php @@ -22,13 +22,13 @@ public function testMultiArrayFlip(): void ]); } - public function testCamelize() + public function testCamelize(): void { $this->assertEquals('User', Helper::camelize('users')); $this->assertEquals('UserLogin', Helper::camelize('users_logins')); } - public function testGetPhpDocProperties() + public function testGetPhpDocProperties(): void { $comment = '/** * @property int $id diff --git a/tests/TestEntities/PhpDocPropertyEntity.php b/tests/TestEntities/PhpDocPropertyEntity.php index e412a84..a3544b6 100644 --- a/tests/TestEntities/PhpDocPropertyEntity.php +++ b/tests/TestEntities/PhpDocPropertyEntity.php @@ -1,15 +1,18 @@ -id; } - public function setId(int $value): self { $this['id'] = $value; + return $this; } - public function getTitle(): ?string { return $this->title; } - public function setTitle(?string $value): self { $this['title'] = $value; + return $this; } - public function getPublished(): bool { return $this->published; } - public function setPublished(bool $value): self { $this['published'] = $value; + return $this; } - public function getCreatedAt(): ?\DateTimeInterface { return $this->created_at; } - public function setCreatedAt(?\DateTimeInterface $value): self { $this['created_at'] = $value; + return $this; } + } diff --git a/tests/TestEntities/UserEntity.php b/tests/TestEntities/UserEntity.php index 1ca2bcb..fa4cad3 100644 --- a/tests/TestEntities/UserEntity.php +++ b/tests/TestEntities/UserEntity.php @@ -9,69 +9,58 @@ class UserEntity extends Entity { - /** @var int */ - protected $id; + protected int $id; - /** @var string */ - protected $username; + protected string $username; - /** @var DateTimeInterface|null */ - protected $last_login; + protected ?DateTimeInterface $last_login = null; - /** @var bool */ - protected $active; + protected bool $active; public function getId(): int { return $this->id; } - public function setId(int $value): self { - $this['id'] = $value; + $this->id = $value; return $this; } - public function getUsername(): string { return $this->username; } - public function setUsername(string $value): self { - $this['username'] = $value; + $this->username = $value; return $this; } - public function getLastLogin(): ?DateTime { return $this->last_login; } - public function setLastLogin(DateTime $value): self { - $this['last_login'] = $value; + $this->last_login = $value; return $this; } - public function isActive(): bool { return $this->active; } - public function setActive(bool $value): self { - $this['active'] = $value; + $this->active = $value; return $this; } diff --git a/tests/phpunit.xml b/tests/phpunit.xml deleted file mode 100644 index 048e4ac..0000000 --- a/tests/phpunit.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - ../src/ - - - \ No newline at end of file