diff --git a/.gitignore b/.gitignore index 7d05333d..02b6ab05 100755 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ -vendor -tests/mysql.local.neon -composer.lock +vendor +tests/mysql.local.neon +composer.lock +/nbproject diff --git a/.travis.yml b/.travis.yml index dd7569ae..c665bc58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,9 +14,7 @@ addons: - mysql php: - - 7.1 - - 7.2 - - 7.3 + - 7.4 env: - # dev @@ -26,31 +24,31 @@ env: matrix: fast_finish: true include: - - php: 7.3 + - php: 7.4 env: COMPOSER_EXTRA_ARGS="--prefer-stable" COVERAGE="--coverage ./coverage.xml --coverage-src ./src" TESTER_RUNTIME="phpdbg" - - php: 7.3 + - php: 7.4 env: COMPOSER_EXTRA_ARGS="--prefer-stable" PHPSTAN=1 exclude: - - php: 7.3 + - php: 7.4 env: COMPOSER_EXTRA_ARGS="--prefer-stable" allow_failures: - env: - - php: 7.3 + - php: 7.4 env: COMPOSER_EXTRA_ARGS="--prefer-stable" COVERAGE="--coverage ./coverage.xml --coverage-src ./src" TESTER_RUNTIME="phpdbg" install: - - if [ "$PHPSTAN" = "1" ]; then composer require --dev --no-update phpstan/phpstan-shim:^0.9; fi +# - if [ "$PHPSTAN" = "1" ]; then composer require --dev --no-update phpstan/phpstan-shim:^0.9; fi - travis_retry composer update --no-interaction --no-suggest --no-progress --prefer-dist $COMPOSER_EXTRA_ARGS - - travis_retry composer create-project --no-interaction jakub-onderka/php-parallel-lint /tmp/php-parallel-lint +# - travis_retry composer create-project --no-interaction php-parallel-lint/PHP-Parallel-Lint /tmp/php-parallel-lint # - travis_retry composer create-project --no-interaction kdyby/code-checker /tmp/code-checker - if [ "$COVERAGE" != "" ]; then travis_retry wget -O /tmp/coveralls.phar https://github.com/satooshi/php-coveralls/releases/download/v1.0.1/coveralls.phar; fi script: - vendor/bin/tester $COVERAGE -s -p ${TESTER_RUNTIME:-php} -c ./tests/php.ini-unix ./tests/KdybyTests/ - - php /tmp/php-parallel-lint/parallel-lint.php -e php,phpt --exclude vendor . +# - php /tmp/php-parallel-lint/parallel-lint.php -e php,phpt --exclude vendor . # - php /tmp/code-checker/src/code-checker.php --short-arrays # - if [ "$PHPSTAN" = "1" ]; then php vendor/phpstan/phpstan-shim/phpstan.phar -v; fi - - if [ "$PHPSTAN" = "1" ]; then php vendor/phpstan/phpstan-shim/phpstan.phar analyse --ansi --no-progress -l7 -c phpstan.neon src tests/KdybyTests; fi +# - if [ "$PHPSTAN" = "1" ]; then php vendor/phpstan/phpstan-shim/phpstan.phar analyse --ansi --no-progress -l7 -c phpstan.neon src tests/KdybyTests; fi after_script: - if [ "$COVERAGE" != "" ]; then php /tmp/coveralls.phar --verbose --config tests/.coveralls.yml || true; fi diff --git a/README.md b/README.md index 1e0ce4b4..bbca861b 100755 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ -Kdyby/Doctrine +dek-cz/Doctrine ====== -[![Build Status](https://travis-ci.org/Kdyby/Doctrine.svg?branch=master)](https://travis-ci.org/Kdyby/Doctrine) -[![Downloads this Month](https://img.shields.io/packagist/dm/kdyby/doctrine.svg)](https://packagist.org/packages/kdyby/doctrine) -[![Latest stable](https://img.shields.io/packagist/v/kdyby/doctrine.svg)](https://packagist.org/packages/kdyby/doctrine) -[![Coverage Status](https://coveralls.io/repos/github/Kdyby/Doctrine/badge.svg?branch=master)](https://coveralls.io/github/Kdyby/Doctrine?branch=master) +[![Build Status](https://travis-ci.com/dek-cz/Doctrine.svg?branch=master)](https://travis-ci.com/dek-cz/Doctrine) +[![Downloads this Month](https://img.shields.io/packagist/dm/dek-cz/doctrine.svg)](https://packagist.org/packages/dek-cz/doctrine) +[![Latest stable](https://img.shields.io/packagist/v/dek-cz/doctrine.svg)](https://packagist.org/packages/dek-cz/doctrine) +[![Coverage Status](https://coveralls.io/repos/github/dek-cz/doctrine/badge.svg?branch=master)](https://coveralls.io/github/dek-cz/doctrine?branch=master) Installation ------------ -The best way to install Kdyby/Doctrine is using [Composer](http://getcomposer.org/): +The best way to install dek-cz/Doctrine is using [Composer](http://getcomposer.org/): ```sh -$ composer require kdyby/doctrine +$ composer require dek-cz/doctrine ``` Documentation diff --git a/composer.json b/composer.json index 88803804..903e2f97 100644 --- a/composer.json +++ b/composer.json @@ -1,65 +1,69 @@ { - "name": "kdyby/doctrine", - "type": "library", - "description": "Doctrine integration into Nette Framework", - "keywords": ["nette", "kdyby", "doctrine", "orm", "dbal"], - "homepage": "http://kdyby.org", - "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"], - "authors": [ - { - "name": "Filip Procházka", - "homepage": "http://filip-prochazka.com", - "email": "filip@prochazka.su" - } - ], - "support": { - "email": "filip@prochazka.su", - "issues": "https://github.com/kdyby/doctrine/issues" - }, - "require": { - "php": "^7.1", - "doctrine/orm": "~2.7", - "doctrine/dbal": "~2.9", - "kdyby/console": "^2.7.1", - "kdyby/annotations": "^3.0", - "kdyby/doctrine-cache": "^3.0", - "kdyby/strict-objects": "^2.0", - "nette/di": "^3.0", - "nette/utils": "^3.0", - "nette/finder": "^2.5" - }, - "suggest": { - "kdyby/doctrine-magic-accessors": "Fast-prototyping magic accessors trait for Doctrine entities", - "kdyby/doctrine-collections-readonly": "Read-only collection wrapper for easier work with Doctrine entity collections", - "kdyby/doctrine-collections-lazy": "Lazy collection for doctrine/collections", - "kdyby/doctrine-dbal-batchimport": "Batch import & execute utils for effective processing of SQL Imports from files and strings" - }, - "require-dev": { - "kdyby/events": "^3.1.1@dev", - "nette/bootstrap": "^3.0", - "nette/caching": "^3.0", - "nette/http": "^3.0", - "tracy/tracy": "^2.5", - "nette/tester": "^2.2" - }, - "minimum-stability": "dev", - "autoload": { - "psr-0": { - "Kdyby\\Doctrine\\": "src/", - "Kdyby\\Persistence\\": "src/" + "name": "dek-cz/doctrine", + "type": "library", + "description": "Doctrine integration into Nette Framework", + "keywords": ["nette", "kdyby", "doctrine", "orm", "dbal"], + "license": ["BSD-3-Clause", "GPL-2.0", "GPL-3.0"], + "authors": [ + { + "name": "Filip Procházka", + "homepage": "http://filip-prochazka.com", + "email": "filip@prochazka.su" + } + ], + "require": { + "php": "^7.4 || ^8.0", + "psr/cache": "^1.0.1", + "doctrine/orm": "^2.7.1", + "doctrine/dbal": "~2.10", + "doctrine/common": "^2.13", + "kdyby/annotations": "^3.0", + "kdyby/doctrine-cache": "^3.0", + "kdyby/strict-objects": "^2.0", + "nette/di": "^3.0", + "nette/utils": "^3.0", + "nette/finder": "^2.5", + "contributte/console": "0.10.x-dev" + }, + "suggest": { + "kdyby/doctrine-magic-accessors": "Fast-prototyping magic accessors trait for Doctrine entities", + "kdyby/doctrine-collections-readonly": "Read-only collection wrapper for easier work with Doctrine entity collections", + "kdyby/doctrine-collections-lazy": "Lazy collection for doctrine/collections", + "kdyby/doctrine-dbal-batchimport": "Batch import & execute utils for effective processing of SQL Imports from files and strings" + }, + "require-dev": { + "kdyby/events": "^3.1.1@dev", + "nette/bootstrap": "^3.0", + "nette/caching": "^3.0", + "nette/http": "^3.0", + "tracy/tracy": "^2.8", + "nette/tester": "^2.4", + "phpstan/phpstan": "^0.12.69", + "phpstan/phpstan-nette": "^0.12.14", + "spaze/phpstan-disallowed-calls": "^1.1", + "phpunit/php-code-coverage": "^9.2", + "php-coveralls/php-coveralls": "^2.4", + "ninjify/qa": "^0.12.1", + "phpstan/phpstan-strict-rules": "^0.12.9" + }, + "minimum-stability": "dev", + "autoload": { + "psr-0": { + "Kdyby\\Doctrine\\": "src/", + "Kdyby\\Persistence\\": "src/" + }, + "classmap": [ + "src/Kdyby/Doctrine/exceptions.php" + ] + }, + "autoload-dev": { + "classmap": [ + "tests/KdybyTests" + ] }, - "classmap": [ - "src/Kdyby/Doctrine/exceptions.php" - ] - }, - "autoload-dev": { - "classmap": [ - "tests/KdybyTests" - ] - }, - "extra": { - "branch-alias": { - "dev-master": "4.0-dev" + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } } - } } diff --git a/docs/en/index.md b/docs/en/index.md index 0992170f..ea35b22b 100644 --- a/docs/en/index.md +++ b/docs/en/index.md @@ -19,7 +19,7 @@ and now enable the extension using your neon config ```yml extensions: # add theese four lines - console: Kdyby\Console\DI\ConsoleExtension + console: Contributte\Console\DI\ConsoleExtension events: Kdyby\Events\DI\EventsExtension annotations: Kdyby\Annotations\DI\AnnotationsExtension doctrine: Kdyby\Doctrine\DI\OrmExtension diff --git a/phpstan.neon b/phpstan.neon index 65020e34..ba95b524 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,3 +1,6 @@ +includes: + - vendor/phpstan/phpstan-nette/extension.neon + - vendor/phpstan/phpstan-nette/rules.neon parameters: ignoreErrors: - '#Constant TEMP_DIR not found#' diff --git a/ruleset.xml b/ruleset.xml new file mode 100644 index 00000000..512060a3 --- /dev/null +++ b/ruleset.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Kdyby/Doctrine/Configuration.php b/src/Kdyby/Doctrine/Configuration.php index 47908060..c57ac85b 100644 --- a/src/Kdyby/Doctrine/Configuration.php +++ b/src/Kdyby/Doctrine/Configuration.php @@ -23,7 +23,7 @@ class Configuration extends BaseConfiguration { - public function getQueryBuilderClassName() + public function getQueryBuilderClassName() : string { return isset($this->_attributes['queryBuilderClass']) ? $this->_attributes['queryBuilderClass'] @@ -32,21 +32,21 @@ public function getQueryBuilderClassName() - public function setQueryBuilderClassName($className) + public function setQueryBuilderClassName(string $className) : void { $this->_attributes['queryBuilderClass'] = $className; } - public function setTargetEntityMap($targetEntityMap) + public function setTargetEntityMap(array $targetEntityMap) : void { $this->_attributes['targetEntityMap'] = $targetEntityMap; } - public function getTargetEntityClassName($className) + public function getTargetEntityClassName(string $className) : string { return isset($this->_attributes['targetEntityMap'], $this->_attributes['targetEntityMap'][$className]) ? $this->_attributes['targetEntityMap'][$className] diff --git a/src/Kdyby/Doctrine/Console/CommandHelper.php b/src/Kdyby/Doctrine/Console/CommandHelper.php index 8a12cf6f..6a6c8fa7 100644 --- a/src/Kdyby/Doctrine/Console/CommandHelper.php +++ b/src/Kdyby/Doctrine/Console/CommandHelper.php @@ -12,7 +12,7 @@ use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper; use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper; -use Kdyby\Console\ContainerHelper; +use Kdyby\Doctrine\Console\ContainerHelper; use Symfony\Component\Console\Helper\HelperSet; /** diff --git a/src/Kdyby/Doctrine/Console/ContainerHelper.php b/src/Kdyby/Doctrine/Console/ContainerHelper.php new file mode 100644 index 00000000..4409819f --- /dev/null +++ b/src/Kdyby/Doctrine/Console/ContainerHelper.php @@ -0,0 +1,78 @@ +container = $dic; + } + + public function hasParameter(string $key): bool + { + return isset($this->container->parameters[$key]); + } + + /** + * @return mixed + */ + public function getParameter(string $key) + { + if (!$this->hasParameter($key)) { + return NULL; + } + + return $this->container->parameters[$key]; + } + + /** + * @return mixed[] + */ + public function getParameters(): array + { + return $this->container->parameters; + } + + public function getContainer(): DIContainer + { + return $this->container; + } + + /** + * @return object + */ + public function getByType(string $type) + { + return $this->container->getByType($type); + } + + /** + * Returns the canonical name of this helper. + */ + public function getName(): string + { + return 'container'; + } + +} diff --git a/src/Kdyby/Doctrine/Console/DbalDelegateCommand.php b/src/Kdyby/Doctrine/Console/DbalDelegateCommand.php index 2aba7c2d..fac43978 100644 --- a/src/Kdyby/Doctrine/Console/DbalDelegateCommand.php +++ b/src/Kdyby/Doctrine/Console/DbalDelegateCommand.php @@ -58,8 +58,9 @@ protected function configure() $this->setHelp($this->command->getHelp()); $this->setDefinition($this->command->getDefinition()); $this->setDescription($this->command->getDescription()); - - $this->addOption('connection', NULL, InputOption::VALUE_OPTIONAL, 'The connection to use for this command'); + if (!$this->getDefinition()->hasOption('connection')) { + $this->addOption('connection', NULL, InputOption::VALUE_OPTIONAL, 'The connection to use for this command'); + } } /** diff --git a/src/Kdyby/Doctrine/Console/OrmDelegateCommand.php b/src/Kdyby/Doctrine/Console/OrmDelegateCommand.php index 00bf7dc0..94922839 100644 --- a/src/Kdyby/Doctrine/Console/OrmDelegateCommand.php +++ b/src/Kdyby/Doctrine/Console/OrmDelegateCommand.php @@ -14,6 +14,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; +use Kdyby\Doctrine\Tools\CacheCleaner; /** * Command Delegate. @@ -24,65 +25,78 @@ abstract class OrmDelegateCommand extends Command { - use \Kdyby\StrictObjects\Scream; - - /** - * @var \Symfony\Component\Console\Command\Command - */ - protected $command; - - /** - * @return \Symfony\Component\Console\Command\Command - */ - abstract protected function createCommand(); - - /** - * @param string[]|bool|string|null $entityManagerName - * @return \Symfony\Component\Console\Command\Command - */ - protected function wrapCommand($entityManagerName) - { - CommandHelper::setApplicationEntityManager($this->getHelper('container'), $entityManagerName); - $this->command->setApplication($this->getApplication()); - return $this->command; - } - - /** - * {@inheritDoc} - */ - protected function configure() - { - $this->command = $this->createCommand(); - - $this->setName($this->command->getName()); - $this->setHelp($this->command->getHelp()); - $this->setDefinition($this->command->getDefinition()); - $this->setDescription($this->command->getDescription()); - - $this->addOption('em', null, InputOption::VALUE_OPTIONAL, 'The entity manager to use for this command'); - } - - /** - * {@inheritDoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - return $this->wrapCommand($input->getOption('em'))->execute($input, $output); - } - - /** - * {@inheritDoc} - */ - protected function interact(InputInterface $input, OutputInterface $output) - { - $this->wrapCommand($input->getOption('em'))->interact($input, $output); - } - - /** - * {@inheritDoc} - */ - protected function initialize(InputInterface $input, OutputInterface $output) - { - $this->wrapCommand($input->getOption('em'))->initialize($input, $output); - } + use \Kdyby\StrictObjects\Scream; + + /** + * @var \Symfony\Component\Console\Command\Command + */ + protected $command; + + /** + * @var CacheCleaner + */ + public $cacheCleaner; + + public function __construct(CacheCleaner $cacheCleaner) + { + parent::__construct(); + $this->cacheCleaner = $cacheCleaner; + } + + /** + * @return \Symfony\Component\Console\Command\Command + */ + abstract protected function createCommand(); + + /** + * @param string[]|bool|string|null $entityManagerName + * @return \Symfony\Component\Console\Command\Command + */ + protected function wrapCommand($entityManagerName) + { + CommandHelper::setApplicationEntityManager($this->getHelper('container'), $entityManagerName); + $this->command->setApplication($this->getApplication()); + return $this->command; + } + + /** + * {@inheritDoc} + */ + protected function configure() + { + $this->command = $this->createCommand(); + + $this->setName($this->command->getName()); + $this->setHelp($this->command->getHelp()); + $this->setDefinition($this->command->getDefinition()); + $this->setDescription($this->command->getDescription()); + if (!$this->getDefinition()->hasOption('em')) { + $this->addOption('em', null, InputOption::VALUE_OPTIONAL, 'The entity manager to use for this command'); + } + } + + /** + * {@inheritDoc} + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + return $this->wrapCommand($input->getOption('em'))->execute($input, $output); + } + + /** + * {@inheritDoc} + */ + protected function interact(InputInterface $input, OutputInterface $output) + { + $this->wrapCommand($input->getOption('em'))->interact($input, $output); + } + + /** + * {@inheritDoc} + */ + protected function initialize(InputInterface $input, OutputInterface $output) + { + $this->wrapCommand($input->getOption('em'))->initialize($input, $output); + } + } diff --git a/src/Kdyby/Doctrine/Console/Proxy/ConvertMappingCommand.php b/src/Kdyby/Doctrine/Console/Proxy/ConvertMappingCommand.php index 23e4427b..18cd6a39 100644 --- a/src/Kdyby/Doctrine/Console/Proxy/ConvertMappingCommand.php +++ b/src/Kdyby/Doctrine/Console/Proxy/ConvertMappingCommand.php @@ -20,27 +20,16 @@ class ConvertMappingCommand extends OrmDelegateCommand { - /** - * @var \Kdyby\Doctrine\Tools\CacheCleaner - * @inject - */ - public $cacheCleaner; - - public function __construct() - { - parent::__construct(); - } - - protected function initialize(InputInterface $input, OutputInterface $output) - { - parent::initialize($input, $output); - - $this->cacheCleaner->invalidate(); - } - - protected function createCommand() - { - return new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(); - } + protected function initialize(InputInterface $input, OutputInterface $output) + { + parent::initialize($input, $output); + + $this->cacheCleaner->invalidate(); + } + + protected function createCommand() + { + return new \Doctrine\ORM\Tools\Console\Command\ConvertMappingCommand(); + } } diff --git a/src/Kdyby/Doctrine/Console/Proxy/GenerateEntitiesCommand.php b/src/Kdyby/Doctrine/Console/Proxy/GenerateEntitiesCommand.php index a080b008..c5940119 100644 --- a/src/Kdyby/Doctrine/Console/Proxy/GenerateEntitiesCommand.php +++ b/src/Kdyby/Doctrine/Console/Proxy/GenerateEntitiesCommand.php @@ -26,10 +26,6 @@ class GenerateEntitiesCommand extends OrmDelegateCommand */ public $cacheCleaner; - public function __construct() - { - parent::__construct(); - } protected function initialize(InputInterface $input, OutputInterface $output) { diff --git a/src/Kdyby/Doctrine/Console/Proxy/GenerateProxiesCommand.php b/src/Kdyby/Doctrine/Console/Proxy/GenerateProxiesCommand.php index b8905798..e6ae9e2e 100644 --- a/src/Kdyby/Doctrine/Console/Proxy/GenerateProxiesCommand.php +++ b/src/Kdyby/Doctrine/Console/Proxy/GenerateProxiesCommand.php @@ -20,16 +20,6 @@ class GenerateProxiesCommand extends OrmDelegateCommand { - /** - * @var \Kdyby\Doctrine\Tools\CacheCleaner - * @inject - */ - public $cacheCleaner; - - public function __construct() - { - parent::__construct(); - } protected function initialize(InputInterface $input, OutputInterface $output) { diff --git a/src/Kdyby/Doctrine/Console/Proxy/InfoCommand.php b/src/Kdyby/Doctrine/Console/Proxy/InfoCommand.php index 9918be6a..4de076bf 100644 --- a/src/Kdyby/Doctrine/Console/Proxy/InfoCommand.php +++ b/src/Kdyby/Doctrine/Console/Proxy/InfoCommand.php @@ -20,27 +20,16 @@ class InfoCommand extends OrmDelegateCommand { - /** - * @var \Kdyby\Doctrine\Tools\CacheCleaner - * @inject - */ - public $cacheCleaner; - - public function __construct() - { - parent::__construct(); - } - - protected function initialize(InputInterface $input, OutputInterface $output) - { - parent::initialize($input, $output); - - $this->cacheCleaner->invalidate(); - } - - protected function createCommand() - { - return new \Doctrine\ORM\Tools\Console\Command\InfoCommand(); - } + protected function initialize(InputInterface $input, OutputInterface $output) + { + parent::initialize($input, $output); + + $this->cacheCleaner->invalidate(); + } + + protected function createCommand() + { + return new \Doctrine\ORM\Tools\Console\Command\InfoCommand(); + } } diff --git a/src/Kdyby/Doctrine/Console/Proxy/SchemaCreateCommand.php b/src/Kdyby/Doctrine/Console/Proxy/SchemaCreateCommand.php index 70fbc9c3..643f9cdb 100644 --- a/src/Kdyby/Doctrine/Console/Proxy/SchemaCreateCommand.php +++ b/src/Kdyby/Doctrine/Console/Proxy/SchemaCreateCommand.php @@ -20,27 +20,16 @@ class SchemaCreateCommand extends OrmDelegateCommand { - /** - * @var \Kdyby\Doctrine\Tools\CacheCleaner - * @inject - */ - public $cacheCleaner; - - public function __construct() - { - parent::__construct(); - } - - protected function initialize(InputInterface $input, OutputInterface $output) - { - parent::initialize($input, $output); - - $this->cacheCleaner->invalidate(); - } - - protected function createCommand() - { - return new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(); - } + protected function initialize(InputInterface $input, OutputInterface $output) + { + parent::initialize($input, $output); + + $this->cacheCleaner->invalidate(); + } + + protected function createCommand() + { + return new \Doctrine\ORM\Tools\Console\Command\SchemaTool\CreateCommand(); + } } diff --git a/src/Kdyby/Doctrine/Console/Proxy/SchemaDropCommand.php b/src/Kdyby/Doctrine/Console/Proxy/SchemaDropCommand.php index 34b24350..7896e977 100644 --- a/src/Kdyby/Doctrine/Console/Proxy/SchemaDropCommand.php +++ b/src/Kdyby/Doctrine/Console/Proxy/SchemaDropCommand.php @@ -20,27 +20,16 @@ class SchemaDropCommand extends OrmDelegateCommand { - /** - * @var \Kdyby\Doctrine\Tools\CacheCleaner - * @inject - */ - public $cacheCleaner; - - public function __construct() - { - parent::__construct(); - } - - protected function initialize(InputInterface $input, OutputInterface $output) - { - parent::initialize($input, $output); - - $this->cacheCleaner->invalidate(); - } - - protected function createCommand() - { - return new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(); - } + protected function initialize(InputInterface $input, OutputInterface $output) + { + parent::initialize($input, $output); + + $this->cacheCleaner->invalidate(); + } + + protected function createCommand() + { + return new \Doctrine\ORM\Tools\Console\Command\SchemaTool\DropCommand(); + } } diff --git a/src/Kdyby/Doctrine/Console/Proxy/SchemaUpdateCommand.php b/src/Kdyby/Doctrine/Console/Proxy/SchemaUpdateCommand.php index d4071c2a..6da35460 100644 --- a/src/Kdyby/Doctrine/Console/Proxy/SchemaUpdateCommand.php +++ b/src/Kdyby/Doctrine/Console/Proxy/SchemaUpdateCommand.php @@ -20,27 +20,16 @@ class SchemaUpdateCommand extends OrmDelegateCommand { - /** - * @var \Kdyby\Doctrine\Tools\CacheCleaner - * @inject - */ - public $cacheCleaner; - - public function __construct() - { - parent::__construct(); - } - - protected function initialize(InputInterface $input, OutputInterface $output) - { - parent::initialize($input, $output); - - $this->cacheCleaner->invalidate(); - } - - protected function createCommand() - { - return new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(); - } + protected function initialize(InputInterface $input, OutputInterface $output) + { + parent::initialize($input, $output); + + $this->cacheCleaner->invalidate(); + } + + protected function createCommand() + { + return new \Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand(); + } } diff --git a/src/Kdyby/Doctrine/Console/Proxy/ValidateSchemaCommand.php b/src/Kdyby/Doctrine/Console/Proxy/ValidateSchemaCommand.php index a4eebcbb..a198249a 100644 --- a/src/Kdyby/Doctrine/Console/Proxy/ValidateSchemaCommand.php +++ b/src/Kdyby/Doctrine/Console/Proxy/ValidateSchemaCommand.php @@ -20,27 +20,16 @@ class ValidateSchemaCommand extends OrmDelegateCommand { - /** - * @var \Kdyby\Doctrine\Tools\CacheCleaner - * @inject - */ - public $cacheCleaner; - - public function __construct() - { - parent::__construct(); - } - - protected function initialize(InputInterface $input, OutputInterface $output) - { - parent::initialize($input, $output); - - $this->cacheCleaner->invalidate(); - } - - protected function createCommand() - { - return new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(); - } + protected function initialize(InputInterface $input, OutputInterface $output) + { + parent::initialize($input, $output); + + $this->cacheCleaner->invalidate(); + } + + protected function createCommand() + { + return new \Doctrine\ORM\Tools\Console\Command\ValidateSchemaCommand(); + } } diff --git a/src/Kdyby/Doctrine/DI/OrmExtension.php b/src/Kdyby/Doctrine/DI/OrmExtension.php index daa84659..1d11298b 100644 --- a/src/Kdyby/Doctrine/DI/OrmExtension.php +++ b/src/Kdyby/Doctrine/DI/OrmExtension.php @@ -28,6 +28,7 @@ use Kdyby\Annotations\DI\AnnotationsExtension; use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper; use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper; +use Kdyby\Doctrine\Console\ContainerHelper; /** * @author Filip Procházka @@ -35,864 +36,835 @@ class OrmExtension extends Nette\DI\CompilerExtension { - const ANNOTATION_DRIVER = 'annotations'; - const PHP_NAMESPACE = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\\\\]*'; - const TAG_CONNECTION = 'doctrine.connection'; - const TAG_ENTITY_MANAGER = 'doctrine.entityManager'; - const TAG_BIND_TO_MANAGER = 'doctrine.bindToManager'; - const TAG_REPOSITORY_ENTITY = 'doctrine.repositoryEntity'; - const DEFAULT_PROXY_NAMESPACE = 'Kdyby\GeneratedProxy'; - const KDYBY_METADATA_NAMESPACE = 'Kdyby\Doctrine'; - - /** - * @var array - */ - public $managerDefaults = [ - 'metadataCache' => 'default', - 'queryCache' => 'default', - 'resultCache' => 'default', - 'hydrationCache' => 'default', - 'secondLevelCache' => [ - 'enabled' => FALSE, - 'factoryClass' => Doctrine\ORM\Cache\DefaultCacheFactory::class, - 'driver' => 'default', - 'regions' => [ - 'defaultLifetime' => 3600, - 'defaultLockLifetime' => 60, - ], - 'fileLockRegionDirectory' => '%tempDir%/cache/Doctrine.Cache.Locks', // todo fix - 'logging' => '%debugMode%', - ], - 'classMetadataFactory' => Kdyby\Doctrine\Mapping\ClassMetadataFactory::class, - 'defaultRepositoryClassName' => Kdyby\Doctrine\EntityRepository::class, - 'repositoryFactoryClassName' => Kdyby\Doctrine\RepositoryFactory::class, - 'queryBuilderClassName' => Kdyby\Doctrine\QueryBuilder::class, - 'autoGenerateProxyClasses' => '%debugMode%', - 'namingStrategy' => Doctrine\ORM\Mapping\UnderscoreNamingStrategy::class, - 'quoteStrategy' => Doctrine\ORM\Mapping\DefaultQuoteStrategy::class, - 'entityListenerResolver' => Kdyby\Doctrine\Mapping\EntityListenerResolver::class, - 'proxyDir' => '%tempDir%/proxies', - 'proxyNamespace' => self::DEFAULT_PROXY_NAMESPACE, - 'dql' => ['string' => [], 'numeric' => [], 'datetime' => [], 'hints' => []], - 'hydrators' => [], - 'metadata' => [], - 'filters' => [], - 'namespaceAlias' => [], - 'targetEntityMappings' => [], - ]; - - /** - * @var array - */ - public $connectionDefaults = [ - 'dbname' => NULL, - 'host' => '127.0.0.1', - 'port' => NULL, - 'user' => NULL, - 'password' => NULL, - 'charset' => 'UTF8', - 'driver' => 'pdo_mysql', - 'driverClass' => NULL, - 'options' => NULL, - 'path' => NULL, - 'memory' => NULL, - 'unix_socket' => NULL, - 'logging' => '%debugMode%', - 'platformService' => NULL, - 'defaultTableOptions' => [], - 'resultCache' => 'default', - 'types' => [], - 'schemaFilter' => NULL, - ]; - - /** - * @var array - */ - public $metadataDriverClasses = [ - self::ANNOTATION_DRIVER => Doctrine\ORM\Mapping\Driver\AnnotationDriver::class, - 'static' => Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver::class, - 'yml' => Doctrine\ORM\Mapping\Driver\YamlDriver::class, - 'yaml' => Doctrine\ORM\Mapping\Driver\YamlDriver::class, - 'xml' => Doctrine\ORM\Mapping\Driver\XmlDriver::class, - 'db' => Doctrine\ORM\Mapping\Driver\DatabaseDriver::class, - ]; - - /** - * @var array - */ - private $proxyAutoloaders = []; - - /** - * @var array - */ - private $targetEntityMappings = []; - - /** - * @var array - */ - private $configuredManagers = []; - - /** - * @var array - */ - private $managerConfigs = []; - - /** - * @var array - */ - private $configuredConnections = []; - - - - public function loadConfiguration() - { - $this->proxyAutoloaders = - $this->targetEntityMappings = - $this->configuredConnections = - $this->managerConfigs = - $this->configuredManagers = []; - - if (!$this->compiler->getExtensions(AnnotationsExtension::class)) { - throw new Nette\Utils\AssertionException(sprintf("You should register %s before %s.", AnnotationsExtension::class, get_class($this))); - } - - $builder = $this->getContainerBuilder(); - $config = $this->getConfig(); - - $builder->parameters[$this->prefix('debug')] = !empty($config['debug']); - if (isset($config['dbname']) || isset($config['driver']) || isset($config['connection'])) { - $config = ['default' => $config]; - $defaults = ['debug' => $builder->parameters['debugMode']]; - - } else { - $defaults = array_intersect_key($config, $this->managerDefaults) - + array_intersect_key($config, $this->connectionDefaults) - + ['debug' => $builder->parameters['debugMode']]; - - $config = array_diff_key($config, $defaults); - } - - if (empty($config)) { - throw new Kdyby\Doctrine\UnexpectedValueException("Please configure the Doctrine extensions using the section '{$this->name}:' in your config file."); - } - - foreach ($config as $name => $emConfig) { - if (!is_array($emConfig) || (empty($emConfig['dbname']) && empty($emConfig['driver']))) { - throw new Kdyby\Doctrine\UnexpectedValueException("Please configure the Doctrine extensions using the section '{$this->name}:' in your config file."); - } - - /** @var mixed[] $emConfig */ - $emConfig = Nette\DI\Config\Helpers::merge($emConfig, $defaults); - $this->processEntityManager($name, $emConfig); - } - - if ($this->targetEntityMappings) { - if (!$this->isKdybyEventsPresent()) { - throw new Nette\Utils\AssertionException('The option \'targetEntityMappings\' requires \'Kdyby\Events\DI\EventsExtension\'.', E_USER_NOTICE); - } - - $listener = $builder->addDefinition($this->prefix('resolveTargetEntityListener')) - ->setClass(Kdyby\Doctrine\Tools\ResolveTargetEntityListener::class) - ->addTag(Kdyby\Events\DI\EventsExtension::TAG_SUBSCRIBER); - - foreach ($this->targetEntityMappings as $originalEntity => $mapping) { - $listener->addSetup('addResolveTargetEntity', [$originalEntity, $mapping['targetEntity'], $mapping]); - } - } - - $this->loadConsole(); - - $builder->addDefinition($this->prefix('registry')) - ->setFactory(Kdyby\Doctrine\Registry::class, [ - $this->configuredConnections, - $this->configuredManagers, - $builder->parameters[$this->name]['dbal']['defaultConnection'], - $builder->parameters[$this->name]['orm']['defaultEntityManager'], - ]); - } - - - - protected function loadConsole() - { - $builder = $this->getContainerBuilder(); - - foreach ($this->loadFromFile(__DIR__ . '/console.neon') as $i => $command) { - $cli = $builder->addDefinition($this->prefix('cli.' . $i)) - ->addTag(Kdyby\Console\DI\ConsoleExtension::TAG_COMMAND) - ->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT, FALSE); // lazy injects - - if (is_string($command)) { - $cli->setClass($command); - - } else { - throw new Kdyby\Doctrine\NotSupportedException; - } - } - } - - - - protected function processEntityManager($name, array $defaults) - { - $builder = $this->getContainerBuilder(); - $config = $this->resolveConfig($defaults, $this->managerDefaults, $this->connectionDefaults); - - if ($isDefault = !isset($builder->parameters[$this->name]['orm']['defaultEntityManager'])) { - $builder->parameters[$this->name]['orm']['defaultEntityManager'] = $name; - } - - $metadataDriver = $builder->addDefinition($this->prefix($name . '.metadataDriver')) - ->setClass(Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain::class) - ->setAutowired(FALSE); - /** @var \Nette\DI\ServiceDefinition $metadataDriver */ - - Validators::assertField($config, 'metadata', 'array'); - Validators::assertField($config, 'targetEntityMappings', 'array'); - $config['targetEntityMappings'] = $this->normalizeTargetEntityMappings($config['targetEntityMappings']); - foreach ($this->compiler->getExtensions() as $extension) { - if ($extension instanceof IEntityProvider) { - $metadata = $extension->getEntityMappings(); - Validators::assert($metadata, 'array'); - foreach ($metadata as $namespace => $nsConfig) { - if (array_key_exists($namespace, $config['metadata'])) { - throw new Nette\Utils\AssertionException(sprintf('The namespace %s is already configured, provider cannot change it', $namespace)); - } - $config['metadata'][$namespace] = $nsConfig; - } - } - - if ($extension instanceof ITargetEntityProvider) { - $targetEntities = $extension->getTargetEntityMappings(); - Validators::assert($targetEntities, 'array'); - $config['targetEntityMappings'] = Nette\Utils\Arrays::mergeTree($config['targetEntityMappings'], $this->normalizeTargetEntityMappings($targetEntities)); - } - - if ($extension instanceof IDatabaseTypeProvider) { - $providedTypes = $extension->getDatabaseTypes(); - Validators::assert($providedTypes, 'array'); - - if (!isset($defaults['types'])) { - $defaults['types'] = []; - } - - $defaults['types'] = array_merge($defaults['types'], $providedTypes); - } - } - - foreach (self::natSortKeys($config['metadata']) as $namespace => $driver) { - $this->processMetadataDriver($metadataDriver, $namespace, $driver, $name); - } - - $this->processMetadataDriver($metadataDriver, self::KDYBY_METADATA_NAMESPACE, __DIR__ . '/../Entities', $name); - - if (empty($config['metadata'])) { - $metadataDriver->addSetup('setDefaultDriver', [ - new Statement($this->metadataDriverClasses[self::ANNOTATION_DRIVER], [ - '@' . Doctrine\Common\Annotations\Reader::class, - [Nette\DI\Helpers::expand('%appDir%', $builder->parameters)] - ]) - ]); - } - - if ($config['repositoryFactoryClassName'] === 'default') { - $config['repositoryFactoryClassName'] = DefaultRepositoryFactory::class; - } - $builder->addDefinition($this->prefix($name . '.repositoryFactory')) - ->setClass($config['repositoryFactoryClassName']) - ->setAutowired(FALSE); - - Validators::assertField($config, 'namespaceAlias', 'array'); - Validators::assertField($config, 'hydrators', 'array'); - Validators::assertField($config, 'dql', 'array'); - Validators::assertField($config['dql'], 'string', 'array'); - Validators::assertField($config['dql'], 'numeric', 'array'); - Validators::assertField($config['dql'], 'datetime', 'array'); - Validators::assertField($config['dql'], 'hints', 'array'); - - $autoGenerateProxyClasses = is_bool($config['autoGenerateProxyClasses']) - ? ($config['autoGenerateProxyClasses'] ? AbstractProxyFactory::AUTOGENERATE_ALWAYS : AbstractProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS) - : $config['autoGenerateProxyClasses']; - - $configuration = $builder->addDefinition($this->prefix($name . '.ormConfiguration')) - ->setClass(Kdyby\Doctrine\Configuration::class) - ->addSetup('setMetadataCacheImpl', [$this->processCache($config['metadataCache'], $name . '.metadata')]) - ->addSetup('setQueryCacheImpl', [$this->processCache($config['queryCache'], $name . '.query')]) - ->addSetup('setResultCacheImpl', [$this->processCache($config['resultCache'], $name . '.ormResult')]) - ->addSetup('setHydrationCacheImpl', [$this->processCache($config['hydrationCache'], $name . '.hydration')]) - ->addSetup('setMetadataDriverImpl', [$this->prefix('@' . $name . '.metadataDriver')]) - ->addSetup('setClassMetadataFactoryName', [$config['classMetadataFactory']]) - ->addSetup('setDefaultRepositoryClassName', [$config['defaultRepositoryClassName']]) - ->addSetup('setQueryBuilderClassName', [$config['queryBuilderClassName']]) - ->addSetup('setRepositoryFactory', [$this->prefix('@' . $name . '.repositoryFactory')]) - ->addSetup('setProxyDir', [$config['proxyDir']]) - ->addSetup('setProxyNamespace', [$config['proxyNamespace']]) - ->addSetup('setAutoGenerateProxyClasses', [$autoGenerateProxyClasses]) - ->addSetup('setEntityNamespaces', [$config['namespaceAlias']]) - ->addSetup('setCustomHydrationModes', [$config['hydrators']]) - ->addSetup('setCustomStringFunctions', [$config['dql']['string']]) - ->addSetup('setCustomNumericFunctions', [$config['dql']['numeric']]) - ->addSetup('setCustomDatetimeFunctions', [$config['dql']['datetime']]) - ->addSetup('setDefaultQueryHints', [$config['dql']['hints']]) - ->addSetup('setNamingStrategy', CacheHelpers::filterArgs($config['namingStrategy'])) - ->addSetup('setQuoteStrategy', CacheHelpers::filterArgs($config['quoteStrategy'])) - ->addSetup('setEntityListenerResolver', CacheHelpers::filterArgs($config['entityListenerResolver'])) - ->setAutowired(FALSE); - /** @var Nette\DI\ServiceDefinition $configuration */ - - $this->proxyAutoloaders[$config['proxyNamespace']] = $config['proxyDir']; - - $this->processSecondLevelCache($name, $config['secondLevelCache'], $isDefault); - - Validators::assertField($config, 'filters', 'array'); - foreach ($config['filters'] as $filterName => $filterClass) { - $configuration->addSetup('addFilter', [$filterName, $filterClass]); - } - - if ($config['targetEntityMappings']) { - $configuration->addSetup('setTargetEntityMap', [array_map(function ($mapping) { - return $mapping['targetEntity']; - }, $config['targetEntityMappings'])]); - $this->targetEntityMappings = Nette\Utils\Arrays::mergeTree($this->targetEntityMappings, $config['targetEntityMappings']); - } - - if ($this->isKdybyEventsPresent()) { - $builder->addDefinition($this->prefix($name . '.evm')) - ->setFactory(Kdyby\Events\NamespacedEventManager::class, [Kdyby\Doctrine\Events::NS . '::']) - ->addSetup('$dispatchGlobalEvents', [TRUE]) // for BC - ->setAutowired(FALSE); - - } else { - $builder->addDefinition($this->prefix($name . '.evm')) - ->setClass('Doctrine\Common\EventManager') - ->setAutowired(FALSE); - } - - // entity manager - $entityManager = $builder->addDefinition($managerServiceId = $this->prefix($name . '.entityManager')) - ->setClass(Kdyby\Doctrine\EntityManager::class) - ->setFactory(Kdyby\Doctrine\EntityManager::class . '::create', [ - $connectionService = $this->processConnection($name, $defaults, $isDefault), - $this->prefix('@' . $name . '.ormConfiguration'), - $this->prefix('@' . $name . '.evm'), - ]) - ->addTag(self::TAG_ENTITY_MANAGER) - ->addTag('kdyby.doctrine.entityManager') - ->setAutowired($isDefault); - - if ($this->isTracyPresent()) { - $entityManager->addSetup('?->bindEntityManager(?)', [$this->prefix('@' . $name . '.diagnosticsPanel'), '@self']); - } - - $builder->addFactoryDefinition($this->prefix('repositoryFactory.' . $name . '.defaultRepositoryFactory')) - ->setImplement(IRepositoryFactory::class) - ->setParameters([EntityManagerInterface::class . ' entityManager', Doctrine\ORM\Mapping\ClassMetadata::class . ' classMetadata']) - ->getResultDefinition() - ->setFactory($config['defaultRepositoryClassName']) - ->setArguments([new Code\PhpLiteral('$entityManager'), new Code\PhpLiteral('$classMetadata')]) - ->setAutowired(FALSE); - - $builder->addDefinition($this->prefix($name . '.schemaValidator')) - ->setFactory(Doctrine\ORM\Tools\SchemaValidator::class, ['@' . $managerServiceId]) - ->setAutowired($isDefault); - - $builder->addDefinition($this->prefix($name . '.schemaTool')) - ->setFactory(Doctrine\ORM\Tools\SchemaTool::class, ['@' . $managerServiceId]) - ->setAutowired($isDefault); - - $cacheCleaner = $builder->addDefinition($this->prefix($name . '.cacheCleaner')) - ->setFactory(Kdyby\Doctrine\Tools\CacheCleaner::class, ['@' . $managerServiceId]) - ->setAutowired($isDefault); - - $builder->addDefinition($this->prefix($name . '.schemaManager')) - ->setClass(AbstractSchemaManager::class) - ->setFactory('@' . Kdyby\Doctrine\Connection::class . '::getSchemaManager') - ->setAutowired($isDefault); - - foreach ($this->compiler->getExtensions(AnnotationsExtension::class) as $extension) { - /** @var AnnotationsExtension $extension */ - $cacheCleaner->addSetup('addCacheStorage', [$extension->prefix('@cache.annotations')]); - } - - if ($isDefault) { - $builder->addDefinition($this->prefix('helper.entityManager')) - ->setFactory(EntityManagerHelper::class, ['@' . $managerServiceId]) - ->addTag(Kdyby\Console\DI\ConsoleExtension::HELPER_TAG, 'em'); - - $builder->addDefinition($this->prefix('helper.connection')) - ->setFactory(ConnectionHelper::class, [$connectionService]) - ->addTag(Kdyby\Console\DI\ConsoleExtension::HELPER_TAG, 'db'); - - $builder->addAlias($this->prefix('schemaValidator'), $this->prefix($name . '.schemaValidator')); - $builder->addAlias($this->prefix('schemaTool'), $this->prefix($name . '.schemaTool')); - $builder->addAlias($this->prefix('cacheCleaner'), $this->prefix($name . '.cacheCleaner')); - $builder->addAlias($this->prefix('schemaManager'), $this->prefix($name . '.schemaManager')); - } - - $this->configuredManagers[$name] = $managerServiceId; - $this->managerConfigs[$name] = $config; - } - - - - protected function processSecondLevelCache($name, array $config, $isDefault) - { - if (!$config['enabled']) { - return; - } - - $builder = $this->getContainerBuilder(); - - $cacheFactory = $builder->addDefinition($this->prefix($name . '.cacheFactory')) - ->setClass(Doctrine\ORM\Cache\CacheFactory::class) - ->setFactory($config['factoryClass'], [ - $this->prefix('@' . $name . '.cacheRegionsConfiguration'), - $this->processCache($config['driver'], $name . '.secondLevel'), - ]) - ->setAutowired($isDefault); - - if ($config['factoryClass'] === $this->managerDefaults['secondLevelCache']['factoryClass'] - || is_subclass_of($config['factoryClass'], $this->managerDefaults['secondLevelCache']['factoryClass']) - ) { - $cacheFactory->addSetup('setFileLockRegionDirectory', [$config['fileLockRegionDirectory']]); - } - - $builder->addDefinition($this->prefix($name . '.cacheRegionsConfiguration')) - ->setClass(Doctrine\ORM\Cache\RegionsConfiguration::class, [ - $config['regions']['defaultLifetime'], - $config['regions']['defaultLockLifetime'], - ]) - ->setAutowired($isDefault); - - $logger = $builder->addDefinition($this->prefix($name . '.cacheLogger')) - ->setClass(Doctrine\ORM\Cache\Logging\CacheLogger::class) - ->setFactory(Doctrine\ORM\Cache\Logging\CacheLoggerChain::class) - ->setAutowired(FALSE); - - if ($config['logging']) { - $logger->addSetup('setLogger', [ - 'statistics', - new Statement(Doctrine\ORM\Cache\Logging\StatisticsCacheLogger::class) - ]); - } - - $builder->addDefinition($cacheConfigName = $this->prefix($name . '.ormCacheConfiguration')) - ->setClass(Doctrine\ORM\Cache\CacheConfiguration::class) - ->addSetup('setCacheFactory', [$this->prefix('@' . $name . '.cacheFactory')]) - ->addSetup('setCacheLogger', [$this->prefix('@' . $name . '.cacheLogger')]) - ->setAutowired($isDefault); - - $this->getServiceDefinition($builder, $this->prefix($name . '.ormConfiguration')) - ->addSetup('setSecondLevelCacheEnabled') - ->addSetup('setSecondLevelCacheConfiguration', ['@' . $cacheConfigName]); - } - - - - protected function processConnection($name, array $defaults, $isDefault = FALSE) - { - $builder = $this->getContainerBuilder(); - $config = $this->resolveConfig($defaults, $this->connectionDefaults, $this->managerDefaults); - - if ($isDefault) { - $builder->parameters[$this->name]['dbal']['defaultConnection'] = $name; - } - - if (isset($defaults['connection'])) { - return $this->prefix('@' . $defaults['connection'] . '.connection'); - } - - // config - $configuration = $builder->addDefinition($this->prefix($name . '.dbalConfiguration')) - ->setClass(Doctrine\DBAL\Configuration::class) - ->addSetup('setResultCacheImpl', [$this->processCache($config['resultCache'], $name . '.dbalResult')]) - ->addSetup('setSQLLogger', [new Statement(Doctrine\DBAL\Logging\LoggerChain::class)]) - ->addSetup('setFilterSchemaAssetsExpression', [$config['schemaFilter']]) - ->setAutowired(FALSE); - - // types - Validators::assertField($config, 'types', 'array'); - $schemaTypes = $dbalTypes = []; - foreach ($config['types'] as $dbType => $className) { - /** @var Doctrine\DBAL\Types\Type $typeInst */ - $typeInst = Code\Helpers::createObject($className, []); - $dbalTypes[$typeInst->getName()] = $className; - $schemaTypes[$dbType] = $typeInst->getName(); - } - - // tracy panel - if ($this->isTracyPresent()) { - $builder->addDefinition($this->prefix($name . '.diagnosticsPanel')) - ->setClass(Kdyby\Doctrine\Diagnostics\Panel::class) - ->setAutowired(FALSE); - } - - // connection - $options = array_diff_key($config, array_flip(['types', 'resultCache', 'connection', 'logging'])); - $connection = $builder->addDefinition($connectionServiceId = $this->prefix($name . '.connection')) - ->setClass(Kdyby\Doctrine\Connection::class) - ->setFactory(Kdyby\Doctrine\Connection::class . '::create', [ - $options, - $this->prefix('@' . $name . '.dbalConfiguration'), - $this->prefix('@' . $name . '.evm'), - ]) - ->addSetup('setSchemaTypes', [$schemaTypes]) - ->addSetup('setDbalTypes', [$dbalTypes]) - ->addTag(self::TAG_CONNECTION) - ->addTag('kdyby.doctrine.connection') - ->setAutowired($isDefault); - - if ($this->isTracyPresent()) { - $connection->addSetup('$panel = ?->bindConnection(?)', [$this->prefix('@' . $name . '.diagnosticsPanel'), '@self']); - } - - /** @var Nette\DI\ServiceDefinition $connection */ - - $this->configuredConnections[$name] = $connectionServiceId; - - if (!is_bool($config['logging'])) { - $fileLogger = new Statement(Kdyby\Doctrine\Diagnostics\FileLogger::class, [Nette\DI\Helpers::expand($config['logging'], $builder->parameters)]); - $configuration->addSetup('$service->getSQLLogger()->addLogger(?)', [$fileLogger]); - - } elseif ($config['logging']) { - $connection->addSetup('?->enableLogging()', [new Code\PhpLiteral('$panel')]); - } - - return $this->prefix('@' . $name . '.connection'); - } - - - - /** - * @param \Nette\DI\ServiceDefinition $metadataDriver - * @param string $namespace - * @param string|array|\stdClass $driver - * @param string $prefix - * @throws \Nette\Utils\AssertionException - * @return string - */ - protected function processMetadataDriver(Nette\DI\ServiceDefinition $metadataDriver, $namespace, $driver, $prefix) - { - if (!is_string($namespace) || !Strings::match($namespace, '#^' . self::PHP_NAMESPACE . '\z#')) { - throw new Nette\Utils\AssertionException("The metadata namespace expects to be valid namespace, $namespace given."); - } - $namespace = ltrim($namespace, '\\'); - - if (is_string($driver) && strpos($driver, '@') === 0) { // service reference - $metadataDriver->addSetup('addDriver', [$driver, $namespace]); - return $driver; - } - - if (is_string($driver) || is_array($driver)) { - $paths = is_array($driver) ? $driver : [$driver]; - foreach ($paths as $path) { - if (!file_exists($path)) { - throw new Nette\Utils\AssertionException("The metadata path expects to be an existing directory, $path given."); - } - } - - $driver = new Statement(self::ANNOTATION_DRIVER, is_array($paths) ? $paths : [$paths]); - } - - $impl = $driver instanceof \stdClass ? $driver->value : ($driver instanceof Statement ? $driver->getEntity() : (string) $driver); - list($driver) = CacheHelpers::filterArgs($driver); - /** @var Statement $driver */ - - /** @var string $impl */ - if (isset($this->metadataDriverClasses[$impl])) { - $driver = new Statement($this->metadataDriverClasses[$impl], $driver->arguments); - } - - if (is_string($driver->getEntity()) && substr($driver->getEntity(), 0, 1) === '@') { - $metadataDriver->addSetup('addDriver', [$driver->getEntity(), $namespace]); - return $driver->getEntity(); - } - - if ($impl === self::ANNOTATION_DRIVER) { - $driver->arguments = [ - '@' . Doctrine\Common\Annotations\Reader::class, - Nette\Utils\Arrays::flatten($driver->arguments) - ]; - } - - $serviceName = $this->prefix($prefix . '.driver.' . str_replace('\\', '_', $namespace) . '.' . str_replace('\\', '_', $impl) . 'Impl'); - - $this->getContainerBuilder()->addDefinition($serviceName) - ->setClass(Doctrine\Common\Persistence\Mapping\Driver\MappingDriver::class) - ->setFactory($driver->getEntity(), $driver->arguments) - ->setAutowired(FALSE); - - $metadataDriver->addSetup('addDriver', ['@' . $serviceName, $namespace]); - return '@' . $serviceName; - } - - - - /** - * @param string|\stdClass $cache - * @param string $suffix - * @return string - */ - protected function processCache($cache, $suffix) - { - return CacheHelpers::processCache($this, $cache, $suffix, $this->getContainerBuilder()->parameters[$this->prefix('debug')]); - } - - - - public function beforeCompile() - { - $this->processRepositories(); - $this->processEventManagers(); - } - - - - protected function processRepositories() - { - $builder = $this->getContainerBuilder(); - - $disabled = TRUE; - foreach ($this->configuredManagers as $managerName => $_) { - $factoryClassName = $builder->getDefinition($this->prefix($managerName . '.repositoryFactory'))->getClass(); - if ($factoryClassName === Kdyby\Doctrine\RepositoryFactory::class || in_array(Kdyby\Doctrine\RepositoryFactory::class, class_parents($factoryClassName), TRUE)) { - $disabled = FALSE; - } - } - - if ($disabled) { - return; - } - - if (!method_exists($builder, 'findByType')) { - foreach ($this->configuredManagers as $managerName => $_) { - $this->getServiceDefinition($builder, $this->prefix($managerName . '.repositoryFactory')) - ->addSetup('setServiceIdsMap', [[], $this->prefix('repositoryFactory.' . $managerName . '.defaultRepositoryFactory')]); - } - - return; - } - - $serviceMap = array_fill_keys(array_keys($this->configuredManagers), []); - - /** - * @var Nette\DI\ServiceDefinition $originalDef - */ - foreach ($builder->findByType(Doctrine\ORM\EntityRepository::class) as $originalServiceName => $originalDef) { - if (strpos($originalServiceName, $this->name . '.') === 0) { - continue; // ignore - } - - $originalDefFactory = $originalDef->getFactory(); - $factory = !empty($originalDefFactory) ? $originalDefFactory->getEntity() : $originalDef->getClass(); - - if ((is_string($factory) && stripos($factory, '::getRepository') !== FALSE) - || (is_array($factory) && array_search('::getRepository', $factory) === FALSE)) { - continue; // ignore - } - $factoryServiceName = $this->prefix('repositoryFactory.' . $originalServiceName); - $factoryDef = $builder->addFactoryDefinition($factoryServiceName) - ->setImplement(IRepositoryFactory::class) - ->setParameters([Doctrine\ORM\EntityManagerInterface::class . ' entityManager', Doctrine\ORM\Mapping\ClassMetadata::class . ' classMetadata']) - ->setAutowired(FALSE) - ->getResultDefinition() - ->setFactory($originalDef->getFactory()); - $factoryStatement = $originalDef->getFactory() ?: new Statement($originalDef->getFactory()); - $factoryStatement->arguments[0] = new Code\PhpLiteral('$entityManager'); - $factoryStatement->arguments[1] = new Code\PhpLiteral('$classMetadata'); - $boundManagers = $this->getServiceBoundManagers($originalDef); - Validators::assert($boundManagers, 'list:1', 'bound manager'); - - if ($boundEntity = $originalDef->getTag(self::TAG_REPOSITORY_ENTITY)) { - if (!is_string($boundEntity) || !class_exists($boundEntity)) { - throw new Nette\Utils\AssertionException(sprintf('The entity "%s" for repository "%s" cannot be autoloaded.', $boundEntity, $originalDef->getClass())); - } - $entityArgument = $boundEntity; - - } else { - throw new Nette\Utils\AssertionException(sprintf( - 'The magic auto-detection of entity for repository %s for %s was removed from Kdyby.' . - 'You have to specify %s tag with classname of the related entity in order to use this feature.', - $originalDef->getClass(), - IRepositoryFactory::class, - self::TAG_REPOSITORY_ENTITY - )); - } - $builder->removeDefinition($originalServiceName); - $builder->addDefinition($originalServiceName) - ->setClass($originalDef->getClass()) - ->setFactory(sprintf('@%s::getRepository', $this->configuredManagers[$boundManagers[0]]), [$entityArgument]); - - $serviceMap[$boundManagers[0]][$originalDef->getClass()] = $factoryServiceName; - } - - foreach ($this->configuredManagers as $managerName => $_) { - - $this->getServiceDefinition($builder, $this->prefix($managerName . '.repositoryFactory')) - ->addSetup('setServiceIdsMap', [ - $serviceMap[$managerName], - $this->prefix('repositoryFactory.' . $managerName . '.defaultRepositoryFactory') - ]); - } - } - - - - protected function processEventManagers() - { - $builder = $this->getContainerBuilder(); - $customEvmService = $builder->getByType(\Doctrine\Common\EventManager::class); - if ($this->isKdybyEventsPresent() || !$customEvmService) { - return; - } - - foreach ($this->configuredManagers as $managerName => $_) { - - $this->getServiceDefinition($builder, $this->prefix($managerName . '.evm')) - ->setFactory('@' . $customEvmService); - } - } - - - - /** - * @param Nette\DI\ServiceDefinition $def - * @return string[] - */ - protected function getServiceBoundManagers(Nette\DI\ServiceDefinition $def) - { - $builder = $this->getContainerBuilder(); - $boundManagers = $def->getTag(self::TAG_BIND_TO_MANAGER); - - return is_array($boundManagers) ? $boundManagers : [$builder->parameters[$this->name]['orm']['defaultEntityManager']]; - } - - - - public function afterCompile(Code\ClassType $class) - { - $init = $class->getMethod('initialize'); - - if ($this->isTracyPresent()) { - $init->addBody('?::registerBluescreen($this);', [new Code\PhpLiteral(Kdyby\Doctrine\Diagnostics\Panel::class)]); - $this->addCollapsePathsToTracy($init); - } - - foreach ($this->proxyAutoloaders as $namespace => $dir) { - $originalInitialize = $init->getBody(); - $init->setBody('?::create(?, ?)->register();', [new Code\PhpLiteral(Kdyby\Doctrine\Proxy\ProxyAutoloader::class), $dir, $namespace]); - $init->addBody((string) $originalInitialize); - } - } - - - - /** + const ANNOTATION_DRIVER = 'annotations'; + const PHP_NAMESPACE = '[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff\\\\]*'; + const TAG_CONNECTION = 'doctrine.connection'; + const TAG_ENTITY_MANAGER = 'doctrine.entityManager'; + const TAG_BIND_TO_MANAGER = 'doctrine.bindToManager'; + const TAG_REPOSITORY_ENTITY = 'doctrine.repositoryEntity'; + const DEFAULT_PROXY_NAMESPACE = 'Kdyby\GeneratedProxy'; + const KDYBY_METADATA_NAMESPACE = 'Kdyby\Doctrine'; + + /** + * @var array + */ + public $consoleCommands = [ + 'orm:clear-cache:region:collection' => 'Kdyby\Doctrine\Console\Proxy\CacheClearCollectionRegionCommand', + 'orm:clear-cache:region:entity' => 'Kdyby\Doctrine\Console\Proxy\CacheClearEntityRegionCommand', + 'orm:clear-cache:metadata' => 'Kdyby\Doctrine\Console\Proxy\CacheClearMetadataCommand', + 'orm:clear-cache:query' => 'Kdyby\Doctrine\Console\Proxy\CacheClearQueryCommand', + 'orm:clear-cache:region:query' => 'Kdyby\Doctrine\Console\Proxy\CacheClearQueryRegionCommand', + 'orm:clear-cache:result' => 'Kdyby\Doctrine\Console\Proxy\CacheClearResultCommand', + 'orm:convert-mapping' => 'Kdyby\Doctrine\Console\Proxy\ConvertMappingCommand', + 'orm:generate-entities' => 'Kdyby\Doctrine\Console\Proxy\GenerateEntitiesCommand', + 'orm:generate-proxies' => 'Kdyby\Doctrine\Console\Proxy\GenerateProxiesCommand', + 'dbal:import' => 'Kdyby\Doctrine\Console\Proxy\ImportCommand', + 'orm:info' => 'Kdyby\Doctrine\Console\Proxy\InfoCommand', + 'orm:mapping:describe' => 'Kdyby\Doctrine\Console\Proxy\MappingDescribeCommand', + 'dbal:reserved-words' => 'Kdyby\Doctrine\Console\Proxy\ReservedWordsCommand', + 'orm:schema-tool:create' => 'Kdyby\Doctrine\Console\Proxy\SchemaCreateCommand', + 'orm:schema-tool:update' => 'Kdyby\Doctrine\Console\Proxy\SchemaUpdateCommand', + 'orm:schema-tool:drop' => 'Kdyby\Doctrine\Console\Proxy\SchemaDropCommand', + 'orm:validate-schema' => 'Kdyby\Doctrine\Console\Proxy\ValidateSchemaCommand', + ]; + + /** + * @var array + */ + public $managerDefaults = [ + 'metadataCache' => 'default', + 'queryCache' => 'default', + 'resultCache' => 'default', + 'hydrationCache' => 'default', + 'secondLevelCache' => [ + 'enabled' => FALSE, + 'factoryClass' => Doctrine\ORM\Cache\DefaultCacheFactory::class, + 'driver' => 'default', + 'regions' => [ + 'defaultLifetime' => 3600, + 'defaultLockLifetime' => 60, + ], + 'fileLockRegionDirectory' => '%tempDir%/cache/Doctrine.Cache.Locks', // todo fix + 'logging' => '%debugMode%', + ], + 'classMetadataFactory' => Kdyby\Doctrine\Mapping\ClassMetadataFactory::class, + 'defaultRepositoryClassName' => Kdyby\Doctrine\EntityRepository::class, + 'repositoryFactoryClassName' => Kdyby\Doctrine\RepositoryFactory::class, + 'queryBuilderClassName' => Kdyby\Doctrine\QueryBuilder::class, + 'autoGenerateProxyClasses' => '%debugMode%', + 'namingStrategy' => Doctrine\ORM\Mapping\UnderscoreNamingStrategy::class, + 'quoteStrategy' => Doctrine\ORM\Mapping\DefaultQuoteStrategy::class, + 'entityListenerResolver' => Kdyby\Doctrine\Mapping\EntityListenerResolver::class, + 'proxyDir' => '%tempDir%/proxies', + 'proxyNamespace' => self::DEFAULT_PROXY_NAMESPACE, + 'dql' => ['string' => [], 'numeric' => [], 'datetime' => [], 'hints' => []], + 'hydrators' => [], + 'metadata' => [], + 'filters' => [], + 'namespaceAlias' => [], + 'targetEntityMappings' => [], + ]; + + /** + * @var array + */ + public $connectionDefaults = [ + 'dbname' => NULL, + 'host' => '127.0.0.1', + 'port' => NULL, + 'user' => NULL, + 'password' => NULL, + 'charset' => 'UTF8', + 'driver' => 'pdo_mysql', + 'driverClass' => NULL, + 'options' => NULL, + 'path' => NULL, + 'memory' => NULL, + 'unix_socket' => NULL, + 'logging' => '%debugMode%', + 'platformService' => NULL, + 'defaultTableOptions' => [], + 'resultCache' => 'default', + 'types' => [], + 'schemaFilter' => NULL, + ]; + + /** + * @var array + */ + public $metadataDriverClasses = [ + self::ANNOTATION_DRIVER => Doctrine\ORM\Mapping\Driver\AnnotationDriver::class, + 'static' => Doctrine\Common\Persistence\Mapping\Driver\StaticPHPDriver::class, + 'yml' => Doctrine\ORM\Mapping\Driver\YamlDriver::class, + 'yaml' => Doctrine\ORM\Mapping\Driver\YamlDriver::class, + 'xml' => Doctrine\ORM\Mapping\Driver\XmlDriver::class, + 'db' => Doctrine\ORM\Mapping\Driver\DatabaseDriver::class, + ]; + + /** + * @var array + */ + private $proxyAutoloaders = []; + + /** + * @var array + */ + private $targetEntityMappings = []; + + /** + * @var array + */ + private $configuredManagers = []; + + /** + * @var array + */ + private $managerConfigs = []; + + /** + * @var array + */ + private $configuredConnections = []; + + public function loadConfiguration() + { + $this->proxyAutoloaders = $this->targetEntityMappings = $this->configuredConnections = $this->managerConfigs = $this->configuredManagers = []; + + if (!$this->compiler->getExtensions(AnnotationsExtension::class)) { + throw new Nette\Utils\AssertionException(sprintf("You should register %s before %s.", AnnotationsExtension::class, get_class($this))); + } + + $builder = $this->getContainerBuilder(); + $config = $this->getConfig(); + + $builder->parameters[$this->prefix('debug')] = !empty($config['debug']); + if (isset($config['dbname']) || isset($config['driver']) || isset($config['connection'])) { + $config = ['default' => $config]; + $defaults = ['debug' => $builder->parameters['debugMode']]; + } else { + $defaults = array_intersect_key($config, $this->managerDefaults) + array_intersect_key($config, $this->connectionDefaults) + ['debug' => $builder->parameters['debugMode']]; + + $config = array_diff_key($config, $defaults); + } + + if (empty($config)) { + throw new Kdyby\Doctrine\UnexpectedValueException("Please configure the Doctrine extensions using the section '{$this->name}:' in your config file."); + } + + foreach ($config as $name => $emConfig) { + if (!is_array($emConfig) || (empty($emConfig['dbname']) && empty($emConfig['driver']))) { + throw new Kdyby\Doctrine\UnexpectedValueException("Please configure the Doctrine extensions using the section '{$this->name}:' in your config file."); + } + + /** @var mixed[] $emConfig */ + $emConfig = Nette\DI\Config\Helpers::merge($emConfig, $defaults); + $this->processEntityManager($name, $emConfig); + } + + if ($this->targetEntityMappings) { + if (!$this->isKdybyEventsPresent()) { + throw new Nette\Utils\AssertionException('The option \'targetEntityMappings\' requires \'Kdyby\Events\DI\EventsExtension\'.', E_USER_NOTICE); + } + + $listener = $builder->addDefinition($this->prefix('resolveTargetEntityListener')) + ->setClass(Kdyby\Doctrine\Tools\ResolveTargetEntityListener::class) + ->addTag(Kdyby\Events\DI\EventsExtension::TAG_SUBSCRIBER); + + foreach ($this->targetEntityMappings as $originalEntity => $mapping) { + $listener->addSetup('addResolveTargetEntity', [$originalEntity, $mapping['targetEntity'], $mapping]); + } + } + + $this->loadConsole(); + + $builder->addDefinition($this->prefix('registry')) + ->setFactory(Kdyby\Doctrine\Registry::class, [ + $this->configuredConnections, + $this->configuredManagers, + $builder->parameters[$this->name]['dbal']['defaultConnection'], + $builder->parameters[$this->name]['orm']['defaultEntityManager'], + ]); + } + + protected function loadConsole() + { + $builder = $this->getContainerBuilder(); + $consoleApplDef = $builder->getDefinition('console.application'); + $consoleApplDef->addSetup('?->getHelperSet()->set(?)', ['@self', new Statement(ContainerHelper::class)]); + + foreach ($this->consoleCommands as $name => $command) { + $cli = $builder->addDefinition($this->prefix(str_replace([':', '-', '_'], ['', '', ''], $name))) + ->addTag('console.command', $name) + ->setAutowired(false) + ->addTag(Nette\DI\Extensions\InjectExtension::TAG_INJECT, FALSE); // lazy injects + + if (is_string($command)) { + $cli->setClass($command); + } else { + throw new Kdyby\Doctrine\NotSupportedException; + } + } + } + + protected function processEntityManager($name, array $defaults) + { + $builder = $this->getContainerBuilder(); + $config = $this->resolveConfig($defaults, $this->managerDefaults, $this->connectionDefaults); + + if ($isDefault = !isset($builder->parameters[$this->name]['orm']['defaultEntityManager'])) { + $builder->parameters[$this->name]['orm']['defaultEntityManager'] = $name; + } + + $metadataDriver = $builder->addDefinition($this->prefix($name . '.metadataDriver')) + ->setClass(Doctrine\Persistence\Mapping\Driver\MappingDriverChain::class) + ->setAutowired(FALSE); + /** @var \Nette\DI\ServiceDefinition $metadataDriver */ + Validators::assertField($config, 'metadata', 'array'); + Validators::assertField($config, 'targetEntityMappings', 'array'); + $config['targetEntityMappings'] = $this->normalizeTargetEntityMappings($config['targetEntityMappings']); + foreach ($this->compiler->getExtensions() as $extension) { + if ($extension instanceof IEntityProvider) { + $metadata = $extension->getEntityMappings(); + Validators::assert($metadata, 'array'); + foreach ($metadata as $namespace => $nsConfig) { + if (array_key_exists($namespace, $config['metadata'])) { + throw new Nette\Utils\AssertionException(sprintf('The namespace %s is already configured, provider cannot change it', $namespace)); + } + $config['metadata'][$namespace] = $nsConfig; + } + } + + if ($extension instanceof ITargetEntityProvider) { + $targetEntities = $extension->getTargetEntityMappings(); + Validators::assert($targetEntities, 'array'); + $config['targetEntityMappings'] = Nette\Utils\Arrays::mergeTree($config['targetEntityMappings'], $this->normalizeTargetEntityMappings($targetEntities)); + } + + if ($extension instanceof IDatabaseTypeProvider) { + $providedTypes = $extension->getDatabaseTypes(); + Validators::assert($providedTypes, 'array'); + + if (!isset($defaults['types'])) { + $defaults['types'] = []; + } + + $defaults['types'] = array_merge($defaults['types'], $providedTypes); + } + } + + foreach (self::natSortKeys($config['metadata']) as $namespace => $driver) { + $this->processMetadataDriver($metadataDriver, $namespace, $driver, $name); + } + + $this->processMetadataDriver($metadataDriver, self::KDYBY_METADATA_NAMESPACE, __DIR__ . '/../Entities', $name); + + if (empty($config['metadata'])) { + $metadataDriver->addSetup('setDefaultDriver', [ + new Statement($this->metadataDriverClasses[self::ANNOTATION_DRIVER], [ + '@' . Doctrine\Common\Annotations\Reader::class, + [Nette\DI\Helpers::expand('%appDir%', $builder->parameters)] + ]) + ]); + } + + if ($config['repositoryFactoryClassName'] === 'default') { + $config['repositoryFactoryClassName'] = DefaultRepositoryFactory::class; + } + $builder->addDefinition($this->prefix($name . '.repositoryFactory')) + ->setClass($config['repositoryFactoryClassName']) + ->setAutowired(FALSE); + + Validators::assertField($config, 'namespaceAlias', 'array'); + Validators::assertField($config, 'hydrators', 'array'); + Validators::assertField($config, 'dql', 'array'); + Validators::assertField($config['dql'], 'string', 'array'); + Validators::assertField($config['dql'], 'numeric', 'array'); + Validators::assertField($config['dql'], 'datetime', 'array'); + Validators::assertField($config['dql'], 'hints', 'array'); + + $autoGenerateProxyClasses = is_bool($config['autoGenerateProxyClasses']) ? ($config['autoGenerateProxyClasses'] ? AbstractProxyFactory::AUTOGENERATE_ALWAYS : AbstractProxyFactory::AUTOGENERATE_FILE_NOT_EXISTS) : $config['autoGenerateProxyClasses']; + + $configuration = $builder->addDefinition($this->prefix($name . '.ormConfiguration')) + ->setClass(Kdyby\Doctrine\Configuration::class) + ->addSetup('setMetadataCacheImpl', [$this->processCache($config['metadataCache'], $name . '.metadata')]) + ->addSetup('setQueryCacheImpl', [$this->processCache($config['queryCache'], $name . '.query')]) + ->addSetup('setResultCacheImpl', [$this->processCache($config['resultCache'], $name . '.ormResult')]) + ->addSetup('setHydrationCacheImpl', [$this->processCache($config['hydrationCache'], $name . '.hydration')]) + ->addSetup('setMetadataDriverImpl', [$this->prefix('@' . $name . '.metadataDriver')]) + ->addSetup('setClassMetadataFactoryName', [$config['classMetadataFactory']]) + ->addSetup('setDefaultRepositoryClassName', [$config['defaultRepositoryClassName']]) + ->addSetup('setQueryBuilderClassName', [$config['queryBuilderClassName']]) + ->addSetup('setRepositoryFactory', [$this->prefix('@' . $name . '.repositoryFactory')]) + ->addSetup('setProxyDir', [$config['proxyDir']]) + ->addSetup('setProxyNamespace', [$config['proxyNamespace']]) + ->addSetup('setAutoGenerateProxyClasses', [$autoGenerateProxyClasses]) + ->addSetup('setEntityNamespaces', [$config['namespaceAlias']]) + ->addSetup('setCustomHydrationModes', [$config['hydrators']]) + ->addSetup('setCustomStringFunctions', [$config['dql']['string']]) + ->addSetup('setCustomNumericFunctions', [$config['dql']['numeric']]) + ->addSetup('setCustomDatetimeFunctions', [$config['dql']['datetime']]) + ->addSetup('setDefaultQueryHints', [$config['dql']['hints']]) + ->addSetup('setNamingStrategy', CacheHelpers::filterArgs($config['namingStrategy'])) + ->addSetup('setQuoteStrategy', CacheHelpers::filterArgs($config['quoteStrategy'])) + ->addSetup('setEntityListenerResolver', CacheHelpers::filterArgs($config['entityListenerResolver'])) + ->setAutowired(FALSE); + /** @var Nette\DI\ServiceDefinition $configuration */ + $this->proxyAutoloaders[$config['proxyNamespace']] = $config['proxyDir']; + + $this->processSecondLevelCache($name, $config['secondLevelCache'], $isDefault); + + Validators::assertField($config, 'filters', 'array'); + foreach ($config['filters'] as $filterName => $filterClass) { + $configuration->addSetup('addFilter', [$filterName, $filterClass]); + } + + if ($config['targetEntityMappings']) { + $configuration->addSetup('setTargetEntityMap', [array_map(function ($mapping) + { + return $mapping['targetEntity']; + }, $config['targetEntityMappings'])]); + $this->targetEntityMappings = Nette\Utils\Arrays::mergeTree($this->targetEntityMappings, $config['targetEntityMappings']); + } + + if ($this->isKdybyEventsPresent()) { + $builder->addDefinition($this->prefix($name . '.evm')) + ->setFactory(Kdyby\Events\NamespacedEventManager::class, [Kdyby\Doctrine\Events::NS . '::']) + ->addSetup('$dispatchGlobalEvents', [TRUE]) // for BC + ->setAutowired(FALSE); + } else { + $builder->addDefinition($this->prefix($name . '.evm')) + ->setClass('Doctrine\Common\EventManager') + ->setAutowired(FALSE); + } + + // entity manager + $entityManager = $builder->addDefinition($managerServiceId = $this->prefix($name . '.entityManager')) + ->setClass(Kdyby\Doctrine\EntityManager::class) + ->setFactory(Kdyby\Doctrine\EntityManager::class . '::create', [ + $connectionService = $this->processConnection($name, $defaults, $isDefault), + $this->prefix('@' . $name . '.ormConfiguration'), + $this->prefix('@' . $name . '.evm'), + ]) + ->addTag(self::TAG_ENTITY_MANAGER) + ->addTag('kdyby.doctrine.entityManager') + ->setAutowired($isDefault); + + if ($this->isTracyPresent()) { + $entityManager->addSetup('?->bindEntityManager(?)', [$this->prefix('@' . $name . '.diagnosticsPanel'), '@self']); + } + + $builder->addFactoryDefinition($this->prefix('repositoryFactory.' . $name . '.defaultRepositoryFactory')) + ->setImplement(IRepositoryFactory::class) + ->setParameters([EntityManagerInterface::class . ' entityManager', Doctrine\ORM\Mapping\ClassMetadata::class . ' classMetadata']) + ->getResultDefinition() + ->setFactory($config['defaultRepositoryClassName']) + ->setArguments([new Code\PhpLiteral('$entityManager'), new Code\PhpLiteral('$classMetadata')]) + ->setAutowired(FALSE); + + $builder->addDefinition($this->prefix($name . '.schemaValidator')) + ->setFactory(Doctrine\ORM\Tools\SchemaValidator::class, ['@' . $managerServiceId]) + ->setAutowired($isDefault); + + $builder->addDefinition($this->prefix($name . '.schemaTool')) + ->setFactory(Doctrine\ORM\Tools\SchemaTool::class, ['@' . $managerServiceId]) + ->setAutowired($isDefault); + + $cacheCleaner = $builder->addDefinition($this->prefix($name . '.cacheCleaner')) + ->setFactory(Kdyby\Doctrine\Tools\CacheCleaner::class, ['@' . $managerServiceId]) + ->setAutowired($isDefault); + + $builder->addDefinition($this->prefix($name . '.schemaManager')) + ->setClass(AbstractSchemaManager::class) + ->setFactory('@' . Kdyby\Doctrine\Connection::class . '::getSchemaManager') + ->setAutowired($isDefault); + + foreach ($this->compiler->getExtensions(AnnotationsExtension::class) as $extension) { + /** @var AnnotationsExtension $extension */ + $cacheCleaner->addSetup('addCacheStorage', [$extension->prefix('@cache.annotations')]); + } + + if ($isDefault) { + $builder->addDefinition($this->prefix('helper.entityManager')) + ->setFactory(EntityManagerHelper::class, ['@' . $managerServiceId]) + ->addTag('console.helpers', 'em'); + + $builder->addDefinition($this->prefix('helper.connection')) + ->setFactory(ConnectionHelper::class, [$connectionService]) + ->addTag('console.helpers', 'db'); + + $builder->addAlias($this->prefix('schemaValidator'), $this->prefix($name . '.schemaValidator')); + $builder->addAlias($this->prefix('schemaTool'), $this->prefix($name . '.schemaTool')); + $builder->addAlias($this->prefix('cacheCleaner'), $this->prefix($name . '.cacheCleaner')); + $builder->addAlias($this->prefix('schemaManager'), $this->prefix($name . '.schemaManager')); + } + + $this->configuredManagers[$name] = $managerServiceId; + $this->managerConfigs[$name] = $config; + } + + protected function processSecondLevelCache($name, array $config, $isDefault) + { + if (!$config['enabled']) { + return; + } + + $builder = $this->getContainerBuilder(); + + $cacheFactory = $builder->addDefinition($this->prefix($name . '.cacheFactory')) + ->setClass(Doctrine\ORM\Cache\CacheFactory::class) + ->setFactory($config['factoryClass'], [ + $this->prefix('@' . $name . '.cacheRegionsConfiguration'), + $this->processCache($config['driver'], $name . '.secondLevel'), + ]) + ->setAutowired($isDefault); + + if ($config['factoryClass'] === $this->managerDefaults['secondLevelCache']['factoryClass'] || is_subclass_of($config['factoryClass'], $this->managerDefaults['secondLevelCache']['factoryClass']) + ) { + $cacheFactory->addSetup('setFileLockRegionDirectory', [$config['fileLockRegionDirectory']]); + } + + $builder->addDefinition($this->prefix($name . '.cacheRegionsConfiguration')) + ->setClass(Doctrine\ORM\Cache\RegionsConfiguration::class, [ + $config['regions']['defaultLifetime'], + $config['regions']['defaultLockLifetime'], + ]) + ->setAutowired($isDefault); + + $logger = $builder->addDefinition($this->prefix($name . '.cacheLogger')) + ->setClass(Doctrine\ORM\Cache\Logging\CacheLogger::class) + ->setFactory(Doctrine\ORM\Cache\Logging\CacheLoggerChain::class) + ->setAutowired(FALSE); + + if ($config['logging']) { + $logger->addSetup('setLogger', [ + 'statistics', + new Statement(Doctrine\ORM\Cache\Logging\StatisticsCacheLogger::class) + ]); + } + + $builder->addDefinition($cacheConfigName = $this->prefix($name . '.ormCacheConfiguration')) + ->setClass(Doctrine\ORM\Cache\CacheConfiguration::class) + ->addSetup('setCacheFactory', [$this->prefix('@' . $name . '.cacheFactory')]) + ->addSetup('setCacheLogger', [$this->prefix('@' . $name . '.cacheLogger')]) + ->setAutowired($isDefault); + + $this->getServiceDefinition($builder, $this->prefix($name . '.ormConfiguration')) + ->addSetup('setSecondLevelCacheEnabled') + ->addSetup('setSecondLevelCacheConfiguration', ['@' . $cacheConfigName]); + } + + protected function processConnection($name, array $defaults, $isDefault = FALSE) + { + $builder = $this->getContainerBuilder(); + $config = $this->resolveConfig($defaults, $this->connectionDefaults, $this->managerDefaults); + + if ($isDefault) { + $builder->parameters[$this->name]['dbal']['defaultConnection'] = $name; + } + + if (isset($defaults['connection'])) { + return $this->prefix('@' . $defaults['connection'] . '.connection'); + } + + // config + $configuration = $builder->addDefinition($this->prefix($name . '.dbalConfiguration')) + ->setClass(Doctrine\DBAL\Configuration::class) + ->addSetup('setResultCacheImpl', [$this->processCache($config['resultCache'], $name . '.dbalResult')]) + ->addSetup('setSQLLogger', [new Statement(Doctrine\DBAL\Logging\LoggerChain::class)]) + ->addSetup('setFilterSchemaAssetsExpression', [$config['schemaFilter']]) + ->setAutowired(FALSE); + + // types + Validators::assertField($config, 'types', 'array'); + $schemaTypes = $dbalTypes = []; + foreach ($config['types'] as $dbType => $className) { + /** @var Doctrine\DBAL\Types\Type $typeInst */ + $typeInst = Code\Helpers::createObject($className, []); + $dbalTypes[$typeInst->getName()] = $className; + $schemaTypes[$dbType] = $typeInst->getName(); + } + + // tracy panel + if ($this->isTracyPresent()) { + $builder->addDefinition($this->prefix($name . '.diagnosticsPanel')) + ->setClass(Kdyby\Doctrine\Diagnostics\Panel::class) + ->setAutowired(FALSE); + } + + // connection + $options = array_diff_key($config, array_flip(['types', 'resultCache', 'connection', 'logging'])); + $connection = $builder->addDefinition($connectionServiceId = $this->prefix($name . '.connection')) + ->setClass(Kdyby\Doctrine\Connection::class) + ->setFactory(Kdyby\Doctrine\Connection::class . '::create', [ + $options, + $this->prefix('@' . $name . '.dbalConfiguration'), + $this->prefix('@' . $name . '.evm'), + ]) + ->addSetup('setSchemaTypes', [$schemaTypes]) + ->addSetup('setDbalTypes', [$dbalTypes]) + ->addTag(self::TAG_CONNECTION) + ->addTag('kdyby.doctrine.connection') + ->setAutowired($isDefault); + + if ($this->isTracyPresent()) { + $connection->addSetup('$panel = ?->bindConnection(?)', [$this->prefix('@' . $name . '.diagnosticsPanel'), '@self']); + } + + /** @var Nette\DI\ServiceDefinition $connection */ + $this->configuredConnections[$name] = $connectionServiceId; + + if (!is_bool($config['logging'])) { + $fileLogger = new Statement(Kdyby\Doctrine\Diagnostics\FileLogger::class, [Nette\DI\Helpers::expand($config['logging'], $builder->parameters)]); + $configuration->addSetup('$service->getSQLLogger()->addLogger(?)', [$fileLogger]); + } elseif ($config['logging']) { + $connection->addSetup('?->enableLogging()', [new Code\PhpLiteral('$panel')]); + } + + return $this->prefix('@' . $name . '.connection'); + } + + /** + * @param \Nette\DI\ServiceDefinition $metadataDriver + * @param string $namespace + * @param string|array|\stdClass $driver + * @param string $prefix + * @throws \Nette\Utils\AssertionException + * @return string + */ + protected function processMetadataDriver(Nette\DI\ServiceDefinition $metadataDriver, $namespace, $driver, $prefix) + { + if (!is_string($namespace) || !Strings::match($namespace, '#^' . self::PHP_NAMESPACE . '\z#')) { + throw new Nette\Utils\AssertionException("The metadata namespace expects to be valid namespace, $namespace given."); + } + $namespace = ltrim($namespace, '\\'); + + if (is_string($driver) && strpos($driver, '@') === 0) { // service reference + $metadataDriver->addSetup('addDriver', [$driver, $namespace]); + return $driver; + } + + if (is_string($driver) || is_array($driver)) { + $paths = is_array($driver) ? $driver : [$driver]; + foreach ($paths as $path) { + if (!file_exists($path)) { + throw new Nette\Utils\AssertionException("The metadata path expects to be an existing directory, $path given."); + } + } + + $driver = new Statement(self::ANNOTATION_DRIVER, is_array($paths) ? $paths : [$paths]); + } + + $impl = $driver instanceof \stdClass ? $driver->value : ($driver instanceof Statement ? $driver->getEntity() : (string) $driver); + list($driver) = CacheHelpers::filterArgs($driver); + /** @var Statement $driver */ + /** @var string $impl */ + if (isset($this->metadataDriverClasses[$impl])) { + $driver = new Statement($this->metadataDriverClasses[$impl], $driver->arguments); + } + + if (is_string($driver->getEntity()) && substr($driver->getEntity(), 0, 1) === '@') { + $metadataDriver->addSetup('addDriver', [$driver->getEntity(), $namespace]); + return $driver->getEntity(); + } + + if ($impl === self::ANNOTATION_DRIVER) { + $driver->arguments = [ + '@' . Doctrine\Common\Annotations\Reader::class, + Nette\Utils\Arrays::flatten($driver->arguments) + ]; + } + + $serviceName = $this->prefix($prefix . '.driver.' . str_replace('\\', '_', $namespace) . '.' . str_replace('\\', '_', $impl) . 'Impl'); + + $this->getContainerBuilder()->addDefinition($serviceName) + ->setClass(Doctrine\Persistence\Mapping\Driver\MappingDriver::class) + ->setFactory($driver->getEntity(), $driver->arguments) + ->setAutowired(FALSE); + + $metadataDriver->addSetup('addDriver', ['@' . $serviceName, $namespace]); + return '@' . $serviceName; + } + + /** + * @param string|\stdClass $cache + * @param string $suffix + * @return string + */ + protected function processCache($cache, $suffix) + { + return CacheHelpers::processCache($this, $cache, $suffix, $this->getContainerBuilder()->parameters[$this->prefix('debug')]); + } + + public function beforeCompile() + { + $this->processRepositories(); + $this->processEventManagers(); + } + + protected function processRepositories() + { + $builder = $this->getContainerBuilder(); + + $disabled = TRUE; + foreach ($this->configuredManagers as $managerName => $_) { + $factoryClassName = $builder->getDefinition($this->prefix($managerName . '.repositoryFactory'))->getClass(); + if ($factoryClassName === Kdyby\Doctrine\RepositoryFactory::class || in_array(Kdyby\Doctrine\RepositoryFactory::class, class_parents($factoryClassName), TRUE)) { + $disabled = FALSE; + } + } + + if ($disabled) { + return; + } + + if (!method_exists($builder, 'findByType')) { + foreach ($this->configuredManagers as $managerName => $_) { + $this->getServiceDefinition($builder, $this->prefix($managerName . '.repositoryFactory')) + ->addSetup('setServiceIdsMap', [[], $this->prefix('repositoryFactory.' . $managerName . '.defaultRepositoryFactory')]); + } + + return; + } + + $serviceMap = array_fill_keys(array_keys($this->configuredManagers), []); + + /** + * @var Nette\DI\ServiceDefinition $originalDef + */ + foreach ($builder->findByType(Doctrine\ORM\EntityRepository::class) as $originalServiceName => $originalDef) { + if (strpos($originalServiceName, $this->name . '.') === 0) { + continue; // ignore + } + + $originalDefFactory = $originalDef->getFactory(); + $factory = !empty($originalDefFactory) ? $originalDefFactory->getEntity() : $originalDef->getClass(); + + if ((is_string($factory) && stripos($factory, '::getRepository') !== FALSE) || (is_array($factory) && array_search('::getRepository', $factory) === FALSE)) { + continue; // ignore + } + $factoryServiceName = $this->prefix('repositoryFactory.' . $originalServiceName); + $factoryDef = $builder->addFactoryDefinition($factoryServiceName) + ->setImplement(IRepositoryFactory::class) + ->setParameters([Doctrine\ORM\EntityManagerInterface::class . ' entityManager', Doctrine\ORM\Mapping\ClassMetadata::class . ' classMetadata']) + ->setAutowired(FALSE) + ->getResultDefinition() + ->setFactory($originalDef->getFactory()); + $factoryStatement = $originalDef->getFactory() ?: new Statement($originalDef->getFactory()); + $factoryStatement->arguments[0] = new Code\PhpLiteral('$entityManager'); + $factoryStatement->arguments[1] = new Code\PhpLiteral('$classMetadata'); + $boundManagers = $this->getServiceBoundManagers($originalDef); + Validators::assert($boundManagers, 'list:1', 'bound manager'); + + if ($boundEntity = $originalDef->getTag(self::TAG_REPOSITORY_ENTITY)) { + if (!is_string($boundEntity) || !class_exists($boundEntity)) { + throw new Nette\Utils\AssertionException(sprintf('The entity "%s" for repository "%s" cannot be autoloaded.', $boundEntity, $originalDef->getClass())); + } + $entityArgument = $boundEntity; + } else { + throw new Nette\Utils\AssertionException(sprintf( + 'The magic auto-detection of entity for repository %s for %s was removed from Kdyby.' . + 'You have to specify %s tag with classname of the related entity in order to use this feature.', + $originalDef->getClass(), + IRepositoryFactory::class, + self::TAG_REPOSITORY_ENTITY + )); + } + $builder->removeDefinition($originalServiceName); + $builder->addDefinition($originalServiceName) + ->setClass($originalDef->getClass()) + ->setFactory(sprintf('@%s::getRepository', $this->configuredManagers[$boundManagers[0]]), [$entityArgument]); + + $serviceMap[$boundManagers[0]][$originalDef->getClass()] = $factoryServiceName; + } + + foreach ($this->configuredManagers as $managerName => $_) { + + $this->getServiceDefinition($builder, $this->prefix($managerName . '.repositoryFactory')) + ->addSetup('setServiceIdsMap', [ + $serviceMap[$managerName], + $this->prefix('repositoryFactory.' . $managerName . '.defaultRepositoryFactory') + ]); + } + } + + protected function processEventManagers() + { + $builder = $this->getContainerBuilder(); + $customEvmService = $builder->getByType(\Doctrine\Common\EventManager::class); + if ($this->isKdybyEventsPresent() || !$customEvmService) { + return; + } + + foreach ($this->configuredManagers as $managerName => $_) { + + $this->getServiceDefinition($builder, $this->prefix($managerName . '.evm')) + ->setFactory('@' . $customEvmService); + } + } + + /** + * @param Nette\DI\ServiceDefinition $def + * @return string[] + */ + protected function getServiceBoundManagers(Nette\DI\ServiceDefinition $def) + { + $builder = $this->getContainerBuilder(); + $boundManagers = $def->getTag(self::TAG_BIND_TO_MANAGER); + + return is_array($boundManagers) ? $boundManagers : [$builder->parameters[$this->name]['orm']['defaultEntityManager']]; + } + + public function afterCompile(Code\ClassType $class) + { + $init = $class->getMethod('initialize'); + + if ($this->isTracyPresent()) { + $init->addBody('?::registerBluescreen($this);', [new Code\PhpLiteral(Kdyby\Doctrine\Diagnostics\Panel::class)]); + $this->addCollapsePathsToTracy($init); + } + + foreach ($this->proxyAutoloaders as $namespace => $dir) { + $originalInitialize = $init->getBody(); + $init->setBody('?::create(?, ?)->register();', [new Code\PhpLiteral(Kdyby\Doctrine\Proxy\ProxyAutoloader::class), $dir, $namespace]); + $init->addBody((string) $originalInitialize); + } + } + + /** * @param array $provided * @param array $defaults * @param array $diff - * @return array - */ - private function resolveConfig(array $provided, array $defaults, array $diff = []) - { - return Nette\DI\Helpers::expand(Nette\DI\Config\Helpers::merge( - array_diff_key($provided, array_diff_key($diff, $defaults)), - $defaults - ), $this->compiler->getContainerBuilder()->parameters); - } - - - /** - * @param array $targetEntityMappings - * @return array - */ - private function normalizeTargetEntityMappings(array $targetEntityMappings) - { - $normalized = []; - foreach ($targetEntityMappings as $originalEntity => $targetEntity) { - $originalEntity = ltrim($originalEntity, '\\'); - Validators::assert($targetEntity, 'array|string'); - if (is_array($targetEntity)) { - Validators::assertField($targetEntity, 'targetEntity', 'string'); - $mapping = array_merge($targetEntity, [ - 'targetEntity' => ltrim($targetEntity['targetEntity'], '\\') - ]); - - } else { - $mapping = [ - 'targetEntity' => ltrim($targetEntity, '\\'), - ]; - } - $normalized[$originalEntity] = $mapping; - } - return $normalized; - } - - - - /** - * @return bool - */ - private function isTracyPresent() - { - return interface_exists(\Tracy\IBarPanel::class); - } - - - - /** - * @return bool - */ - private function isKdybyEventsPresent() - { - return (bool) $this->compiler->getExtensions(\Kdyby\Events\DI\EventsExtension::class); - } - - - - private function addCollapsePathsToTracy(Method $init) - { - $blueScreen = \Tracy\Debugger::class . '::getBlueScreen()'; - $commonDirname = dirname(Nette\Reflection\ClassType::from(Doctrine\Common\Version::class)->getFileName()); - - $init->addBody($blueScreen . '->collapsePaths[] = ?;', [dirname(Nette\Reflection\ClassType::from(Kdyby\Doctrine\Exception::class)->getFileName())]); - $init->addBody($blueScreen . '->collapsePaths[] = ?;', [dirname(dirname(dirname(dirname($commonDirname))))]); // this should be vendor/doctrine - foreach ($this->proxyAutoloaders as $dir) { - $init->addBody($blueScreen . '->collapsePaths[] = ?;', [$dir]); - } - } - - - - /** - * @param \Nette\Configurator $configurator - */ - public static function register(Nette\Configurator $configurator) - { - $configurator->onCompile[] = function ($config, Nette\DI\Compiler $compiler) { - $compiler->addExtension('doctrine', new OrmExtension()); - }; - } - - - - /** - * @param array $array - */ - private static function natSortKeys(array &$array) - { - $keys = array_keys($array); - natsort($keys); - $keys = array_flip(array_reverse($keys, TRUE)); - $array = array_merge($keys, $array); - return $array; - } - - private function getServiceDefinition(ContainerBuilder $builder, string $name): ServiceDefinition - { - $definition = $builder->getDefinition($name); - assert($definition instanceof ServiceDefinition); - return $definition; - } + * @return array + */ + private function resolveConfig(array $provided, array $defaults, array $diff = []) + { + return Nette\DI\Helpers::expand(Nette\DI\Config\Helpers::merge( + array_diff_key($provided, array_diff_key($diff, $defaults)), + $defaults + ), $this->compiler->getContainerBuilder()->parameters); + } + + /** + * @param array $targetEntityMappings + * @return array + */ + private function normalizeTargetEntityMappings(array $targetEntityMappings) + { + $normalized = []; + foreach ($targetEntityMappings as $originalEntity => $targetEntity) { + $originalEntity = ltrim($originalEntity, '\\'); + Validators::assert($targetEntity, 'array|string'); + if (is_array($targetEntity)) { + Validators::assertField($targetEntity, 'targetEntity', 'string'); + $mapping = array_merge($targetEntity, [ + 'targetEntity' => ltrim($targetEntity['targetEntity'], '\\') + ]); + } else { + $mapping = [ + 'targetEntity' => ltrim($targetEntity, '\\'), + ]; + } + $normalized[$originalEntity] = $mapping; + } + return $normalized; + } + + /** + * @return bool + */ + private function isTracyPresent() + { + return interface_exists(\Tracy\IBarPanel::class); + } + + /** + * @return bool + */ + private function isKdybyEventsPresent() + { + return (bool) $this->compiler->getExtensions(\Kdyby\Events\DI\EventsExtension::class); + } + + private function addCollapsePathsToTracy(Method $init) + { + $blueScreen = \Tracy\Debugger::class . '::getBlueScreen()'; + $commonDirname = dirname((new \ReflectionClass(\Doctrine\Common\CommonException::class))->getFileName()); + + $init->addBody($blueScreen . '->collapsePaths[] = ?;', [dirname((new \ReflectionClass(Kdyby\Doctrine\Exception::class))->getFileName())]); + $init->addBody($blueScreen . '->collapsePaths[] = ?;', [dirname(dirname(dirname(dirname($commonDirname))))]); // this should be vendor/doctrine + foreach ($this->proxyAutoloaders as $dir) { + $init->addBody($blueScreen . '->collapsePaths[] = ?;', [$dir]); + } + } + + /** + * @param \Nette\Configurator $configurator + */ + public static function register(Nette\Configurator $configurator) + { + $configurator->onCompile[] = function ($config, Nette\DI\Compiler $compiler) + { + $compiler->addExtension('doctrine', new OrmExtension()); + }; + } + + /** + * @param array $array + */ + private static function natSortKeys(array &$array) + { + $keys = array_keys($array); + natsort($keys); + $keys = array_flip(array_reverse($keys, TRUE)); + $array = array_merge($keys, $array); + return $array; + } + + private function getServiceDefinition(ContainerBuilder $builder, string $name): ServiceDefinition + { + $definition = $builder->getDefinition($name); + assert($definition instanceof ServiceDefinition); + return $definition; + } } diff --git a/src/Kdyby/Doctrine/DI/console.neon b/src/Kdyby/Doctrine/DI/console.neon deleted file mode 100644 index af70cdac..00000000 --- a/src/Kdyby/Doctrine/DI/console.neon +++ /dev/null @@ -1,17 +0,0 @@ -- Kdyby\Doctrine\Console\Proxy\CacheClearCollectionRegionCommand -- Kdyby\Doctrine\Console\Proxy\CacheClearEntityRegionCommand -- Kdyby\Doctrine\Console\Proxy\CacheClearMetadataCommand -- Kdyby\Doctrine\Console\Proxy\CacheClearQueryCommand -- Kdyby\Doctrine\Console\Proxy\CacheClearQueryRegionCommand -- Kdyby\Doctrine\Console\Proxy\CacheClearResultCommand -- Kdyby\Doctrine\Console\Proxy\ConvertMappingCommand -- Kdyby\Doctrine\Console\Proxy\GenerateEntitiesCommand -- Kdyby\Doctrine\Console\Proxy\GenerateProxiesCommand -- Kdyby\Doctrine\Console\Proxy\ImportCommand -- Kdyby\Doctrine\Console\Proxy\InfoCommand -- Kdyby\Doctrine\Console\Proxy\MappingDescribeCommand -- Kdyby\Doctrine\Console\Proxy\ReservedWordsCommand -- Kdyby\Doctrine\Console\Proxy\SchemaCreateCommand -- Kdyby\Doctrine\Console\Proxy\SchemaUpdateCommand -- Kdyby\Doctrine\Console\Proxy\SchemaDropCommand -- Kdyby\Doctrine\Console\Proxy\ValidateSchemaCommand diff --git a/src/Kdyby/Doctrine/Mapping/RuntimeReflectionService.php b/src/Kdyby/Doctrine/Mapping/RuntimeReflectionService.php index fece83bc..94be530d 100644 --- a/src/Kdyby/Doctrine/Mapping/RuntimeReflectionService.php +++ b/src/Kdyby/Doctrine/Mapping/RuntimeReflectionService.php @@ -20,36 +20,13 @@ /** * @author Filip Procházka */ -class RuntimeReflectionService extends Doctrine\Common\Persistence\Mapping\RuntimeReflectionService +class RuntimeReflectionService extends Doctrine\Persistence\Mapping\RuntimeReflectionService { - /** - * Return a reflection class instance or null - * - * @param string $class - * @return \Nette\Reflection\ClassType - */ - public function getClass($class) - { - return new Reflection\ClassType($class); - } - - - - /** - * Return an accessible property (setAccessible(true)) or null. - * - * @param string $class - * @param string $property - * @return \Nette\Reflection\Property|NULL - */ public function getAccessibleProperty($class, $property) { try { - $property = new Reflection\Property($class, $property); - $property->setAccessible(TRUE); - - return $property; + return parent::getAccessibleProperty($class, $property); } catch (\ReflectionException $e) { return NULL; diff --git a/src/Kdyby/Doctrine/Registry.php b/src/Kdyby/Doctrine/Registry.php index bb3c0e8a..e8c1398e 100644 --- a/src/Kdyby/Doctrine/Registry.php +++ b/src/Kdyby/Doctrine/Registry.php @@ -10,7 +10,7 @@ namespace Kdyby\Doctrine; -use Doctrine\Common\Persistence\AbstractManagerRegistry; +use Doctrine\Persistence\AbstractManagerRegistry; use Doctrine\ORM\ORMException; use Kdyby; use Nette; diff --git a/tests/KdybyTests/Doctrine/Console/CommandTestCase.php b/tests/KdybyTests/Doctrine/Console/CommandTestCase.php index 99b21680..635ec876 100644 --- a/tests/KdybyTests/Doctrine/Console/CommandTestCase.php +++ b/tests/KdybyTests/Doctrine/Console/CommandTestCase.php @@ -83,12 +83,12 @@ protected function executeCommand($command, array $input = [], array $options = /** - * @return Kdyby\Console\Application + * @return Contributte\Console\Application */ protected function getApplication() { - /** @var \Kdyby\Console\Application $application */ - $application = $this->getServiceLocator()->getByType(\Kdyby\Console\Application::class); + /** @var \Contributte\Console\Application $application */ + $application = $this->getServiceLocator()->getByType(\Contributte\Console\Application::class); $application->setAutoExit(FALSE); return $application; } diff --git a/tests/KdybyTests/Doctrine/Extension.phpt b/tests/KdybyTests/Doctrine/Extension.phpt index 24e6791f..e2220d82 100644 --- a/tests/KdybyTests/Doctrine/Extension.phpt +++ b/tests/KdybyTests/Doctrine/Extension.phpt @@ -179,10 +179,12 @@ class ExtensionTest extends Tester\TestCase $env['SESSION_ID'] = $sessionId = $compileOutput[1]; $storeOutput = self::runExternalScript(__DIR__ . '/proxies-sessions-test/run.php', ['store'], $env); - Assert::match(\Kdyby\Doctrine\DI\OrmExtension::DEFAULT_PROXY_NAMESPACE . '\__CG__\\' . \KdybyTests\Doctrine\CmsOrder::class . ' %A%id => 1%A%status => "new"%A%', $storeOutput); +// Assert::match(\Kdyby\Doctrine\DI\OrmExtension::DEFAULT_PROXY_NAMESPACE . '\__CG__\\' . \KdybyTests\Doctrine\CmsOrder::class . ' %A%id => 1%A%status => "new"%A%', $storeOutput); + Assert::match(preg_replace('/#\w+/', '', file_get_contents(__DIR__ . '/proxies-sessions-test/data/expected-tracy-dump-store')), preg_replace('/#\w+/', '', $storeOutput)); $runOutput = self::runExternalScript(__DIR__ . '/proxies-sessions-test/run.php', ['read'], $env); - Assert::match(\Kdyby\Doctrine\DI\OrmExtension::DEFAULT_PROXY_NAMESPACE . '\__CG__\\' . \KdybyTests\Doctrine\CmsOrder::class . ' %A%id => 1%A%status => "new"%A%', $runOutput); +// Assert::match(\Kdyby\Doctrine\DI\OrmExtension::DEFAULT_PROXY_NAMESPACE . '\__CG__\\' . \KdybyTests\Doctrine\CmsOrder::class . ' %A%id => 1%A%status => "new"%A%', $runOutput); + Assert::match(preg_replace('/#\w+/', '', file_get_contents(__DIR__ . '/proxies-sessions-test/data/expected-tracy-dump-read')), preg_replace('/#\w+/', '', $runOutput)); } diff --git a/tests/KdybyTests/Doctrine/config/proxiesSessionAutoloading.neon b/tests/KdybyTests/Doctrine/config/proxiesSessionAutoloading.neon index f7e75f57..a91c40be 100644 --- a/tests/KdybyTests/Doctrine/config/proxiesSessionAutoloading.neon +++ b/tests/KdybyTests/Doctrine/config/proxiesSessionAutoloading.neon @@ -1,6 +1,3 @@ -kdyby.console: - disabled: true - kdyby.doctrine: driver: pdo_sqlite path: %tempDir%/db.sqlite diff --git a/tests/KdybyTests/Doctrine/proxies-sessions-test/data/expected-tracy-dump-read b/tests/KdybyTests/Doctrine/proxies-sessions-test/data/expected-tracy-dump-read new file mode 100644 index 00000000..a00acee1 --- /dev/null +++ b/tests/KdybyTests/Doctrine/proxies-sessions-test/data/expected-tracy-dump-read @@ -0,0 +1,6 @@ +Kdyby\GeneratedProxy\__CG__\KdybyTests\Doctrine\CmsOrder #16 + __initializer__: null + __cloner__: null + __isInitialized__: true + id: 1 + status: 'new' \ No newline at end of file diff --git a/tests/KdybyTests/Doctrine/proxies-sessions-test/data/expected-tracy-dump-store b/tests/KdybyTests/Doctrine/proxies-sessions-test/data/expected-tracy-dump-store new file mode 100644 index 00000000..3f32c311 --- /dev/null +++ b/tests/KdybyTests/Doctrine/proxies-sessions-test/data/expected-tracy-dump-store @@ -0,0 +1,6 @@ +Kdyby\GeneratedProxy\__CG__\KdybyTests\Doctrine\CmsOrder #117 + __initializer__: null + __cloner__: null + __isInitialized__: true + id: 1 + status: 'new' \ No newline at end of file diff --git a/tests/KdybyTests/nette-reset.neon b/tests/KdybyTests/nette-reset.neon index 725e12bc..06ab6e23 100644 --- a/tests/KdybyTests/nette-reset.neon +++ b/tests/KdybyTests/nette-reset.neon @@ -3,7 +3,7 @@ php: extensions: - kdyby.console: Kdyby\Console\DI\ConsoleExtension + console: Contributte\Console\DI\ConsoleExtension(%consoleMode%) kdyby.annotations: Kdyby\Annotations\DI\AnnotationsExtension kdyby.doctrine: Kdyby\Doctrine\DI\OrmExtension @@ -15,8 +15,6 @@ kdyby.doctrine: hydrationCache: array -kdyby.console: - url: http://www.kdyby.org/ http: