diff --git a/cli-config.php b/cli-config.php new file mode 100644 index 0000000..b555030 --- /dev/null +++ b/cli-config.php @@ -0,0 +1,9 @@ + new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper( + $container->get('doctrine.entity_manager.orm_default') + ), +]); \ No newline at end of file diff --git a/composer.json b/composer.json index 194a642..9c9da34 100644 --- a/composer.json +++ b/composer.json @@ -7,8 +7,11 @@ "config": { "sort-packages": true }, + "minimum-stability": "dev", + "prefer-stable": true, "require": { "php": "^7.1", + "dasprid/container-interop-doctrine": "^1.0", "imagine/imagine": "^0.7.1", "roave/security-advisories": "dev-master", "symfony/yaml": "*", diff --git a/composer.lock b/composer.lock index d01c8a5..8ae0d96 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "1f20b08976c04bb5ad210675c9abd33e", + "content-hash": "0d2243f5ed579595868f13b7ebc30f7f", "packages": [ { "name": "container-interop/container-interop", @@ -37,6 +37,655 @@ "homepage": "https://github.com/container-interop/container-interop", "time": "2017-02-14T19:40:03+00:00" }, + { + "name": "dasprid/container-interop-doctrine", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/DASPRiD/container-interop-doctrine.git", + "reference": "a4833d25dcfa42165c4ddec0c7062528206eeadc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/DASPRiD/container-interop-doctrine/zipball/a4833d25dcfa42165c4ddec0c7062528206eeadc", + "reference": "a4833d25dcfa42165c4ddec0c7062528206eeadc", + "shasum": "" + }, + "require": { + "doctrine/common": "^2.6", + "doctrine/dbal": "^2.5", + "doctrine/orm": "^2.5", + "php": "^5.5|^7.0", + "psr/container": "^1.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8", + "squizlabs/php_codesniffer": "^2.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "ContainerInteropDoctrine\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "description": "Doctrine factories for container-interop", + "homepage": "https://github.com/DASPRiD/container-interop-doctrine", + "time": "2017-06-30T14:14:39+00:00" + }, + { + "name": "doctrine/annotations", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "5beebb01b025c94e93686b7a0ed3edae81fe3e7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/5beebb01b025c94e93686b7a0ed3edae81fe3e7f", + "reference": "5beebb01b025c94e93686b7a0ed3edae81fe3e7f", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "php": "^7.1" + }, + "require-dev": { + "doctrine/cache": "1.*", + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "time": "2017-07-22T10:58:02+00:00" + }, + { + "name": "doctrine/cache", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/cache.git", + "reference": "53d9518ffeb019c51d542ff60cb578f076d3ff16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/cache/zipball/53d9518ffeb019c51d542ff60cb578f076d3ff16", + "reference": "53d9518ffeb019c51d542ff60cb578f076d3ff16", + "shasum": "" + }, + "require": { + "php": "~7.1" + }, + "conflict": { + "doctrine/common": ">2.2,<2.4" + }, + "require-dev": { + "alcaeus/mongo-php-adapter": "^1.1", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Caching library offering an object-oriented API for many cache backends", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "cache", + "caching" + ], + "time": "2017-07-22T13:00:15+00:00" + }, + { + "name": "doctrine/collections", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/collections.git", + "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/collections/zipball/a01ee38fcd999f34d9bfbcee59dbda5105449cbf", + "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "doctrine/coding-standard": "~0.1@dev", + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Collections\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Collections Abstraction library", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "array", + "collections", + "iterator" + ], + "time": "2017-07-22T10:37:32+00:00" + }, + { + "name": "doctrine/common", + "version": "v2.8.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/common.git", + "reference": "ed349f953d443963c590b008b37b864b8a3c4b21" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/common/zipball/ed349f953d443963c590b008b37b864b8a3c4b21", + "reference": "ed349f953d443963c590b008b37b864b8a3c4b21", + "shasum": "" + }, + "require": { + "doctrine/annotations": "1.*", + "doctrine/cache": "1.*", + "doctrine/collections": "1.*", + "doctrine/inflector": "1.*", + "doctrine/lexer": "1.*", + "php": "~7.1" + }, + "require-dev": { + "phpunit/phpunit": "^5.7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common Library for Doctrine projects", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "annotations", + "collections", + "eventmanager", + "persistence", + "spl" + ], + "time": "2017-07-22T09:01:43+00:00" + }, + { + "name": "doctrine/dbal", + "version": "v2.6.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/dbal.git", + "reference": "1a086f853425b1f5349775ce57e45a772d2d2ba5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/1a086f853425b1f5349775ce57e45a772d2d2ba5", + "reference": "1a086f853425b1f5349775ce57e45a772d2d2ba5", + "shasum": "" + }, + "require": { + "doctrine/common": "^2.7.1", + "ext-pdo": "*", + "php": "^7.1" + }, + "require-dev": { + "phpunit/phpunit": "^5.4.6", + "phpunit/phpunit-mock-objects": "!=3.2.4,!=3.2.5", + "symfony/console": "2.*||^3.0" + }, + "suggest": { + "symfony/console": "For helpful console commands such as SQL execution and import of files." + }, + "bin": [ + "bin/doctrine-dbal" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\DBAL\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Database Abstraction Layer", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "dbal", + "persistence", + "queryobject" + ], + "time": "2017-07-28T10:40:18+00:00" + }, + { + "name": "doctrine/inflector", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/e11d84c6e018beedd929cff5220969a3c6d1d462", + "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462", + "shasum": "" + }, + "require": { + "php": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Common String Manipulations with regard to casing and singular/plural rules.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "inflection", + "pluralize", + "singularize", + "string" + ], + "time": "2017-07-22T12:18:28+00:00" + }, + { + "name": "doctrine/instantiator", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2017-07-22T11:58:36+00:00" + }, + { + "name": "doctrine/lexer", + "version": "v1.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", + "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\Lexer\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "lexer", + "parser" + ], + "time": "2014-09-09T13:34:57+00:00" + }, + { + "name": "doctrine/orm", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/doctrine/doctrine2.git", + "reference": "a0c0d3bf2a7f49020ad7e54d7d3319a251574230" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/a0c0d3bf2a7f49020ad7e54d7d3319a251574230", + "reference": "a0c0d3bf2a7f49020ad7e54d7d3319a251574230", + "shasum": "" + }, + "require": { + "doctrine/annotations": "~1.4", + "doctrine/cache": "~1.6", + "doctrine/collections": "^1.4", + "doctrine/common": "^2.7.1", + "doctrine/dbal": ">=2.5-dev,<2.7-dev", + "doctrine/instantiator": "~1.1", + "ext-pdo": "*", + "php": "^7.1", + "symfony/console": "~3.0|~4.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0", + "symfony/yaml": "~3.0|~4.0" + }, + "suggest": { + "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + }, + "bin": [ + "bin/doctrine" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.6.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\ORM\\": "lib/Doctrine/ORM" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Object-Relational-Mapper for PHP", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database", + "orm" + ], + "time": "2017-08-11 20:29:45" + }, { "name": "fig/http-message-util", "version": "1.1.2", @@ -339,6 +988,53 @@ ], "time": "2016-08-06T14:39:51+00:00" }, + { + "name": "psr/log", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "time": "2016-10-10T12:19:37+00:00" + }, { "name": "roave/security-advisories", "version": "dev-master", @@ -476,6 +1172,190 @@ "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", "time": "2017-08-08T18:44:50+00:00" }, + { + "name": "symfony/console", + "version": "v3.3.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "b0878233cb5c4391347e5495089c7af11b8e6201" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/b0878233cb5c4391347e5495089c7af11b8e6201", + "reference": "b0878233cb5c4391347e5495089c7af11b8e6201", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "symfony/debug": "~2.8|~3.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/dependency-injection": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~3.3", + "symfony/dependency-injection": "~3.3", + "symfony/event-dispatcher": "~2.8|~3.0", + "symfony/filesystem": "~2.8|~3.0", + "symfony/http-kernel": "~2.8|~3.0", + "symfony/process": "~2.8|~3.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/filesystem": "", + "symfony/process": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Console Component", + "homepage": "https://symfony.com", + "time": "2017-07-29T21:27:59+00:00" + }, + { + "name": "symfony/debug", + "version": "v3.3.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug.git", + "reference": "7c13ae8ce1e2adbbd574fc39de7be498e1284e13" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug/zipball/7c13ae8ce1e2adbbd574fc39de7be498e1284e13", + "reference": "7c13ae8ce1e2adbbd574fc39de7be498e1284e13", + "shasum": "" + }, + "require": { + "php": ">=5.5.9", + "psr/log": "~1.0" + }, + "conflict": { + "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" + }, + "require-dev": { + "symfony/http-kernel": "~2.8|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Debug\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Debug Component", + "homepage": "https://symfony.com", + "time": "2017-07-28T15:27:31+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "f29dca382a6485c3cbe6379f0c61230167681937" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/f29dca382a6485c3cbe6379f0c61230167681937", + "reference": "f29dca382a6485c3cbe6379f0c61230167681937", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "time": "2017-06-09T14:24:12+00:00" + }, { "name": "symfony/yaml", "version": "v3.3.6", @@ -1241,60 +2121,6 @@ } ], "packages-dev": [ - { - "name": "doctrine/instantiator", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "shasum": "" - }, - "require": { - "php": "^7.1" - }, - "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" - } - ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" - ], - "time": "2017-07-22T11:58:36+00:00" - }, { "name": "filp/whoops", "version": "2.1.10", @@ -2102,53 +2928,6 @@ ], "time": "2017-08-03T14:08:16+00:00" }, - { - "name": "psr/log", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "Psr/Log/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", - "keywords": [ - "log", - "psr", - "psr-3" - ], - "time": "2016-10-10T12:19:37+00:00" - }, { "name": "sebastian/code-unit-reverse-lookup", "version": "1.0.1", @@ -2927,11 +3706,11 @@ } ], "aliases": [], - "minimum-stability": "stable", + "minimum-stability": "dev", "stability-flags": { "roave/security-advisories": 20 }, - "prefer-stable": false, + "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^7.1" diff --git a/config/autoload/doctrine.global.php b/config/autoload/doctrine.global.php new file mode 100644 index 0000000..e29ecfe --- /dev/null +++ b/config/autoload/doctrine.global.php @@ -0,0 +1,68 @@ + [ + 'driver' => [ + 'orm_default' => [ + 'class' => \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain::class, + 'drivers' => [ + 'App\Entity' => 'my_entity', + ], + ], + 'my_entity' => [ + 'class' => \Doctrine\ORM\Mapping\Driver\AnnotationDriver::class, + 'cache' => 'array', + 'paths' => __DIR__ . '/../../src/App/Entity', + ], + ], + 'configuration' => [ + 'orm_default' => [ +// 'datetime_functions' => [ +// 'date' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'time' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'timestamp' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'convert_tz' => Oro\ORM\Query\AST\Functions\DateTime\ConvertTz::class, +// ], +// 'numeric_functions' => [ +// 'timestampdiff' => Oro\ORM\Query\AST\Functions\Numeric\TimestampDiff::class, +// 'dayofyear' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'dayofmonth' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'dayofweek' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'week' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'day' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'hour' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'minute' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'month' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'quarter' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'second' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'year' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'sign' => Oro\ORM\Query\AST\Functions\Numeric\Sign::class, +// 'pow' => Oro\ORM\Query\AST\Functions\Numeric\Pow::class, +// ], +// 'string_functions' => [ +// 'md5' => Oro\ORM\Query\AST\Functions\SimpleFunction::class, +// 'group_concat' => Oro\ORM\Query\AST\Functions\String\GroupConcat::class, +// 'cast' => Oro\ORM\Query\AST\Functions\Cast::class, +// 'concat_ws' => Oro\ORM\Query\AST\Functions\String\ConcatWs::class +// ] +// 'filters' => [ +// 'soft-deleteable' => Gedmo\SoftDeleteable\Filter\SoftDeleteableFilter::class, +// ], + ], + ], + 'event_manager' => [ + 'orm_default' => [ + 'subscribers' => [ + // Gedmo\Timestampable\TimestampableListener::class, + // 'Gedmo\Tree\TreeListener', + // 'Gedmo\SoftDeleteable\SoftDeleteableListener', + // 'Gedmo\Translatable\TranslatableListener', + // 'Gedmo\Blameable\BlameableListener', + // 'Gedmo\Loggable\LoggableListener', + // 'Gedmo\Sortable\SortableListener', + // 'Gedmo\Sluggable\SluggableListener', + ], + ], + ], + ], +]; diff --git a/config/autoload/doctrine.local.dist.php b/config/autoload/doctrine.local.dist.php new file mode 100644 index 0000000..d21cb8b --- /dev/null +++ b/config/autoload/doctrine.local.dist.php @@ -0,0 +1,14 @@ + [ + 'connection' => [ + 'orm_default' => [ + 'params' => [ + 'url' => 'sqlite:///data/gallery.db', + 'charset' => 'UTF8', + ], + ], + ], + ], +]; diff --git a/config/routes.php b/config/routes.php index 6e6807d..192d3ae 100644 --- a/config/routes.php +++ b/config/routes.php @@ -28,5 +28,4 @@ $app->get('/', App\Action\HomePageAction::class, 'home'); $app->get('/api/galleries', App\Action\ListGalleriesAction::class, 'api.galleries'); -$app->get('/api/gallery/{slug}', App\Action\GetGalleryImagesAction::class, 'api.gallery'); $app->get('/image/{slug}/{image}[/{thumb}]', App\Action\GetImageAction::class, 'download.image'); diff --git a/src/App/Action/GetGalleryImagesAction.php b/src/App/Action/GetGalleryImagesAction.php deleted file mode 100644 index a5ca948..0000000 --- a/src/App/Action/GetGalleryImagesAction.php +++ /dev/null @@ -1,25 +0,0 @@ -galleryService = $galleryService; - } - - public function process(ServerRequestInterface $request, DelegateInterface $delegate) - { - $slug = $request->getAttribute('slug', false); - return new JsonCorsResponse($this->galleryService->getGallery($slug)); - } -} diff --git a/src/App/Action/GetGalleryImagesFactory.php b/src/App/Action/GetGalleryImagesFactory.php deleted file mode 100644 index 818f3cf..0000000 --- a/src/App/Action/GetGalleryImagesFactory.php +++ /dev/null @@ -1,15 +0,0 @@ -get(GalleryService::class); - return new GetGalleryImagesAction($galleryService); - } -} diff --git a/src/App/Action/ListGalleriesAction.php b/src/App/Action/ListGalleriesAction.php index 332a14f..3c9c7a6 100644 --- a/src/App/Action/ListGalleriesAction.php +++ b/src/App/Action/ListGalleriesAction.php @@ -19,7 +19,6 @@ class ListGalleriesAction implements ServerMiddlewareInterface public function process(ServerRequestInterface $request, DelegateInterface $delegate) { -// return new JsonCorsResponse($this->galleryService->listGalleries(true)); return new JsonCorsResponse($this->galleryService->loadGalleryData(true)); } } diff --git a/src/App/ConfigProvider.php b/src/App/ConfigProvider.php index 1d6ee71..d046489 100644 --- a/src/App/ConfigProvider.php +++ b/src/App/ConfigProvider.php @@ -2,6 +2,8 @@ namespace App; +use ContainerInteropDoctrine\EntityManagerFactory; + /** * The configuration provider for the App module * @@ -34,13 +36,16 @@ class ConfigProvider { return [ 'invokables' => [ - Service\GalleryService::class => Service\GalleryService::class, Action\HomePageAction::class => Action\HomePageAction::class, ], 'factories' => [ + 'doctrine.entity_manager.orm_default' => EntityManagerFactory::class, + 'doctrine.hydrator' => Hydrator\DoctrineObjectFactory::class, + Action\ListGalleriesAction::class => Action\ListGalleriesFactory::class, - Action\GetGalleryImagesAction::class => Action\GetGalleryImagesFactory::class, Action\GetImageAction::class => Action\GetImageFactory::class, + + Service\GalleryService::class => Service\GalleryServiceFactory::class, ], ]; } diff --git a/src/App/Entity/Album.php b/src/App/Entity/Album.php new file mode 100644 index 0000000..76f6fc5 --- /dev/null +++ b/src/App/Entity/Album.php @@ -0,0 +1,20 @@ +id; + } + + /** + * @param mixed $id + * @return Image + */ + public function setId(?int $id): Image + { + $this->id = $id; + return $this; + } + + /** + * @return string + */ + public function getDir(): ?string + { + return $this->dir; + } + + /** + * @param string $dir + * @return Image + */ + public function setDir(?string $dir): Image + { + $this->dir = $dir; + return $this; + } + + /** + * @return string + */ + public function getLabel(): ?string + { + return $this->label; + } + + /** + * @param string $label + * @return Image + */ + public function setLabel(?string $label): Image + { + $this->label = $label; + return $this; + } + + /** + * @return string + */ + public function getPath(): ?string + { + return $this->path; + } + + /** + * @param string $path + * @return Image + */ + public function setPath(?string $path): Image + { + $this->path = $path; + return $this; + } + + /** + * @return int + */ + public function getWidth(): ?int + { + return $this->width; + } + + /** + * @param int $width + * @return Image + */ + public function setWidth(?int $width): Image + { + $this->width = $width; + return $this; + } + + /** + * @return int + */ + public function getHeight(): ?int + { + return $this->height; + } + + /** + * @param int $height + * @return Image + */ + public function setHeight(?int $height): Image + { + $this->height = $height; + return $this; + } + + public function jsonSerialize() + { + return [ + 'dir' => $this->getDir(), + 'label' => $this->getLabel(), + 'path' => $this->getPath(), + 'width' => $this->getWidth(), + 'height' => $this->getHeight(), + ]; + } +} \ No newline at end of file diff --git a/src/App/Hydrator/DoctrineObject.php b/src/App/Hydrator/DoctrineObject.php new file mode 100644 index 0000000..912e5c2 --- /dev/null +++ b/src/App/Hydrator/DoctrineObject.php @@ -0,0 +1,594 @@ +. + */ + +namespace App\Hydrator; + +use DateTime; +use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Common\Util\Inflector; +use InvalidArgumentException; +use RuntimeException; +use Traversable; +use Zend\Stdlib\ArrayUtils; +use Zend\Hydrator\AbstractHydrator; +use Zend\Hydrator\Filter\FilterProviderInterface; + +/** + * This hydrator has been completely refactored for DoctrineModule 0.7.0. It provides an easy and powerful way + * of extracting/hydrator objects in Doctrine, by handling most associations types. + * + * Starting from DoctrineModule 0.8.0, the hydrator can be used multiple times with different objects + * + * @license MIT + * @link http://www.doctrine-project.org/ + * @since 0.7.0 + * @author Michael Gallego + */ +class DoctrineObject extends AbstractHydrator +{ + /** + * @var ObjectManager + */ + protected $objectManager; + + /** + * @var ClassMetadata + */ + protected $metadata; + + /** + * @var bool + */ + protected $byValue = true; + + + /** + * Constructor + * + * @param ObjectManager $objectManager The ObjectManager to use + * @param bool $byValue If set to true, hydrator will always use entity's public API + */ + public function __construct(ObjectManager $objectManager, $byValue = true) + { + parent::__construct(); + + $this->objectManager = $objectManager; + $this->byValue = (bool) $byValue; + } + + /** + * Extract values from an object + * + * @param object $object + * @return array + */ + public function extract($object) + { + $this->prepare($object); + + if ($this->byValue) { + return $this->extractByValue($object); + } + + return $this->extractByReference($object); + } + + /** + * Hydrate $object with the provided $data. + * + * @param array $data + * @param object $object + * @return object + */ + public function hydrate(array $data, $object) + { + $this->prepare($object); + + if ($this->byValue) { + return $this->hydrateByValue($data, $object); + } + + return $this->hydrateByReference($data, $object); + } + + /** + * Prepare the hydrator by adding strategies to every collection valued associations + * + * @param object $object + * @return void + */ + protected function prepare($object) + { + $this->metadata = $this->objectManager->getClassMetadata(get_class($object)); + $this->prepareStrategies(); + } + + /** + * Prepare strategies before the hydrator is used + * + * @throws \InvalidArgumentException + * @return void + */ + protected function prepareStrategies() + { + $associations = $this->metadata->getAssociationNames(); + + foreach ($associations as $association) { + if ($this->metadata->isCollectionValuedAssociation($association)) { + // Add a strategy if the association has none set by user + if (!$this->hasStrategy($association)) { + if ($this->byValue) { + $this->addStrategy($association, new Strategy\AllowRemoveByValue()); + } else { + $this->addStrategy($association, new Strategy\AllowRemoveByReference()); + } + } + + $strategy = $this->getStrategy($association); + + if (!$strategy instanceof Strategy\AbstractCollectionStrategy) { + throw new InvalidArgumentException( + sprintf( + 'Strategies used for collections valued associations must inherit from ' + . 'Strategy\AbstractCollectionStrategy, %s given', + get_class($strategy) + ) + ); + } + + $strategy->setCollectionName($association) + ->setClassMetadata($this->metadata); + } + } + } + + /** + * Extract values from an object using a by-value logic (this means that it uses the entity + * API, in this case, getters) + * + * @param object $object + * @throws RuntimeException + * @return array + */ + protected function extractByValue($object) + { + $fieldNames = array_merge($this->metadata->getFieldNames(), $this->metadata->getAssociationNames()); + $methods = get_class_methods($object); + $filter = $object instanceof FilterProviderInterface + ? $object->getFilter() + : $this->filterComposite; + + $data = []; + foreach ($fieldNames as $fieldName) { + if ($filter && !$filter->filter($fieldName)) { + continue; + } + + $getter = 'get' . Inflector::classify($fieldName); + $isser = 'is' . Inflector::classify($fieldName); + + $dataFieldName = $this->computeExtractFieldName($fieldName); + if (in_array($getter, $methods)) { + $data[$dataFieldName] = $this->extractValue($fieldName, $object->$getter(), $object); + } elseif (in_array($isser, $methods)) { + $data[$dataFieldName] = $this->extractValue($fieldName, $object->$isser(), $object); + } elseif (substr($fieldName, 0, 2) === 'is' + && ctype_upper(substr($fieldName, 2, 1)) + && in_array($fieldName, $methods)) { + $data[$dataFieldName] = $this->extractValue($fieldName, $object->$fieldName(), $object); + } + + // Unknown fields are ignored + } + + return $data; + } + + /** + * Extract values from an object using a by-reference logic (this means that values are + * directly fetched without using the public API of the entity, in this case, getters) + * + * @param object $object + * @return array + */ + protected function extractByReference($object) + { + $fieldNames = array_merge($this->metadata->getFieldNames(), $this->metadata->getAssociationNames()); + $refl = $this->metadata->getReflectionClass(); + $filter = $object instanceof FilterProviderInterface + ? $object->getFilter() + : $this->filterComposite; + + $data = []; + foreach ($fieldNames as $fieldName) { + if ($filter && !$filter->filter($fieldName)) { + continue; + } + $reflProperty = $refl->getProperty($fieldName); + $reflProperty->setAccessible(true); + + $dataFieldName = $this->computeExtractFieldName($fieldName); + $data[$dataFieldName] = $this->extractValue($fieldName, $reflProperty->getValue($object), $object); + } + + return $data; + } + + /** + * Hydrate the object using a by-value logic (this means that it uses the entity API, in this + * case, setters) + * + * @param array $data + * @param object $object + * @throws RuntimeException + * @return object + */ + protected function hydrateByValue(array $data, $object) + { + $tryObject = $this->tryConvertArrayToObject($data, $object); + $metadata = $this->metadata; + + if (is_object($tryObject)) { + $object = $tryObject; + } + + foreach ($data as $field => $value) { + $field = $this->computeHydrateFieldName($field); + $value = $this->handleTypeConversions($value, $metadata->getTypeOfField($field)); + $setter = 'set' . Inflector::classify($field); + + if ($metadata->hasAssociation($field)) { + $target = $metadata->getAssociationTargetClass($field); + + if ($metadata->isSingleValuedAssociation($field)) { + if (! method_exists($object, $setter)) { + continue; + } + + $value = $this->toOne($target, $this->hydrateValue($field, $value, $data)); + + if (null === $value + && !current($metadata->getReflectionClass()->getMethod($setter)->getParameters())->allowsNull() + ) { + continue; + } + + $object->$setter($value); + } elseif ($metadata->isCollectionValuedAssociation($field)) { + $this->toMany($object, $field, $target, $value); + } + } else { + if (! method_exists($object, $setter)) { + continue; + } + + $object->$setter($this->hydrateValue($field, $value, $data)); + } + } + + return $object; + } + + /** + * Hydrate the object using a by-reference logic (this means that values are modified directly without + * using the public API, in this case setters, and hence override any logic that could be done in those + * setters) + * + * @param array $data + * @param object $object + * @return object + */ + protected function hydrateByReference(array $data, $object) + { + $tryObject = $this->tryConvertArrayToObject($data, $object); + $metadata = $this->metadata; + $refl = $metadata->getReflectionClass(); + + if (is_object($tryObject)) { + $object = $tryObject; + } + + foreach ($data as $field => $value) { + $field = $this->computeHydrateFieldName($field); + + // Ignore unknown fields + if (!$refl->hasProperty($field)) { + continue; + } + + $value = $this->handleTypeConversions($value, $metadata->getTypeOfField($field)); + $reflProperty = $refl->getProperty($field); + $reflProperty->setAccessible(true); + + if ($metadata->hasAssociation($field)) { + $target = $metadata->getAssociationTargetClass($field); + + if ($metadata->isSingleValuedAssociation($field)) { + $value = $this->toOne($target, $this->hydrateValue($field, $value, $data)); + $reflProperty->setValue($object, $value); + } elseif ($metadata->isCollectionValuedAssociation($field)) { + $this->toMany($object, $field, $target, $value); + } + } else { + $reflProperty->setValue($object, $this->hydrateValue($field, $value, $data)); + } + } + + return $object; + } + + /** + * This function tries, given an array of data, to convert it to an object if the given array contains + * an identifier for the object. This is useful in a context of updating existing entities, without ugly + * tricks like setting manually the existing id directly into the entity + * + * @param array $data The data that may contain identifiers keys + * @param object $object + * @return object + */ + protected function tryConvertArrayToObject($data, $object) + { + $metadata = $this->metadata; + $identifierNames = $metadata->getIdentifierFieldNames($object); + $identifierValues = []; + + if (empty($identifierNames)) { + return $object; + } + + foreach ($identifierNames as $identifierName) { + if (!isset($data[$identifierName])) { + return $object; + } + + $identifierValues[$identifierName] = $data[$identifierName]; + } + + return $this->find($identifierValues, $metadata->getName()); + } + + /** + * Handle ToOne associations + * + * When $value is an array but is not the $target's identifiers, $value is + * most likely an array of fieldset data. The identifiers will be determined + * and a target instance will be initialized and then hydrated. The hydrated + * target will be returned. + * + * @param string $target + * @param mixed $value + * @return object + */ + protected function toOne($target, $value) + { + $metadata = $this->objectManager->getClassMetadata($target); + + if (is_array($value) && array_keys($value) != $metadata->getIdentifier()) { + // $value is most likely an array of fieldset data + $identifiers = array_intersect_key( + $value, + array_flip($metadata->getIdentifier()) + ); + $object = $this->find($identifiers, $target) ?: new $target; + return $this->hydrate($value, $object); + } + + return $this->find($value, $target); + } + + /** + * Handle ToMany associations. In proper Doctrine design, Collections should not be swapped, so + * collections are always handled by reference. Internally, every collection is handled using specials + * strategies that inherit from AbstractCollectionStrategy class, and that add or remove elements but without + * changing the collection of the object + * + * @param object $object + * @param mixed $collectionName + * @param string $target + * @param mixed $values + * + * @throws \InvalidArgumentException + * + * @return void + */ + protected function toMany($object, $collectionName, $target, $values) + { + $metadata = $this->objectManager->getClassMetadata(ltrim($target, '\\')); + $identifier = $metadata->getIdentifier(); + + if (!is_array($values) && !$values instanceof Traversable) { + $values = (array)$values; + } + + $collection = []; + + // If the collection contains identifiers, fetch the objects from database + foreach ($values as $value) { + if ($value instanceof $target) { + // assumes modifications have already taken place in object + $collection[] = $value; + continue; + } elseif (empty($value)) { + // assumes no id and retrieves new $target + $collection[] = $this->find($value, $target); + continue; + } + + $find = []; + if (is_array($identifier)) { + foreach ($identifier as $field) { + switch (gettype($value)) { + case 'object': + $getter = 'get' . ucfirst($field); + if (method_exists($value, $getter)) { + $find[$field] = $value->$getter(); + } elseif (property_exists($value, $field)) { + $find[$field] = $value->$field; + } + break; + case 'array': + if (array_key_exists($field, $value) && $value[$field] != null) { + $find[$field] = $value[$field]; + unset($value[$field]); // removed identifier from persistable data + } + break; + default: + $find[$field] = $value; + break; + } + } + } + + if (!empty($find) && $found = $this->find($find, $target)) { + $collection[] = (is_array($value)) ? $this->hydrate($value, $found) : $found; + } else { + $collection[] = (is_array($value)) ? $this->hydrate($value, new $target) : new $target; + } + } + + $collection = array_filter( + $collection, + function ($item) { + return null !== $item; + } + ); + + // Set the object so that the strategy can extract the Collection from it + + /** @var \DoctrineModule\Stdlib\Hydrator\Strategy\AbstractCollectionStrategy $collectionStrategy */ + $collectionStrategy = $this->getStrategy($collectionName); + $collectionStrategy->setObject($object); + + // We could directly call hydrate method from the strategy, but if people want to override + // hydrateValue function, they can do it and do their own stuff + $this->hydrateValue($collectionName, $collection, $values); + } + + /** + * Handle various type conversions that should be supported natively by Doctrine (like DateTime) + * + * @param mixed $value + * @param string $typeOfField + * @return DateTime + */ + protected function handleTypeConversions($value, $typeOfField) + { + switch ($typeOfField) { + case 'datetimetz': + case 'datetime': + case 'time': + case 'date': + if ('' === $value) { + return null; + } + + if (is_int($value)) { + $dateTime = new DateTime(); + $dateTime->setTimestamp($value); + $value = $dateTime; + } elseif (is_string($value)) { + $value = new DateTime($value); + } + + break; + default: + } + + return $value; + } + + /** + * Find an object by a given target class and identifier + * + * @param mixed $identifiers + * @param string $targetClass + * + * @return object|null + */ + protected function find($identifiers, $targetClass) + { + if ($identifiers instanceof $targetClass) { + return $identifiers; + } + + if ($this->isNullIdentifier($identifiers)) { + return null; + } + + return $this->objectManager->find($targetClass, $identifiers); + } + + /** + * Verifies if a provided identifier is to be considered null + * + * @param mixed $identifier + * + * @return bool + */ + private function isNullIdentifier($identifier) + { + if (null === $identifier) { + return true; + } + + if ($identifier instanceof Traversable || is_array($identifier)) { + $nonNullIdentifiers = array_filter( + ArrayUtils::iteratorToArray($identifier), + function ($value) { + return null !== $value; + } + ); + + return empty($nonNullIdentifiers); + } + + return false; + } + + /** + * Applies the naming strategy if there is one set + * + * @param string $field + * + * @return string + */ + protected function computeHydrateFieldName($field) + { + if ($this->hasNamingStrategy()) { + $field = $this->getNamingStrategy()->hydrate($field); + } + return $field; + } + + /** + * Applies the naming strategy if there is one set + * + * @param string $field + * + * @return string + */ + protected function computeExtractFieldName($field) + { + if ($this->hasNamingStrategy()) { + $field = $this->getNamingStrategy()->extract($field); + } + return $field; + } +} diff --git a/src/App/Hydrator/DoctrineObjectFactory.php b/src/App/Hydrator/DoctrineObjectFactory.php new file mode 100644 index 0000000..d7d10ea --- /dev/null +++ b/src/App/Hydrator/DoctrineObjectFactory.php @@ -0,0 +1,15 @@ +get('doctrine.entity_manager.orm_default'); + return new DoctrineObject($em); + } +} diff --git a/src/App/Hydrator/Filter/PropertyName.php b/src/App/Hydrator/Filter/PropertyName.php new file mode 100644 index 0000000..daafc86 --- /dev/null +++ b/src/App/Hydrator/Filter/PropertyName.php @@ -0,0 +1,66 @@ +. + */ + +namespace App\Hydrator\Filter; + +use Zend\Hydrator\Filter\FilterInterface; + +/** + * Provides a filter to restrict returned fields by whitelisting or + * blacklisting property names. + * + * @license MIT + * @link http://www.doctrine-project.org/ + * @author Liam O'Boyle + */ +class PropertyName implements FilterInterface +{ + /** + * The propteries to exclude. + * + * @var array + */ + protected $properties = []; + + /** + * Either an exclude or an include. + * + * @var bool + */ + protected $exclude = null; + + /** + * @param [ string | array ] $properties The properties to exclude or include. + * @param bool $exclude If the method should be excluded + */ + public function __construct($properties, $exclude = true) + { + $this->exclude = $exclude; + $this->properties = is_array($properties) + ? $properties + : [$properties]; + } + + public function filter($property) + { + return in_array($property, $this->properties) + ? !$this->exclude + : $this->exclude; + } +} diff --git a/src/App/Hydrator/Strategy/AbstractCollectionStrategy.php b/src/App/Hydrator/Strategy/AbstractCollectionStrategy.php new file mode 100644 index 0000000..37e6738 --- /dev/null +++ b/src/App/Hydrator/Strategy/AbstractCollectionStrategy.php @@ -0,0 +1,190 @@ +. + */ + +namespace App\Hydrator\Strategy; + +use InvalidArgumentException; +use Doctrine\Common\Collections\Collection; +use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Zend\Hydrator\Strategy\StrategyInterface; + +/** + * @license MIT + * @link http://www.doctrine-project.org/ + * @since 0.7.0 + * @author Michael Gallego + */ +abstract class AbstractCollectionStrategy implements StrategyInterface +{ + /** + * @var string + */ + protected $collectionName; + + /** + * @var ClassMetadata + */ + protected $metadata; + + /** + * @var object + */ + protected $object; + + + /** + * Set the name of the collection + * + * @param string $collectionName + * @return AbstractCollectionStrategy + */ + public function setCollectionName($collectionName) + { + $this->collectionName = (string) $collectionName; + return $this; + } + + /** + * Get the name of the collection + * + * @return string + */ + public function getCollectionName() + { + return $this->collectionName; + } + + /** + * Set the class metadata + * + * @param ClassMetadata $classMetadata + * @return AbstractCollectionStrategy + */ + public function setClassMetadata(ClassMetadata $classMetadata) + { + $this->metadata = $classMetadata; + return $this; + } + + /** + * Get the class metadata + * + * @return ClassMetadata + */ + public function getClassMetadata() + { + return $this->metadata; + } + + /** + * Set the object + * + * @param object $object + * + * @throws \InvalidArgumentException + * + * @return AbstractCollectionStrategy + */ + public function setObject($object) + { + if (!is_object($object)) { + throw new InvalidArgumentException( + sprintf('The parameter given to setObject method of %s class is not an object', get_called_class()) + ); + } + + $this->object = $object; + return $this; + } + + /** + * Get the object + * + * @return object + */ + public function getObject() + { + return $this->object; + } + + /** + * {@inheritDoc} + */ + public function extract($value) + { + return $value; + } + + /** + * Return the collection by value (using the public API) + * + * @throws \InvalidArgumentException + * + * @return Collection + */ + protected function getCollectionFromObjectByValue() + { + $object = $this->getObject(); + $getter = 'get' . ucfirst($this->getCollectionName()); + + if (!method_exists($object, $getter)) { + throw new InvalidArgumentException( + sprintf( + 'The getter %s to access collection %s in object %s does not exist', + $getter, + $this->getCollectionName(), + get_class($object) + ) + ); + } + + return $object->$getter(); + } + + /** + * Return the collection by reference (not using the public API) + * + * @return Collection + */ + protected function getCollectionFromObjectByReference() + { + $object = $this->getObject(); + $refl = $this->getClassMetadata()->getReflectionClass(); + $reflProperty = $refl->getProperty($this->getCollectionName()); + + $reflProperty->setAccessible(true); + + return $reflProperty->getValue($object); + } + + + /** + * This method is used internally by array_udiff to check if two objects are equal, according to their + * SPL hash. This is needed because the native array_diff only compare strings + * + * @param object $a + * @param object $b + * + * @return int + */ + protected function compareObjects($a, $b) + { + return strcmp(spl_object_hash($a), spl_object_hash($b)); + } +} diff --git a/src/App/Hydrator/Strategy/AllowRemoveByReference.php b/src/App/Hydrator/Strategy/AllowRemoveByReference.php new file mode 100644 index 0000000..57e4222 --- /dev/null +++ b/src/App/Hydrator/Strategy/AllowRemoveByReference.php @@ -0,0 +1,58 @@ +. + */ + +namespace App\Hydrator\Strategy; + +/** + * When this strategy is used for Collections, if the new collection does not contain elements that are present in + * the original collection, then this strategy remove elements from the original collection. For instance, if the + * collection initially contains elements A and B, and that the new collection contains elements B and C, then the + * final collection will contain elements B and C (while element A will be asked to be removed). + * + * This strategy is by reference, this means it won't use public API to add/remove elements to the collection + * + * @license MIT + * @link http://www.doctrine-project.org/ + * @since 0.7.0 + * @author Michael Gallego + */ +class AllowRemoveByReference extends AbstractCollectionStrategy +{ + /** + * {@inheritDoc} + */ + public function hydrate($value) + { + $collection = $this->getCollectionFromObjectByReference(); + $collectionArray = $collection->toArray(); + + $toAdd = array_udiff($value, $collectionArray, [$this, 'compareObjects']); + $toRemove = array_udiff($collectionArray, $value, [$this, 'compareObjects']); + + foreach ($toAdd as $element) { + $collection->add($element); + } + + foreach ($toRemove as $element) { + $collection->removeElement($element); + } + + return $collection; + } +} diff --git a/src/App/Hydrator/Strategy/AllowRemoveByValue.php b/src/App/Hydrator/Strategy/AllowRemoveByValue.php new file mode 100644 index 0000000..2ac85ae --- /dev/null +++ b/src/App/Hydrator/Strategy/AllowRemoveByValue.php @@ -0,0 +1,76 @@ +. + */ + +namespace App\Hydrator\Strategy; + +use Doctrine\Common\Collections\Collection; +use LogicException; +use Doctrine\Common\Collections\ArrayCollection; + +/** + * When this strategy is used for Collections, if the new collection does not contain elements that are present in + * the original collection, then this strategy remove elements from the original collection. For instance, if the + * collection initially contains elements A and B, and that the new collection contains elements B and C, then the + * final collection will contain elements B and C (while element A will be asked to be removed). + * + * This strategy is by value, this means it will use the public API (in this case, adder and remover) + * + * @license MIT + * @link http://www.doctrine-project.org/ + * @since 0.7.0 + * @author Michael Gallego + */ +class AllowRemoveByValue extends AbstractCollectionStrategy +{ + /** + * {@inheritDoc} + */ + public function hydrate($value) + { + // AllowRemove strategy need "adder" and "remover" + $adder = 'add' . ucfirst($this->collectionName); + $remover = 'remove' . ucfirst($this->collectionName); + + if (!method_exists($this->object, $adder) || !method_exists($this->object, $remover)) { + throw new LogicException( + sprintf( + 'AllowRemove strategy for DoctrineModule hydrator requires both %s and %s to be defined in %s + entity domain code, but one or both seem to be missing', + $adder, + $remover, + get_class($this->object) + ) + ); + } + + $collection = $this->getCollectionFromObjectByValue(); + + if ($collection instanceof Collection) { + $collection = $collection->toArray(); + } + + $toAdd = new ArrayCollection(array_udiff($value, $collection, [$this, 'compareObjects'])); + $toRemove = new ArrayCollection(array_udiff($collection, $value, [$this, 'compareObjects'])); + + $this->object->$adder($toAdd); + $this->object->$remover($toRemove); + + return $collection; + } +} diff --git a/src/App/Hydrator/Strategy/DisallowRemoveByReference.php b/src/App/Hydrator/Strategy/DisallowRemoveByReference.php new file mode 100644 index 0000000..e1cbb41 --- /dev/null +++ b/src/App/Hydrator/Strategy/DisallowRemoveByReference.php @@ -0,0 +1,53 @@ +. + */ + +namespace App\Hydrator\Strategy; + +/** + * When this strategy is used for Collections, if the new collection does not contain elements that are present in + * the original collection, then this strategy will not remove those elements. At most, it will add new elements. For + * instance, if the collection initially contains elements A and B, and that the new collection contains elements B + * and C, then the final collection will contain elements A, B and C. + * + * This strategy is by reference, this means it won't use the public API to remove elements + * + * @license MIT + * @link http://www.doctrine-project.org/ + * @since 0.7.0 + * @author Michael Gallego + */ +class DisallowRemoveByReference extends AbstractCollectionStrategy +{ + /** + * {@inheritDoc} + */ + public function hydrate($value) + { + $collection = $this->getCollectionFromObjectByReference(); + $collectionArray = $collection->toArray(); + + $toAdd = array_udiff($value, $collectionArray, [$this, 'compareObjects']); + + foreach ($toAdd as $element) { + $collection->add($element); + } + + return $collection; + } +} diff --git a/src/App/Hydrator/Strategy/DisallowRemoveByValue.php b/src/App/Hydrator/Strategy/DisallowRemoveByValue.php new file mode 100644 index 0000000..6f2bbcc --- /dev/null +++ b/src/App/Hydrator/Strategy/DisallowRemoveByValue.php @@ -0,0 +1,72 @@ +. + */ + +namespace App\Hydrator\Strategy; + +use Doctrine\Common\Collections\Collection; +use LogicException; +use Doctrine\Common\Collections\ArrayCollection; + +/** + * When this strategy is used for Collections, if the new collection does not contain elements that are present in + * the original collection, then this strategy will not remove those elements. At most, it will add new elements. For + * instance, if the collection initially contains elements A and B, and that the new collection contains elements B + * and C, then the final collection will contain elements A, B and C. + * + * This strategy is by value, this means it will use the public API (in this case, remover) + * + * @license MIT + * @link http://www.doctrine-project.org/ + * @since 0.7.0 + * @author Michael Gallego + */ +class DisallowRemoveByValue extends AbstractCollectionStrategy +{ + /** + * {@inheritDoc} + */ + public function hydrate($value) + { + // AllowRemove strategy need "adder" + $adder = 'add' . ucfirst($this->collectionName); + + if (!method_exists($this->object, $adder)) { + throw new LogicException( + sprintf( + 'DisallowRemove strategy for DoctrineModule hydrator requires %s to + be defined in %s entity domain code, but it seems to be missing', + $adder, + get_class($this->object) + ) + ); + } + + $collection = $this->getCollectionFromObjectByValue(); + + if ($collection instanceof Collection) { + $collection = $collection->toArray(); + } + + $toAdd = new ArrayCollection(array_udiff($value, $collection, [$this, 'compareObjects'])); + + $this->object->$adder($toAdd); + + return $collection; + } +} diff --git a/src/App/Service/GalleryService.php b/src/App/Service/GalleryService.php index 7cd66c4..7dd3723 100644 --- a/src/App/Service/GalleryService.php +++ b/src/App/Service/GalleryService.php @@ -4,6 +4,8 @@ namespace App\Service; +use App\Entity\Image; +use Doctrine\ORM\EntityManager; use Imagine\Gd\Imagine; use Imagine\Image\Box; use Imagine\Image\ImageInterface; @@ -18,19 +20,29 @@ class GalleryService const THUMBNAIL_SIZE = 500; protected $contentTypeMap = [ - 'jpg' => 'image/jpeg', + 'jpg' => 'image/jpeg', 'jpeg' => 'image/jpeg', - 'png' => 'image/png', + 'png' => 'image/png', ]; protected $config; + /** + * @var EntityManager + */ + protected $em; + + public function __construct(EntityManager $entityManager) + { + $this->em = $entityManager; + } + public function loadGalleryData($includeHidden = false) { $config = $this->getConfig(); - $slugs = []; + $albums = []; foreach ($config['galleries'] as $id => $data) { if ($includeHidden || $data['public']) { - $slugs[] = [ + $albums[] = [ 'slug' => $id, 'name' => $data['name'], 'coverImage' => isset($data['cover']) @@ -44,7 +56,7 @@ class GalleryService ]; } } - return $slugs; + return $albums; } private function getGalleryDate(string $dir): string @@ -56,73 +68,53 @@ class GalleryService /** * @param string $dir - * @return array + * @return Image[] * @todo implement label for image in some way */ - private function loadGalleryImages(string $dir) + private function loadGalleryImages(string $dir): array { $images = array_map('basename', glob( sprintf(self::IMAGE_BASEDIR . "*.{jpg,jpeg,png}", $dir), GLOB_BRACE )); - return array_map(function ($image) { - return [ - 'label' => '', + $imagine = new Imagine(); + return array_map(function ($image) use ($dir, $imagine) { + $imageEntity = $this->em->getRepository(Image::class)->findOneBy([ + 'dir' => $dir, 'path' => $image, - ]; + ]); + if (null === $imageEntity) { + $imageEntity = new Image(); + $imageEntity->setLabel("") + ->setDir($dir) + ->setPath($image); + $this->processImageSizes($dir, $imageEntity, $imagine); + $this->em->persist($imageEntity); + $this->em->flush(); + } + return $imageEntity; }, $images); } + private function processImageSizes(string $dir, Image $image, Imagine $imagine) + { + $img = $imagine->open(sprintf(self::IMAGE_BASEDIR, $dir) . $image->getPath()); + $imgSize = $img->getSize(); + $image->setWidth($imgSize->getWidth()) + ->setHeight($imgSize->getHeight()); + } + /** * @param string $image - * @return array + * @return Image */ - private function getCoverImage(string $image) + private function getCoverImage(string $image): Image { - return [ - 'label' => '', - 'path' => $image, - ]; - } - - public function listGalleries($includeHidden = false) - { - $config = $this->getConfig(); - $slugs = []; - foreach ($config['galleries'] as $id => $data) { - if ($includeHidden || $data['public']) { - $slugs[] = [ - 'id' => $id, - 'label' => $data['name'], - 'new' => $data['new'], - ]; - } - } - return $slugs; - } - - public function getGallery(string $slug) - { - $galleryList = $this->listGalleries(true); - $slugs = array_map(function ($item) { - return $item['id']; - }, $galleryList); - $config = $this->getConfig(); - $images = []; - - if (in_array($slug, $slugs)) { - $dir = $config['galleries'][$slug]['dir']; - $images = array_map('basename', glob( - sprintf(self::IMAGE_BASEDIR . "*.{jpg,jpeg,png}", $dir), - GLOB_BRACE - )); - } - - return [ - 'name' => $config['galleries'][$slug]['name'], - 'type' => $config['galleries'][$slug]['type'], - 'images' => $images, - ]; + $img = new Image(); + return $img->setLabel("") + ->setPath($image) + ->setWidth(0) + ->setHeight(0); } public function getImage(string $slug, string $image, $size = false): string diff --git a/src/App/Service/GalleryServiceFactory.php b/src/App/Service/GalleryServiceFactory.php new file mode 100644 index 0000000..fb4d395 --- /dev/null +++ b/src/App/Service/GalleryServiceFactory.php @@ -0,0 +1,14 @@ +get('doctrine.entity_manager.orm_default'); + return new GalleryService($galleryService); + } +}