From a5ef2a3b4fec30ccf9fd69f322b1c988a7b8500f Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Tue, 31 Jan 2017 22:06:56 +0200 Subject: [PATCH 01/13] Setup project. Added database scheme & entities --- README.md | 19 + app/AppKernel.php | 1 + app/config/config.yml | 12 +- composer.json | 8 +- composer.lock | 603 +++++++++++++++++- src/AppBundle/Entity/BaseSuperClass.php | 102 +++ src/AppBundle/Entity/User.php | 395 ++++++++++++ src/AppBundle/Entity/UserProfile.php | 81 +++ src/AppBundle/Entity/Wishlist.php | 101 +++ src/AppBundle/Entity/Word.php | 134 ++++ .../Repository/UserProfileRepository.php | 13 + src/AppBundle/Repository/UserRepository.php | 13 + .../Repository/WishlistRepository.php | 13 + src/AppBundle/Repository/WordRepository.php | 11 + 14 files changed, 1469 insertions(+), 37 deletions(-) create mode 100644 src/AppBundle/Entity/BaseSuperClass.php create mode 100644 src/AppBundle/Entity/User.php create mode 100644 src/AppBundle/Entity/UserProfile.php create mode 100644 src/AppBundle/Entity/Wishlist.php create mode 100644 src/AppBundle/Entity/Word.php create mode 100644 src/AppBundle/Repository/UserProfileRepository.php create mode 100644 src/AppBundle/Repository/UserRepository.php create mode 100644 src/AppBundle/Repository/WishlistRepository.php create mode 100644 src/AppBundle/Repository/WordRepository.php diff --git a/README.md b/README.md index 20ae887..98ecebb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,22 @@ +Geekhub PHP HomeWork#14: Symfony Vocabulary Application - Translations += + +####EER Diagram: + +https://docs.google.com/drawings/d/1gXIQH6vCcoeqFa2ess2fpVgOADpIkfmPAOGW7HD2LCs/edit?usp=sharing + +####Setup: + +Note: Before continue, install Node.js. + +```bash +$ git clone -b hw14-andrey-lukashenko https://github.com/AndreyLuka/geekhub-php-vocabulary.git +$ cd geekhub-php-vocabulary +$ composer install +$ php bin/console doctrine:fixtures:load +``` + + Homework 14: Vocabulary ========== diff --git a/app/AppKernel.php b/app/AppKernel.php index 3789b32..c9be0bb 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -16,6 +16,7 @@ public function registerBundles() new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new AppBundle\AppBundle(), + new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(), ]; if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { diff --git a/app/config/config.yml b/app/config/config.yml index cfb0391..64be8f0 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -48,7 +48,10 @@ doctrine: dbname: "%database_name%" user: "%database_user%" password: "%database_password%" - charset: UTF8 + charset: utf8mb4 + default_table_options: + charset: utf8mb4 + collate: utf8mb4_unicode_ci # if using pdo_sqlite as your database driver: # 1. add the path in parameters.yml # e.g. database_path: "%kernel.root_dir%/../var/data/data.sqlite" @@ -68,3 +71,10 @@ swiftmailer: username: "%mailer_user%" password: "%mailer_password%" spool: { type: memory } + +# StofDoctrineExtensionsBundle Configuration +stof_doctrine_extensions: + default_locale: en_US + orm: + default: + timestampable: true diff --git a/composer.json b/composer.json index 5017df0..b4d2254 100644 --- a/composer.json +++ b/composer.json @@ -27,11 +27,15 @@ "symfony/polyfill-apcu": "^1.0", "sensio/distribution-bundle": "^5.0", "sensio/framework-extra-bundle": "^3.0.2", - "incenteev/composer-parameter-handler": "^2.0" + "incenteev/composer-parameter-handler": "^2.0", + "stof/doctrine-extensions-bundle": "^1.2", + "knplabs/knp-paginator-bundle": "^2.5" }, "require-dev": { "sensio/generator-bundle": "^3.0", - "symfony/phpunit-bridge": "^3.0" + "symfony/phpunit-bridge": "^3.0", + "nelmio/alice": "2.1.4", + "doctrine/doctrine-fixtures-bundle": "^2.3" }, "scripts": { "symfony-scripts": [ diff --git a/composer.lock b/composer.lock index 7dc1557..6df39a8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,49 @@ "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": "c1d710a5e4a8bb5e5c86aa1032601ecf", + "hash": "23ccd7418d03cdee7337d5ec74aa786f", + "content-hash": "89cd2ff4948e7648e6f33d8d75c319b9", "packages": [ + { + "name": "behat/transliterator", + "version": "v1.1.0", + "source": { + "type": "git", + "url": "https://github.com/Behat/Transliterator.git", + "reference": "868e05be3a9f25ba6424c2dd4849567f50715003" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Behat/Transliterator/zipball/868e05be3a9f25ba6424c2dd4849567f50715003", + "reference": "868e05be3a9f25ba6424c2dd4849567f50715003", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "psr-0": { + "Behat\\Transliterator": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Artistic-1.0" + ], + "description": "String transliterator", + "keywords": [ + "i18n", + "slug", + "transliterator" + ], + "time": "2015-09-28 16:26:35" + }, { "name": "doctrine/annotations", "version": "v1.3.1", @@ -72,7 +113,7 @@ "docblock", "parser" ], - "time": "2016-12-30T15:59:45+00:00" + "time": "2016-12-30 15:59:45" }, { "name": "doctrine/cache", @@ -142,7 +183,7 @@ "cache", "caching" ], - "time": "2016-10-29T11:16:17+00:00" + "time": "2016-10-29 11:16:17" }, { "name": "doctrine/collections", @@ -209,7 +250,7 @@ "collections", "iterator" ], - "time": "2017-01-03T10:49:41+00:00" + "time": "2017-01-03 10:49:41" }, { "name": "doctrine/common", @@ -282,7 +323,7 @@ "persistence", "spl" ], - "time": "2017-01-13T14:02:13+00:00" + "time": "2017-01-13 14:02:13" }, { "name": "doctrine/dbal", @@ -353,7 +394,7 @@ "persistence", "queryobject" ], - "time": "2017-01-23T23:17:10+00:00" + "time": "2017-01-23 23:17:10" }, { "name": "doctrine/doctrine-bundle", @@ -434,7 +475,7 @@ "orm", "persistence" ], - "time": "2017-01-16T12:01:26+00:00" + "time": "2017-01-16 12:01:26" }, { "name": "doctrine/doctrine-cache-bundle", @@ -522,7 +563,7 @@ "cache", "caching" ], - "time": "2016-01-26T17:28:51+00:00" + "time": "2016-01-26 17:28:51" }, { "name": "doctrine/inflector", @@ -589,7 +630,7 @@ "singularize", "string" ], - "time": "2015-11-06T14:35:42+00:00" + "time": "2015-11-06 14:35:42" }, { "name": "doctrine/instantiator", @@ -643,7 +684,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2015-06-14 21:17:01" }, { "name": "doctrine/lexer", @@ -697,7 +738,7 @@ "lexer", "parser" ], - "time": "2014-09-09T13:34:57+00:00" + "time": "2014-09-09 13:34:57" }, { "name": "doctrine/orm", @@ -773,7 +814,86 @@ "database", "orm" ], - "time": "2016-12-18T15:42:34+00:00" + "time": "2016-12-18 15:42:34" + }, + { + "name": "gedmo/doctrine-extensions", + "version": "v2.4.26", + "source": { + "type": "git", + "url": "https://github.com/Atlantic18/DoctrineExtensions.git", + "reference": "983dd85d6860f87fb7dffd0d9f7ad1462e20a09d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Atlantic18/DoctrineExtensions/zipball/983dd85d6860f87fb7dffd0d9f7ad1462e20a09d", + "reference": "983dd85d6860f87fb7dffd0d9f7ad1462e20a09d", + "shasum": "" + }, + "require": { + "behat/transliterator": "~1.0", + "doctrine/common": "~2.4", + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/common": ">=2.5.0", + "doctrine/mongodb-odm": ">=1.0.2", + "doctrine/orm": ">=2.5.0", + "phpunit/phpunit": "~4.4", + "phpunit/phpunit-mock-objects": "~2.3", + "symfony/yaml": "~2.6" + }, + "suggest": { + "doctrine/mongodb-odm": "to use the extensions with the MongoDB ODM", + "doctrine/orm": "to use the extensions with the ORM" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4.x-dev" + } + }, + "autoload": { + "psr-0": { + "Gedmo\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David Buchmann", + "email": "david@liip.ch" + }, + { + "name": "Gediminas Morkevicius", + "email": "gediminas.morkevicius@gmail.com" + }, + { + "name": "Gustavo Falco", + "email": "comfortablynumb84@gmail.com" + } + ], + "description": "Doctrine2 behavioral extensions", + "homepage": "http://gediminasm.org/", + "keywords": [ + "Blameable", + "behaviors", + "doctrine2", + "extensions", + "gedmo", + "loggable", + "nestedset", + "sluggable", + "sortable", + "timestampable", + "translatable", + "tree", + "uploadable" + ], + "time": "2016-12-21 13:46:54" }, { "name": "incenteev/composer-parameter-handler", @@ -824,7 +944,7 @@ "keywords": [ "parameters management" ], - "time": "2015-11-10T17:04:01+00:00" + "time": "2015-11-10 17:04:01" }, { "name": "jdorn/sql-formatter", @@ -874,7 +994,139 @@ "highlight", "sql" ], - "time": "2014-01-12T16:20:24+00:00" + "time": "2014-01-12 16:20:24" + }, + { + "name": "knplabs/knp-components", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/KnpLabs/knp-components.git", + "reference": "f98bcc6d348fbe863a224b468e11fb5e91e28f2a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/KnpLabs/knp-components/zipball/f98bcc6d348fbe863a224b468e11fb5e91e28f2a", + "reference": "f98bcc6d348fbe863a224b468e11fb5e91e28f2a", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "doctrine/mongodb-odm": "~1.0@beta", + "doctrine/orm": "~2.4", + "doctrine/phpcr-odm": "~1.2", + "jackalope/jackalope-doctrine-dbal": "~1.2", + "phpunit/phpunit": "~4.2", + "ruflin/elastica": "~1.0", + "symfony/event-dispatcher": "~2.5" + }, + "suggest": { + "doctrine/common": "to allow usage pagination with Doctrine ArrayCollection", + "doctrine/mongodb-odm": "to allow usage pagination with Doctrine ODM MongoDB", + "doctrine/orm": "to allow usage pagination with Doctrine ORM", + "doctrine/phpcr-odm": "to allow usage pagination with Doctrine ODM PHPCR", + "propel/propel1": "to allow usage pagination with Propel ORM", + "ruflin/Elastica": "to allow usage pagination with ElasticSearch Client", + "solarium/solarium": "to allow usage pagination with Solarium Client" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Knp\\Component": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KnpLabs Team", + "homepage": "http://knplabs.com" + }, + { + "name": "Symfony Community", + "homepage": "http://github.com/KnpLabs/knp-components/contributors" + } + ], + "description": "Knplabs component library", + "homepage": "http://github.com/KnpLabs/knp-components", + "keywords": [ + "components", + "knp", + "knplabs", + "pager", + "paginator" + ], + "time": "2016-12-06 18:10:24" + }, + { + "name": "knplabs/knp-paginator-bundle", + "version": "2.5.3", + "source": { + "type": "git", + "url": "https://github.com/KnpLabs/KnpPaginatorBundle.git", + "reference": "c988761005504007c6c87d6a557641281194a0e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/KnpLabs/KnpPaginatorBundle/zipball/c988761005504007c6c87d6a557641281194a0e5", + "reference": "c988761005504007c6c87d6a557641281194a0e5", + "shasum": "" + }, + "require": { + "knplabs/knp-components": "~1.2", + "php": ">=5.3.3", + "symfony/framework-bundle": "~2.3|~3.0", + "twig/twig": "~1.12|~2" + }, + "require-dev": { + "symfony/expression-language": "~2.4|~3.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.5.x-dev" + } + }, + "autoload": { + "psr-4": { + "Knp\\Bundle\\PaginatorBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KnpLabs Team", + "homepage": "http://knplabs.com" + }, + { + "name": "Symfony2 Community", + "homepage": "http://github.com/KnpLabs/KnpPaginatorBundle/contributors" + } + ], + "description": "Paginator bundle for Symfony2 to automate pagination and simplify sorting and other features", + "homepage": "http://github.com/KnpLabs/KnpPaginatorBundle", + "keywords": [ + "Symfony2", + "bundle", + "knp", + "knplabs", + "pager", + "pagination", + "paginator" + ], + "time": "2016-04-20 11:40:30" }, { "name": "monolog/monolog", @@ -952,7 +1204,7 @@ "logging", "psr-3" ], - "time": "2016-11-26T00:15:39+00:00" + "time": "2016-11-26 00:15:39" }, { "name": "paragonie/random_compat", @@ -1000,7 +1252,7 @@ "pseudorandom", "random" ], - "time": "2016-11-07T23:38:38+00:00" + "time": "2016-11-07 23:38:38" }, { "name": "psr/cache", @@ -1046,7 +1298,7 @@ "psr", "psr-6" ], - "time": "2016-08-06T20:24:11+00:00" + "time": "2016-08-06 20:24:11" }, { "name": "psr/log", @@ -1093,7 +1345,7 @@ "psr", "psr-3" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2016-10-10 12:19:37" }, { "name": "sensio/distribution-bundle", @@ -1145,7 +1397,7 @@ "configuration", "distribution" ], - "time": "2017-01-10T14:58:45+00:00" + "time": "2017-01-10 14:58:45" }, { "name": "sensio/framework-extra-bundle", @@ -1213,7 +1465,7 @@ "annotations", "controllers" ], - "time": "2017-01-10T19:42:56+00:00" + "time": "2017-01-10 19:42:56" }, { "name": "sensiolabs/security-checker", @@ -1257,7 +1509,68 @@ } ], "description": "A security checker for your composer.lock", - "time": "2016-09-23T18:09:57+00:00" + "time": "2016-09-23 18:09:57" + }, + { + "name": "stof/doctrine-extensions-bundle", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/stof/StofDoctrineExtensionsBundle.git", + "reference": "4e7499d25dc5d0862da09fa8e336164948a29a25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stof/StofDoctrineExtensionsBundle/zipball/4e7499d25dc5d0862da09fa8e336164948a29a25", + "reference": "4e7499d25dc5d0862da09fa8e336164948a29a25", + "shasum": "" + }, + "require": { + "gedmo/doctrine-extensions": "^2.3.1", + "php": ">=5.3.2", + "symfony/framework-bundle": "~2.1|~3.0" + }, + "suggest": { + "doctrine/doctrine-bundle": "to use the ORM extensions", + "doctrine/mongodb-odm-bundle": "to use the MongoDB ODM extensions" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Stof\\DoctrineExtensionsBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christophe Coevoet", + "email": "stof@notk.org" + } + ], + "description": "Integration of the gedmo/doctrine-extensions with Symfony2", + "homepage": "https://github.com/stof/StofDoctrineExtensionsBundle", + "keywords": [ + "behaviors", + "doctrine2", + "extensions", + "gedmo", + "loggable", + "nestedset", + "sluggable", + "sortable", + "timestampable", + "translatable", + "tree" + ], + "time": "2016-01-26 23:58:32" }, { "name": "swiftmailer/swiftmailer", @@ -1311,7 +1624,7 @@ "mail", "mailer" ], - "time": "2016-12-29T10:02:40+00:00" + "time": "2016-12-29 10:02:40" }, { "name": "symfony/monolog-bundle", @@ -1371,7 +1684,7 @@ "log", "logging" ], - "time": "2017-01-10T20:01:51+00:00" + "time": "2017-01-10 20:01:51" }, { "name": "symfony/polyfill-apcu", @@ -1424,7 +1737,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-intl-icu", @@ -1482,7 +1795,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-mbstring", @@ -1541,7 +1854,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php56", @@ -1597,7 +1910,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php70", @@ -1656,7 +1969,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-util", @@ -1708,7 +2021,7 @@ "polyfill", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/swiftmailer-bundle", @@ -1767,7 +2080,7 @@ ], "description": "Symfony SwiftmailerBundle", "homepage": "http://symfony.com", - "time": "2016-12-20T04:44:33+00:00" + "time": "2016-12-20 04:44:33" }, { "name": "symfony/symfony", @@ -1909,7 +2222,7 @@ "keywords": [ "framework" ], - "time": "2017-01-12T21:36:55+00:00" + "time": "2017-01-12 21:36:55" }, { "name": "twig/twig", @@ -1971,10 +2284,232 @@ "keywords": [ "templating" ], - "time": "2017-01-11T19:39:01+00:00" + "time": "2017-01-11 19:39:01" } ], "packages-dev": [ + { + "name": "doctrine/data-fixtures", + "version": "v1.2.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/data-fixtures.git", + "reference": "17fa5bfe6ff52e35cb3d9ec37c934a2f4bd1fa2e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/17fa5bfe6ff52e35cb3d9ec37c934a2f4bd1fa2e", + "reference": "17fa5bfe6ff52e35cb3d9ec37c934a2f4bd1fa2e", + "shasum": "" + }, + "require": { + "doctrine/common": "~2.2", + "php": "^5.6 || ^7.0" + }, + "conflict": { + "doctrine/orm": "< 2.4" + }, + "require-dev": { + "doctrine/dbal": "^2.5.4", + "doctrine/orm": "^2.5.4", + "phpunit/phpunit": "^5.4.6" + }, + "suggest": { + "doctrine/mongodb-odm": "For loading MongoDB ODM fixtures", + "doctrine/orm": "For loading ORM fixtures", + "doctrine/phpcr-odm": "For loading PHPCR ODM fixtures" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "psr-0": { + "Doctrine\\Common\\DataFixtures": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + } + ], + "description": "Data Fixtures for all Doctrine Object Managers", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database" + ], + "time": "2016-09-20 10:07:57" + }, + { + "name": "doctrine/doctrine-fixtures-bundle", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/DoctrineFixturesBundle.git", + "reference": "0f1a2f91b349e10f5c343f75ab71d23aace5b029" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/0f1a2f91b349e10f5c343f75ab71d23aace5b029", + "reference": "0f1a2f91b349e10f5c343f75ab71d23aace5b029", + "shasum": "" + }, + "require": { + "doctrine/data-fixtures": "~1.0", + "doctrine/doctrine-bundle": "~1.0", + "php": ">=5.3.2", + "symfony/doctrine-bridge": "~2.3|~3.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Bundle\\FixturesBundle\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + }, + { + "name": "Doctrine Project", + "homepage": "http://www.doctrine-project.org" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "Symfony DoctrineFixturesBundle", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "Fixture", + "persistence" + ], + "time": "2015-11-04 21:23:23" + }, + { + "name": "fzaninotto/faker", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/fzaninotto/Faker.git", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fzaninotto/Faker/zipball/44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "reference": "44f9a286a04b80c76a4e5fb7aad8bb539b920123", + "shasum": "" + }, + "require": { + "php": "^5.3.3|^7.0" + }, + "require-dev": { + "ext-intl": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~1.5" + }, + "type": "library", + "extra": { + "branch-alias": [] + }, + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "time": "2016-04-29 12:21:54" + }, + { + "name": "nelmio/alice", + "version": "2.1.4", + "source": { + "type": "git", + "url": "https://github.com/nelmio/alice.git", + "reference": "c8cb3413ab5d1fa76ee84296dafe356b0c703014" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nelmio/alice/zipball/c8cb3413ab5d1fa76ee84296dafe356b0c703014", + "reference": "c8cb3413ab5d1fa76ee84296dafe356b0c703014", + "shasum": "" + }, + "require": { + "fzaninotto/faker": "~1.0", + "php": ">=5.4", + "symfony/yaml": "~2.0|~3.0" + }, + "require-dev": { + "doctrine/common": "~2.3", + "phpunit/phpunit": "~4.0", + "symfony/property-access": "~2.2|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Nelmio\\Alice\\": "src/Nelmio/Alice" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + }, + { + "name": "Tim Shelburne", + "email": "shelburt02@gmail.com" + } + ], + "description": "Expressive fixtures generator", + "keywords": [ + "Fixture", + "data", + "orm", + "test" + ], + "time": "2016-01-07 14:44:47" + }, { "name": "sensio/generator-bundle", "version": "v3.1.2", @@ -2025,7 +2560,7 @@ } ], "description": "This bundle generates code for you", - "time": "2016-12-05T16:01:19+00:00" + "time": "2016-12-05 16:01:19" }, { "name": "symfony/phpunit-bridge", @@ -2083,7 +2618,7 @@ ], "description": "Symfony PHPUnit Bridge", "homepage": "https://symfony.com", - "time": "2017-01-06T17:19:17+00:00" + "time": "2017-01-06 17:19:17" } ], "aliases": [], diff --git a/src/AppBundle/Entity/BaseSuperClass.php b/src/AppBundle/Entity/BaseSuperClass.php new file mode 100644 index 0000000..4bdaaef --- /dev/null +++ b/src/AppBundle/Entity/BaseSuperClass.php @@ -0,0 +1,102 @@ +id; + } + + /** + * Set dateCreated + * + * @param \DateTime $dateCreated + * + * @return BaseSuperClass + */ + public function setDateCreated($dateCreated) + { + $this->dateCreated = $dateCreated; + + return $this; + } + + /** + * Get dateCreated + * + * @return \DateTime + */ + public function getDateCreated() + { + return $this->dateCreated; + } + + /** + * Set dateUpdated + * + * @param \DateTime $dateUpdated + * + * @return BaseSuperClass + */ + public function setDateUpdated($dateUpdated) + { + $this->dateUpdated = $dateUpdated; + + return $this; + } + + /** + * Get dateUpdated + * + * @return \DateTime + */ + public function getDateUpdated() + { + return $this->dateUpdated; + } +} diff --git a/src/AppBundle/Entity/User.php b/src/AppBundle/Entity/User.php new file mode 100644 index 0000000..601c2fe --- /dev/null +++ b/src/AppBundle/Entity/User.php @@ -0,0 +1,395 @@ +isActive = true; + $this->words = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Set username + * + * @param string $username + * + * @return User + */ + public function setUsername($username) + { + $this->username = $username; + + return $this; + } + + /** + * Get username + * + * @return string + */ + public function getUsername() + { + return $this->username; + } + + /** + * @param string $password + * + * @return User + */ + public function setPlainPassword($password) + { + $this->plainPassword = $password; + + return $this; + } + + /** + * @return string + */ + public function getPlainPassword() + { + return $this->plainPassword; + } + + /** + * Set password + * + * @param string $password + * + * @return User + */ + public function setPassword($password) + { + $this->password = $password; + + return $this; + } + + /** + * Get password + * + * @return string + */ + public function getPassword() + { + return $this->password; + } + + /** + * Set email + * + * @param string $email + * + * @return User + */ + public function setEmail($email) + { + $this->email = $email; + + return $this; + } + + /** + * Get email + * + * @return string + */ + public function getEmail() + { + return $this->email; + } + + /** + * @inheritdoc + */ + public function isAccountNonExpired() + { + return true; + } + + + /** + * @inheritdoc + */ + public function isAccountNonLocked() + { + return true; + } + + /** + * @inheritdoc + */ + public function isCredentialsNonExpired() + { + return true; + } + + /** + * @inheritdoc + */ + public function isEnabled() + { + return $this->isActive; + } + + /** + * @inheritdoc + */ + public function serialize() + { + return serialize(array( + $this->id, + $this->username, + $this->password, + $this->isActive, + )); + } + + /** + * @inheritdoc + */ + public function unserialize($serialized) + { + list ( + $this->id, + $this->username, + $this->password, + $this->isActive, + ) = unserialize($serialized); + } + + /** + * @inheritdoc + */ + public function getSalt() + { + return null; + } + + /** + * @inheritdoc + */ + public function eraseCredentials() + { + $this->setPlainPassword(null); + } + + /** + * Set isActive + * + * @param boolean $isActive + * + * @return User + */ + public function setIsActive($isActive) + { + $this->isActive = $isActive; + + return $this; + } + + /** + * Get isActive + * + * @return boolean + */ + public function getIsActive() + { + return $this->isActive; + } + + /** + * @param array $roles + * @return User + */ + public function setRoles(array $roles) + { + $this->roles = $roles; + + // allows for chaining + return $this; + } + + /** + * @return array + */ + public function getRoles() + { + return $this->roles; + } + + /** + * Set userProfile + * + * @param \AppBundle\Entity\UserProfile $userProfile + * + * @return User + */ + public function setUserProfile(\AppBundle\Entity\UserProfile $userProfile = null) + { + $this->userProfile = $userProfile; + + return $this; + } + + /** + * Get userProfile + * + * @return \AppBundle\Entity\UserProfile + */ + public function getUserProfile() + { + return $this->userProfile; + } + + /** + * Set wishlist + * + * @param \AppBundle\Entity\Wishlist $wishlist + * + * @return User + */ + public function setWishlist(\AppBundle\Entity\Wishlist $wishlist = null) + { + $this->wishlist = $wishlist; + + return $this; + } + + /** + * Get wishlist + * + * @return \AppBundle\Entity\Wishlist + */ + public function getWishlist() + { + return $this->wishlist; + } + + /** + * Add word + * + * @param \AppBundle\Entity\Word $word + * + * @return User + */ + public function addWord(\AppBundle\Entity\Word $word) + { + $this->words[] = $word; + + return $this; + } + + /** + * Remove word + * + * @param \AppBundle\Entity\Word $word + */ + public function removeWord(\AppBundle\Entity\Word $word) + { + $this->words->removeElement($word); + } + + /** + * Get words + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getWords() + { + return $this->words; + } +} diff --git a/src/AppBundle/Entity/UserProfile.php b/src/AppBundle/Entity/UserProfile.php new file mode 100644 index 0000000..a6df60e --- /dev/null +++ b/src/AppBundle/Entity/UserProfile.php @@ -0,0 +1,81 @@ +firstName = $firstName; + + return $this; + } + + /** + * Get firstName + * + * @return string + */ + public function getFirstName() + { + return $this->firstName; + } + + /** + * Set lastName + * + * @param string $lastName + * + * @return UserProfile + */ + public function setLastName($lastName) + { + $this->lastName = $lastName; + + return $this; + } + + /** + * Get lastName + * + * @return string + */ + public function getLastName() + { + return $this->lastName; + } +} diff --git a/src/AppBundle/Entity/Wishlist.php b/src/AppBundle/Entity/Wishlist.php new file mode 100644 index 0000000..8af1706 --- /dev/null +++ b/src/AppBundle/Entity/Wishlist.php @@ -0,0 +1,101 @@ +words = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Set name + * + * @param string $name + * + * @return Wishlist + */ + public function setName($name) + { + $this->name = $name; + + return $this; + } + + /** + * Get name + * + * @return string + */ + public function getName() + { + return $this->name; + } + + /** + * Add word + * + * @param \AppBundle\Entity\Word $word + * + * @return Wishlist + */ + public function addWord(\AppBundle\Entity\Word $word) + { + if (!$this->words->contains($word)) { + $this->words[] = $word; + $word->addWishlist($this); + } + + return $this; + } + + /** + * Remove word + * + * @param \AppBundle\Entity\Word $word + */ + public function removeWord(\AppBundle\Entity\Word $word) + { + $this->words->removeElement($word); + } + + /** + * Get words + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getWords() + { + return $this->words; + } +} diff --git a/src/AppBundle/Entity/Word.php b/src/AppBundle/Entity/Word.php new file mode 100644 index 0000000..6aaad4d --- /dev/null +++ b/src/AppBundle/Entity/Word.php @@ -0,0 +1,134 @@ +wishlists = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * Set word + * + * @param string $word + * + * @return Word + */ + public function setWord($word) + { + $this->word = $word; + + return $this; + } + + /** + * Get word + * + * @return string + */ + public function getWord() + { + return $this->word; + } + + /** + * Set user + * + * @param \AppBundle\Entity\User $user + * + * @return Word + */ + public function setUser(\AppBundle\Entity\User $user = null) + { + $this->user = $user; + + return $this; + } + + /** + * Get user + * + * @return \AppBundle\Entity\User + */ + public function getUser() + { + return $this->user; + } + + /** + * Add wishlist + * + * @param \AppBundle\Entity\Wishlist $wishlist + * + * @return Word + */ + public function addWishlist(\AppBundle\Entity\Wishlist $wishlist) + { + if (!$this->wishlists->contains($wishlist)) { + $this->wishlists[] = $wishlist; + $wishlist->addWord($this); + } + + return $this; + } + + /** + * Remove wishlist + * + * @param \AppBundle\Entity\Wishlist $wishlist + */ + public function removeWishlist(\AppBundle\Entity\Wishlist $wishlist) + { + $this->wishlists->removeElement($wishlist); + } + + /** + * Get wishlists + * + * @return \Doctrine\Common\Collections\Collection + */ + public function getWishlists() + { + return $this->wishlists; + } +} diff --git a/src/AppBundle/Repository/UserProfileRepository.php b/src/AppBundle/Repository/UserProfileRepository.php new file mode 100644 index 0000000..c33372c --- /dev/null +++ b/src/AppBundle/Repository/UserProfileRepository.php @@ -0,0 +1,13 @@ + Date: Tue, 31 Jan 2017 23:06:22 +0200 Subject: [PATCH 02/13] Added fixtures --- app/AppKernel.php | 1 + app/config/security.yml | 3 ++ .../DataFixtures/ORM/AppFixtures.php | 34 +++++++++++++ .../ORM/Processor/UserProcessor.php | 43 +++++++++++++++++ src/AppBundle/DataFixtures/ORM/fixtures.yml | 48 +++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 src/AppBundle/DataFixtures/ORM/AppFixtures.php create mode 100644 src/AppBundle/DataFixtures/ORM/Processor/UserProcessor.php create mode 100644 src/AppBundle/DataFixtures/ORM/fixtures.yml diff --git a/app/AppKernel.php b/app/AppKernel.php index c9be0bb..587b2eb 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -24,6 +24,7 @@ public function registerBundles() $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); + $bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle(); } return $bundles; diff --git a/app/config/security.yml b/app/config/security.yml index 343eb49..8f669d3 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -1,6 +1,9 @@ # To get started with security, check out the documentation: # http://symfony.com/doc/current/security.html security: + encoders: + AppBundle\Entity\User: + algorithm: bcrypt # http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded providers: diff --git a/src/AppBundle/DataFixtures/ORM/AppFixtures.php b/src/AppBundle/DataFixtures/ORM/AppFixtures.php new file mode 100644 index 0000000..5026b69 --- /dev/null +++ b/src/AppBundle/DataFixtures/ORM/AppFixtures.php @@ -0,0 +1,34 @@ +container = $container; + } + + /** + * @param ObjectManager $manager + */ + public function load(ObjectManager $manager) + { + $encoder = $this->container->get('security.password_encoder'); + + $userProcessor = new UserProcessor($encoder); + + Fixtures::load(__DIR__.'/fixtures.yml', $manager, [], [$userProcessor]); + } +} diff --git a/src/AppBundle/DataFixtures/ORM/Processor/UserProcessor.php b/src/AppBundle/DataFixtures/ORM/Processor/UserProcessor.php new file mode 100644 index 0000000..c2bc6ad --- /dev/null +++ b/src/AppBundle/DataFixtures/ORM/Processor/UserProcessor.php @@ -0,0 +1,43 @@ +encoder = $encoder; + } + + /** + * @param object $object + */ + public function preProcess($object) + { + if (!$object instanceof User) { + return; + } + + $password = $this->encoder->encodePassword($object, $object->getPassword()); + $object->setPassword($password); + } + + /** + * @param object $object + */ + public function postProcess($object) + { + } +} diff --git a/src/AppBundle/DataFixtures/ORM/fixtures.yml b/src/AppBundle/DataFixtures/ORM/fixtures.yml new file mode 100644 index 0000000..0b925a8 --- /dev/null +++ b/src/AppBundle/DataFixtures/ORM/fixtures.yml @@ -0,0 +1,48 @@ +AppBundle\Entity\User: + userAdminDefault1: + userProfile (unique): '@uProfile1' + wishlist (unique): '@wishlist1' + username (unique): admin + password: admin + email: admin@example.com + roles: ["ROLE_ADMIN"] + dateCreated: '' + dateUpdated: '' + userDefault2: + userProfile (unique): '@uProfile2' + wishlist (unique): '@wishlist2' + username (unique): user + password: user + email: user@example.com + roles: ["ROLE_USER"] + dateCreated: '' + dateUpdated: '' + user{3..12}: + userProfile (unique): '@uProfile' + wishlist (unique): '@wishlist' + username (unique): '' + password: '' + email (unique): '' + roles: '' + dateCreated: '' + dateUpdated: '' + +AppBundle\Entity\UserProfile: + uProfile{1..12}: + firstName: '' + lastName: '' + dateCreated: '' + dateUpdated: '' + +AppBundle\Entity\Word: + word{1..30}: + user: '@user*' + word: '' + dateCreated: '' + dateUpdated: '' + +AppBundle\Entity\Wishlist: + wishlist{1..12}: + words: ['@word*'] + dateCreated: '' + dateUpdated: '' From 2e85aedf8fa4826d1e865d7d45279d37e49d86df Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Wed, 1 Feb 2017 06:02:09 +0200 Subject: [PATCH 03/13] Added: Controllers, Forms, Templates, Gulp, Security --- .gitignore | 6 + app/AppKernel.php | 1 + app/config/config.yml | 13 ++ app/config/security.yml | 19 +++ app/config/services.yml | 7 + bower.json | 22 +++ composer.json | 4 +- gulpfile.js | 93 ++++++++++++ package.json | 32 +++++ .../Controller/DefaultController.php | 21 --- src/AppBundle/Controller/UserController.php | 90 ++++++++++++ .../Controller/WishlistController.php | 98 +++++++++++++ src/AppBundle/Controller/WordController.php | 135 ++++++++++++++++++ src/AppBundle/Form/LoginType.php | 41 ++++++ src/AppBundle/Form/UserProfileType.php | 41 ++++++ src/AppBundle/Form/UserType.php | 53 +++++++ src/AppBundle/Form/WordType.php | 60 ++++++++ src/AppBundle/Repository/WordRepository.php | 26 ++++ src/AppBundle/Resources/views/base.html.twig | 29 ++++ .../Resources/views/base/_bottom.html.twig | 3 + .../Resources/views/base/_footer.html.twig | 11 ++ .../Resources/views/base/_head.html.twig | 8 ++ .../Resources/views/base/_header.html.twig | 36 +++++ .../views/default/_navbar_top_links.html.twig | 18 +++ .../Resources/views/default/form.html.twig | 15 ++ .../Resources/views/user/form.html.twig | 25 ++++ .../Resources/views/word/index.html.twig | 63 ++++++++ src/AppBundle/Security/AppVoter.php | 118 +++++++++++++++ web-src/js/app.js | 3 + web-src/less/app.less | 15 ++ 30 files changed, 1084 insertions(+), 22 deletions(-) create mode 100644 bower.json create mode 100644 gulpfile.js create mode 100644 package.json delete mode 100644 src/AppBundle/Controller/DefaultController.php create mode 100644 src/AppBundle/Controller/UserController.php create mode 100644 src/AppBundle/Controller/WishlistController.php create mode 100644 src/AppBundle/Controller/WordController.php create mode 100644 src/AppBundle/Form/LoginType.php create mode 100644 src/AppBundle/Form/UserProfileType.php create mode 100644 src/AppBundle/Form/UserType.php create mode 100644 src/AppBundle/Form/WordType.php create mode 100644 src/AppBundle/Resources/views/base.html.twig create mode 100644 src/AppBundle/Resources/views/base/_bottom.html.twig create mode 100644 src/AppBundle/Resources/views/base/_footer.html.twig create mode 100644 src/AppBundle/Resources/views/base/_head.html.twig create mode 100644 src/AppBundle/Resources/views/base/_header.html.twig create mode 100644 src/AppBundle/Resources/views/default/_navbar_top_links.html.twig create mode 100644 src/AppBundle/Resources/views/default/form.html.twig create mode 100644 src/AppBundle/Resources/views/user/form.html.twig create mode 100644 src/AppBundle/Resources/views/word/index.html.twig create mode 100644 src/AppBundle/Security/AppVoter.php create mode 100644 web-src/js/app.js create mode 100644 web-src/less/app.less diff --git a/.gitignore b/.gitignore index 93821ad..90c4427 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,9 @@ !var/SymfonyRequirements.php /vendor/ /web/bundles/ +/node_modules/ +/bower_components/ +/web/fonts/ +/web/css/ +/web/images/ +/web/js/ diff --git a/app/AppKernel.php b/app/AppKernel.php index 587b2eb..74597b1 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -17,6 +17,7 @@ public function registerBundles() new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new AppBundle\AppBundle(), new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(), + new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(), ]; if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { diff --git a/app/config/config.yml b/app/config/config.yml index 64be8f0..ae0cee0 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -38,6 +38,8 @@ framework: twig: debug: "%kernel.debug%" strict_variables: "%kernel.debug%" + form_themes: + - bootstrap_3_layout.html.twig # Doctrine Configuration doctrine: @@ -78,3 +80,14 @@ stof_doctrine_extensions: orm: default: timestampable: true + +knp_paginator: + page_range: 5 # default page range used in pagination control + default_options: + page_name: page # page query parameter name + sort_field_name: sort # sort field query parameter name + sort_direction_name: direction # sort direction query parameter name + distinct: true # ensure distinct results, useful when ORM queries are using GROUP BY statements + template: + pagination: KnpPaginatorBundle:Pagination:twitter_bootstrap_v3_pagination.html.twig # sliding pagination controls template + sortable: KnpPaginatorBundle:Pagination:sortable_link.html.twig # sort link template diff --git a/app/config/security.yml b/app/config/security.yml index 8f669d3..75939b4 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -10,6 +10,11 @@ security: in_memory: memory: ~ + app_db_provider: + entity: + class: AppBundle:User + property: username + firewalls: # disables authentication for assets and the profiler, adapt it according to your needs dev: @@ -25,3 +30,17 @@ security: # form_login: ~ # http://symfony.com/doc/current/cookbook/security/form_login_setup.html + + form_login: + login_path: login + check_path: login + logout: + path: /logout + target: /login + provider: app_db_provider + + role_hierarchy: + ROLE_ADMIN: [ROLE_USER] + + access_control: + - { path: ^/words/[0-9]+, roles: [ROLE_USER] } diff --git a/app/config/services.yml b/app/config/services.yml index 5a805ca..c62ba4f 100644 --- a/app/config/services.yml +++ b/app/config/services.yml @@ -7,3 +7,10 @@ services: # service_name: # class: AppBundle\Directory\ClassName # arguments: ["@another_service_name", "plain_value", "%parameter_name%"] + + app.app_voter: + class: AppBundle\Security\AppVoter + arguments: ['@security.access.decision_manager'] + public: false + tags: + - { name: security.voter } diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..9c3a774 --- /dev/null +++ b/bower.json @@ -0,0 +1,22 @@ +{ + "name": "geekhub-php-vocabulary", + "description": "Geekhub PHP HomeWork: Symfony vocabulary Application", + "main": "index.js", + "authors": [ + "Andrey Lukashenko" + ], + "license": "MIT", + "homepage": "https://github.com/AndreyLuka/geekhub-php-vocabulary", + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "bootstrap": "^3.3.7", + "html5shiv": "^3.7.3", + "respond": "Respond#^1.4.2" + } +} diff --git a/composer.json b/composer.json index b4d2254..72a62a7 100644 --- a/composer.json +++ b/composer.json @@ -47,7 +47,9 @@ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" ], "post-install-cmd": [ - "@symfony-scripts" + "@symfony-scripts", + "npm i", + "./node_modules/.bin/bower install" ], "post-update-cmd": [ "@symfony-scripts" diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..6c2884b --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,93 @@ +var gulp = require('gulp'), + gulpif = require('gulp-if'), + uglify = require('gulp-uglify'), + uglifycss = require('gulp-uglifycss'), + less = require('gulp-less'), + concat = require('gulp-concat'), + sourcemaps = require('gulp-sourcemaps'), + del = require('del'), + env = process.env.GULP_ENV; + +var Config = { + path: { + 'source': 'web-src', + 'build': 'web' + }, + mainCss: 'app.css', + mainJs: 'app.js', + jsFiles: [ + 'bower_components/jquery/dist/jquery.js', + 'bower_components/bootstrap/dist/js/bootstrap.js', + 'web-src/js/*.js', + 'web-src/js/**/*.js' + ], + cssFiles: [ + 'bower_components/bootstrap/dist/css/bootstrap.css', + 'web-src/less/*.less', + 'web-src/less/**/*.less' + ], + fontsFiles: [ + 'bower_components/bootstrap/dist/fonts/*' + ], + ieFiles: [ + 'bower_components/html5shiv/dist/html5shiv.min.js', + 'bower_components/respond/dest/respond.min.js' + ] +}; + +// Clean task: Delete all +gulp.task('clean', function () { + del.sync(['web/css', 'web/js', 'web/img', 'web/fonts']); +}); + +// JavaScript task: Write one minified js file +gulp.task('js', function () { + return gulp.src(Config.jsFiles) + .pipe(sourcemaps.init()) + .pipe(concat(Config.mainJs)) + .pipe(gulpif(env === 'prod', uglify())) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest(Config.path.build + '/js')); +}); + +// CSS task: Write one minified css file +gulp.task('css', function () { + return gulp.src(Config.cssFiles) + .pipe(sourcemaps.init()) + .pipe(gulpif(/[.]less/, less())) + .pipe(concat(Config.mainCss)) + .pipe(gulpif(env === 'prod', uglifycss())) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest(Config.path.build + '/css')); +}); + +// Image task: Pipe images from project folder to public web folder +gulp.task('img', function() { + return gulp.src(Config.path.source + '/img/**/*.*') + .pipe(gulp.dest(Config.path.build + '/img')); +}); + +// Fonts task: Pipe fonts to public web folder +gulp.task('fonts', function() { + return gulp.src(Config.fontsFiles) + .pipe(gulp.dest(Config.path.build + '/fonts')); +}); + +// IE task: Pipe IE hacks to public web folder +gulp.task('ie', function() { + return gulp.src(Config.ieFiles) + .pipe(gulp.dest(Config.path.build + '/js/ie')); +}); + +// Default task when running 'gulp' command +gulp.task('default', ['clean'], function () { + gulp.start(['js', 'css', 'img', 'fonts', 'ie']) +}); + +// Watch task +gulp.task('watch', ['default'], function () { + gulp.watch(Config.path.source + '/less/*.less', ['css']); + gulp.watch(Config.path.source + '/less/**/*.less', ['css']); + gulp.watch(Config.path.source + '/js/*.js', ['js']); + gulp.watch(Config.path.source + '/js/**/*.js', ['js']); +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..2c20422 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "geekhub-php-vocabulary", + "version": "0.0.0", + "description": "Geekhub PHP HomeWork: Symfony Vocabulary Application", + "main": "index.js", + "directories": { + "test": "tests" + }, + "scripts": { + "test": "test" + }, + "repository": { + "type": "git", + "url": "https://github.com/AndreyLuka/geekhub-php-vocabulary.git" + }, + "author": "Andrey Lukashenko", + "license": "MIT", + "bugs": { + "url": "https://github.com/AndreyLuka/geekhub-php-vocabulary/issues" + }, + "dependencies": { + "bower": "~1.8.0", + "gulp": "~3.9.1", + "gulp-if": "~2.0.2", + "gulp-uglifycss": "~1.0.6", + "gulp-concat": "~2.6.1", + "gulp-sourcemaps": "~1.9.1", + "gulp-uglify": "~2.0.0", + "gulp-less": "~3.3.0", + "del": "~2.2.2" + } +} diff --git a/src/AppBundle/Controller/DefaultController.php b/src/AppBundle/Controller/DefaultController.php deleted file mode 100644 index 5216afe..0000000 --- a/src/AppBundle/Controller/DefaultController.php +++ /dev/null @@ -1,21 +0,0 @@ -render('default/index.html.twig', [ - 'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR, - ]); - } -} diff --git a/src/AppBundle/Controller/UserController.php b/src/AppBundle/Controller/UserController.php new file mode 100644 index 0000000..48cdfb8 --- /dev/null +++ b/src/AppBundle/Controller/UserController.php @@ -0,0 +1,90 @@ +createForm(UserType::class, $user); + + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + + $password = $this->get('security.password_encoder') + ->encodePassword($user, $user->getPlainPassword()); + $user->setPassword($password); + + $user->setRoles(array('ROLE_USER')); + + $wishlist = new Wishlist(); + $user->setWishlist($wishlist); + + $em = $this->getDoctrine()->getManager(); + $em->persist($user); + $em->flush(); + + return $this->redirectToRoute('homepage'); + } + + return $this->render('AppBundle:user:form.html.twig', array( + 'formTitle' => 'Registration', + 'form' => $form->createView(), + 'error' => null + )); + } + + /** + * @Route("/login", name="login") + * @Method({"GET", "POST"}) + * + * @return Response + */ + public function loginAction() + { + $authenticationUtils = $this->get('security.authentication_utils'); + + // get the login error if there is one + $error = $authenticationUtils->getLastAuthenticationError(); + + // last username entered by the user + $lastUsername = $authenticationUtils->getLastUsername(); + + $form = $this->createForm(LoginType::class, array( + '_username' => $lastUsername + )); + + return $this->render('AppBundle:user:form.html.twig', array( + 'formTitle' => 'Login', + 'form' => $form->createView(), + 'error' => $error + )); + } + + /** + * @Route("/logout", name="logout") + */ + public function logoutAction() + { + } +} diff --git a/src/AppBundle/Controller/WishlistController.php b/src/AppBundle/Controller/WishlistController.php new file mode 100644 index 0000000..8260f7c --- /dev/null +++ b/src/AppBundle/Controller/WishlistController.php @@ -0,0 +1,98 @@ +getDoctrine() + ->getRepository('AppBundle:Word') + ->findAllByWishlist($wishlist->getId()); + + $pagination = $this->get('knp_paginator')->paginate( + $words, $page, 5 + ); + + return $this->render('AppBundle:word:index.html.twig', array( + 'title' => 'Wishlist', + 'pagination' => $pagination + )); + } + + /** + * @Route("/wishlist/{id}/add/{wordId}", + * requirements={"id": "\d+", "wordId": "\d+"}, + * name="wishlist_add_word" + * ) + * @ParamConverter("word", options={"mapping": {"wordId": "id"}}) + * @Method({"GET"}) + * + * @param Wishlist $wishlist + * @param Word $word + * + * @return Response + */ + public function addWordAction(Wishlist $wishlist, Word $word) + { + $wishlist->addWord($word); + + $em = $this->getDoctrine()->getManager(); + $em->persist($wishlist); + $em->flush(); + + return $this->redirectToRoute('wishlist_show', ['id' => $wishlist->getId()]); + } + + /** + * @Route("/wishlist/{id}/delete/{wordId}", + * requirements={"id": "\d+", "wordId": "\d+"}, + * name="wishlist_remove_word" + * ) + * @ParamConverter("word", options={"mapping": {"wordId": "id"}}) + * @Method({"GET"}) + * + * @param Wishlist $wishlist + * @param Word $word + * + * @return Response + */ + public function removeWordAction(Wishlist $wishlist, Word $word) + { + $wishlist->removeWord($word); + $word->removeWishlist($wishlist); + + $em = $this->getDoctrine()->getManager(); + + $em->persist($wishlist); + $em->persist($word); + $em->flush(); + + return $this->redirectToRoute('wishlist_show', ['id' => $wishlist->getId()]); + } +} diff --git a/src/AppBundle/Controller/WordController.php b/src/AppBundle/Controller/WordController.php new file mode 100644 index 0000000..8a07e94 --- /dev/null +++ b/src/AppBundle/Controller/WordController.php @@ -0,0 +1,135 @@ +getDoctrine() + ->getRepository('AppBundle:Word') + ->findAllWords(); + + $pagination = $this->get('knp_paginator')->paginate( + $words, $page, 5 + ); + + return $this->render('AppBundle:word:index.html.twig', array( + 'title' => 'Words', + 'pagination' => $pagination + )); + } + + /** + * @Route("/words/new", name="word_new") + * @Method({"GET", "POST"}) + * + * @param Request $request + * + * @return Response + */ + public function newAction(Request $request) + { + $this->denyAccessUnlessGranted('create_word', $this->getUser()); + + $word = new Word(); + $word->setUser($this->getUser()); + + $form = $this->createForm(WordType::class, $word, [ + 'authorizationChecker' => $this->get('security.authorization_checker') + ]); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $wordData = $form->getData(); + + $em = $this->getDoctrine()->getManager(); + $em->persist($wordData); + $em->flush(); + + return $this->redirectToRoute('word_index'); + } + + return $this->render('AppBundle:default:form.html.twig', array( + 'formTitle' => 'Add new word', + 'form' => $form->createView() + )); + } + + /** + * @Route("/words/{id}/edit", requirements={"id": "\d+"}, name="word_edit") + * @Method({"GET", "POST"}) + * + * @param Request $request + * @param Word $word + * + * @return Response + */ + public function editAction(Request $request, Word $word) + { + $this->denyAccessUnlessGranted('edit_word', $this->getUser()); + + $form = $this->createForm(WordType::class, $word, [ + 'authorizationChecker' => $this->get('security.authorization_checker') + ]); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + $wordData = $form->getData(); + + $em = $this->getDoctrine()->getManager(); + $em->persist($wordData); + $em->flush(); + + return $this->redirectToRoute('word_index'); + } + + return $this->render('AppBundle:default:form.html.twig', array( + 'formTitle' => 'Edit word', + 'form' => $form->createView() + )); + } + + /** + * @Route("/words/{id}/delete", requirements={"id": "\d+"}, name="word_delete") + * @Method({"GET", "POST"}) + * + * @param Word $word + * + * @return Response + */ + public function deleteAction(Word $word) + { + $this->denyAccessUnlessGranted('edit', $word); + + $em = $this->getDoctrine()->getManager(); + + $em->remove($word); + $em->flush(); + + return $this->redirectToRoute('word_index'); + } +} diff --git a/src/AppBundle/Form/LoginType.php b/src/AppBundle/Form/LoginType.php new file mode 100644 index 0000000..66fd05e --- /dev/null +++ b/src/AppBundle/Form/LoginType.php @@ -0,0 +1,41 @@ +add('_username') + ->add('_password', PasswordType::class) + ->add('login', SubmitType::class); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'attr' => array('novalidate' => 'novalidate') + )); + } + + /** + * {@inheritdoc} + */ + public function getBlockPrefix() + { + return null; + } +} diff --git a/src/AppBundle/Form/UserProfileType.php b/src/AppBundle/Form/UserProfileType.php new file mode 100644 index 0000000..913b106 --- /dev/null +++ b/src/AppBundle/Form/UserProfileType.php @@ -0,0 +1,41 @@ +add('firstName') + ->add('lastName') + ; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'data_class' => UserProfile::class, + 'attr' => array('novalidate' => 'novalidate') + )); + } + + /** + * {@inheritdoc} + */ + public function getBlockPrefix() + { + return 'appbundle_user_profile'; + } +} diff --git a/src/AppBundle/Form/UserType.php b/src/AppBundle/Form/UserType.php new file mode 100644 index 0000000..c33d3d5 --- /dev/null +++ b/src/AppBundle/Form/UserType.php @@ -0,0 +1,53 @@ +add('email', EmailType::class) + ->add('username', TextType::class) + ->add('plainPassword', RepeatedType::class, array( + 'type' => PasswordType::class, + 'first_options' => array('label' => 'Password'), + 'second_options' => array('label' => 'Repeat Password'), + )) + ->add('userProfile', UserProfileType::class) + ->add('Register', SubmitType::class) + ; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'data_class' => User::class, + 'attr' => array('novalidate' => 'novalidate') + )); + } + + /** + * {@inheritdoc} + */ + public function getBlockPrefix() + { + return 'appbundle_user'; + } +} diff --git a/src/AppBundle/Form/WordType.php b/src/AppBundle/Form/WordType.php new file mode 100644 index 0000000..baef1dd --- /dev/null +++ b/src/AppBundle/Form/WordType.php @@ -0,0 +1,60 @@ +authorizationChecker = $options['authorizationChecker']; + + $builder + ->add('word'); + + if (isset($this->authorizationChecker) && $this->authorizationChecker->isGranted('ROLE_ADMIN')) { + $builder->add('user', EntityType::class, array( + 'class' => 'AppBundle:User', + 'choice_label' => 'userProfile.firstName userProfile.lastName', + 'label' => 'Author', + )); + } + + $builder->add('save', SubmitType::class); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + 'data_class' => 'AppBundle\Entity\Word', + 'attr' => array('novalidate' => 'novalidate'), + 'authorizationChecker' => null + )); + } + + /** + * {@inheritdoc} + */ + public function getBlockPrefix() + { + return 'appbundle_word'; + } +} diff --git a/src/AppBundle/Repository/WordRepository.php b/src/AppBundle/Repository/WordRepository.php index 49f7f83..b8c40f4 100644 --- a/src/AppBundle/Repository/WordRepository.php +++ b/src/AppBundle/Repository/WordRepository.php @@ -7,5 +7,31 @@ */ class WordRepository extends \Doctrine\ORM\EntityRepository { + /** + * @return \Doctrine\ORM\Query + */ + public function findAllWords() + { + $query = $this->createQueryBuilder('w') + ->orderBy('w.dateCreated', 'DESC') + ; + return $query; + } + + /** + * @param int $wishlistId + * + * @return \Doctrine\ORM\Query + */ + public function findAllByWishlist($wishlistId) + { + $query = $this->createQueryBuilder('word') + ->innerJoin('word.wishlists', 'w', 'WITH', 'w.id = :wishlistId') + ->setParameter('wishlistId', $wishlistId) + ->orderBy('word.dateCreated', 'DESC') + ; + + return $query; + } } diff --git a/src/AppBundle/Resources/views/base.html.twig b/src/AppBundle/Resources/views/base.html.twig new file mode 100644 index 0000000..2f124c5 --- /dev/null +++ b/src/AppBundle/Resources/views/base.html.twig @@ -0,0 +1,29 @@ + + + + + + + {% block docTitle 'Vocabulary' %} + {% block head %} + {% include 'AppBundle:base:_head.html.twig' %} + {% endblock %} + + + {% block header %} + {% include 'AppBundle:base:_header.html.twig' %} + {% endblock %} + +
+ {% block main %}{% endblock %} +
+ + {% block footer %} + {% include 'AppBundle:base:_footer.html.twig' %} + {% endblock %} + + {% block bottom %} + {% include 'AppBundle:base:_bottom.html.twig' %} + {% endblock %} + + diff --git a/src/AppBundle/Resources/views/base/_bottom.html.twig b/src/AppBundle/Resources/views/base/_bottom.html.twig new file mode 100644 index 0000000..a41317b --- /dev/null +++ b/src/AppBundle/Resources/views/base/_bottom.html.twig @@ -0,0 +1,3 @@ +{% block javascripts %} + +{% endblock %} diff --git a/src/AppBundle/Resources/views/base/_footer.html.twig b/src/AppBundle/Resources/views/base/_footer.html.twig new file mode 100644 index 0000000..6f0164d --- /dev/null +++ b/src/AppBundle/Resources/views/base/_footer.html.twig @@ -0,0 +1,11 @@ +
+
+
+
+
+

© Andrey Lukashenko

+

Geekhub PHP 2016

+
+
+
+
diff --git a/src/AppBundle/Resources/views/base/_head.html.twig b/src/AppBundle/Resources/views/base/_head.html.twig new file mode 100644 index 0000000..776462a --- /dev/null +++ b/src/AppBundle/Resources/views/base/_head.html.twig @@ -0,0 +1,8 @@ +{% block stylesheets %} + +{% endblock %} + + diff --git a/src/AppBundle/Resources/views/base/_header.html.twig b/src/AppBundle/Resources/views/base/_header.html.twig new file mode 100644 index 0000000..8a4f465 --- /dev/null +++ b/src/AppBundle/Resources/views/base/_header.html.twig @@ -0,0 +1,36 @@ + diff --git a/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig b/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig new file mode 100644 index 0000000..5615b38 --- /dev/null +++ b/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig @@ -0,0 +1,18 @@ + diff --git a/src/AppBundle/Resources/views/default/form.html.twig b/src/AppBundle/Resources/views/default/form.html.twig new file mode 100644 index 0000000..aa010ab --- /dev/null +++ b/src/AppBundle/Resources/views/default/form.html.twig @@ -0,0 +1,15 @@ +{% extends 'AppBundle::base.html.twig' %} + +{% block main %} +
+
+
+

{{ formTitle }}

+ + {{ form_start(form) }} + {{ form_widget(form) }} + {{ form_end(form) }} +
+
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/user/form.html.twig b/src/AppBundle/Resources/views/user/form.html.twig new file mode 100644 index 0000000..5c44cc0 --- /dev/null +++ b/src/AppBundle/Resources/views/user/form.html.twig @@ -0,0 +1,25 @@ +{% extends 'AppBundle::base.html.twig' %} + +{% block main %} +
+
+
+ {% if is_granted('IS_AUTHENTICATED_FULLY') %} +

You are logged in. Logout

+ {% else %} +

{{ formTitle }}

+ + {% if error %} +
+ {{ error.messageKey|trans(error.messageData, 'security') }} +
+ {% endif %} + + {{ form_start(form) }} + {{ form_widget(form) }} + {{ form_end(form) }} + {% endif %} +
+
+
+{% endblock %} diff --git a/src/AppBundle/Resources/views/word/index.html.twig b/src/AppBundle/Resources/views/word/index.html.twig new file mode 100644 index 0000000..550473d --- /dev/null +++ b/src/AppBundle/Resources/views/word/index.html.twig @@ -0,0 +1,63 @@ +{% extends 'AppBundle::base.html.twig' %} + +{% block main %} +
+
+
+ +
+ +

{{ title }}

+ {% if is_granted('create_word', app.user) %} +

Add new word

+ {% endif %} + +
+ + + + + + + + {% if is_granted('edit_word', app.user) %} + + {% endif %} + + + + {% for word in pagination %} + + + + + + + + {% endfor %} + +
WordAuthorCreatedUpdatedActions
{{ word.word }}{{ word.user.userProfile.firstName }} {{ word.user.userProfile.lastName }}{{ word.dateCreated|date("d.m.Y") }}{{ word.dateUpdated|date("d.m.Y") }} + {% if is_granted('edit_word', app.user) %} + {% if word in app.user.wishlist.words %} + Remove from wishlist + {% else %} + Add to wishlist + {% endif %} + Edit + {% endif %} + {% if is_granted('edit', word) %} + Delete + {% endif %} +
+
+ +
+ +
+ {{ knp_pagination_render(pagination) }} +
+ +
+
+
+{% endblock %} diff --git a/src/AppBundle/Security/AppVoter.php b/src/AppBundle/Security/AppVoter.php new file mode 100644 index 0000000..7674b07 --- /dev/null +++ b/src/AppBundle/Security/AppVoter.php @@ -0,0 +1,118 @@ +decisionManager = $decisionManager; + } + + /** + * @inheritdoc + */ + protected function supports($attribute, $subject) + { + // if the attribute isn't one we support, return false + if (!in_array($attribute, array( + self::VIEW, self::EDIT, self::CREATE_WORD, self::EDIT_WORD + ))) { + return false; + } + + // only vote on this objects inside this voter + if (!($subject instanceof Word || $subject instanceof User)) { + return false; + } + + return true; + } + + /** + * @inheritdoc + */ + protected function voteOnAttribute($attribute, $subject, TokenInterface $token) + { + $user = $token->getUser(); + $roleAdmin = $this->decisionManager->decide($token, array('ROLE_ADMIN')); + $roleUser = $this->decisionManager->decide($token, array('ROLE_USER')); + + if (!$user instanceof User) { + // the user must be logged in; if not, deny access + return false; + } + + // ROLE_ADMIN can do anything! The power! + if ($roleAdmin) { + return true; + } + + switch ($attribute) { + case self::VIEW: + return $this->canView($subject, $user); + case self::EDIT: + return $this->canEdit($subject, $user); + case self::CREATE_WORD: + if ($roleUser) { + return true; + } + case self::EDIT_WORD: + if ($roleUser) { + return true; + } + } + + return false; + } + + /** + * @param mixed $subject + * @param User $user + * + * @return bool + */ + private function canView($subject, User $user) + { + // if they can edit, they can view + if ($this->canEdit($subject, $user)) { + return true; + } + + return false; + } + + /** + * @param mixed $subject + * @param User $user + * + * @return bool + */ + private function canEdit($subject, User $user) + { + // this assumes that the data object has a getOwner() method + // to get the entity of the user who owns this data object + return $user === $subject->getUser(); + } +} diff --git a/web-src/js/app.js b/web-src/js/app.js new file mode 100644 index 0000000..42f8096 --- /dev/null +++ b/web-src/js/app.js @@ -0,0 +1,3 @@ +$(document).ready(function () { + console.log('Hello from web/js/app.js'); +}); // document.ready diff --git a/web-src/less/app.less b/web-src/less/app.less new file mode 100644 index 0000000..34f195d --- /dev/null +++ b/web-src/less/app.less @@ -0,0 +1,15 @@ +.site-header { + .navbar { + border-width: 0 0 1px; + border-radius: 0; + } +} + +.site-footer { + > .panel { + margin-bottom: 0; + border-radius: 0; + border-width: 1px 0 0; + box-shadow: none; + } +} From 1e232aad118c9d250900cba9c6bf5abe0fb39cfb Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Thu, 2 Feb 2017 23:25:30 +0200 Subject: [PATCH 04/13] Added OneToOne bidirectional relation to User & Wishlist --- .../Controller/WishlistController.php | 6 ++++ src/AppBundle/DataFixtures/ORM/fixtures.yml | 19 +++++++++--- src/AppBundle/Entity/User.php | 2 +- src/AppBundle/Entity/Wishlist.php | 31 +++++++++++++++++++ src/AppBundle/Security/AppVoter.php | 7 ++++- 5 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/AppBundle/Controller/WishlistController.php b/src/AppBundle/Controller/WishlistController.php index 8260f7c..a1e9ef0 100644 --- a/src/AppBundle/Controller/WishlistController.php +++ b/src/AppBundle/Controller/WishlistController.php @@ -31,6 +31,8 @@ class WishlistController extends Controller */ public function showAction(Wishlist $wishlist, $page = 1) { + $this->denyAccessUnlessGranted('edit', $wishlist); + $words = $this->getDoctrine() ->getRepository('AppBundle:Word') ->findAllByWishlist($wishlist->getId()); @@ -60,6 +62,8 @@ public function showAction(Wishlist $wishlist, $page = 1) */ public function addWordAction(Wishlist $wishlist, Word $word) { + $this->denyAccessUnlessGranted('edit', $wishlist); + $wishlist->addWord($word); $em = $this->getDoctrine()->getManager(); @@ -84,6 +88,8 @@ public function addWordAction(Wishlist $wishlist, Word $word) */ public function removeWordAction(Wishlist $wishlist, Word $word) { + $this->denyAccessUnlessGranted('edit', $wishlist); + $wishlist->removeWord($word); $word->removeWishlist($wishlist); diff --git a/src/AppBundle/DataFixtures/ORM/fixtures.yml b/src/AppBundle/DataFixtures/ORM/fixtures.yml index 0b925a8..581da2a 100644 --- a/src/AppBundle/DataFixtures/ORM/fixtures.yml +++ b/src/AppBundle/DataFixtures/ORM/fixtures.yml @@ -1,7 +1,7 @@ AppBundle\Entity\User: userAdminDefault1: userProfile (unique): '@uProfile1' - wishlist (unique): '@wishlist1' + #wishlist (unique): '@wishlist1' username (unique): admin password: admin email: admin@example.com @@ -10,7 +10,7 @@ AppBundle\Entity\User: dateUpdated: '' userDefault2: userProfile (unique): '@uProfile2' - wishlist (unique): '@wishlist2' + #wishlist (unique): '@wishlist2' username (unique): user password: user email: user@example.com @@ -19,7 +19,7 @@ AppBundle\Entity\User: dateUpdated: '' user{3..12}: userProfile (unique): '@uProfile' - wishlist (unique): '@wishlist' + #wishlist (unique): '@wishlist' username (unique): '' password: '' email (unique): '' @@ -42,7 +42,18 @@ AppBundle\Entity\Word: dateUpdated: '' AppBundle\Entity\Wishlist: - wishlist{1..12}: + wishlist1: words: ['@word*'] + user: '@userAdminDefault1' + dateCreated: '' + dateUpdated: '' + wishlist2: + words: ['@word*'] + user: '@userDefault2' + dateCreated: '' + dateUpdated: '' + wishlist{3..12}: + words: ['@word*'] + user (unique): '@user' dateCreated: '' dateUpdated: '' diff --git a/src/AppBundle/Entity/User.php b/src/AppBundle/Entity/User.php index 601c2fe..1b92c03 100644 --- a/src/AppBundle/Entity/User.php +++ b/src/AppBundle/Entity/User.php @@ -80,7 +80,7 @@ class User extends BaseSuperClass implements AdvancedUserInterface, \Serializabl /** * @var Wishlist * - * @ORM\OneToOne(targetEntity="Wishlist", cascade={"persist"}) + * @ORM\OneToOne(targetEntity="Wishlist", mappedBy="user", cascade={"persist"}) */ private $wishlist; diff --git a/src/AppBundle/Entity/Wishlist.php b/src/AppBundle/Entity/Wishlist.php index 8af1706..996b909 100644 --- a/src/AppBundle/Entity/Wishlist.php +++ b/src/AppBundle/Entity/Wishlist.php @@ -22,6 +22,13 @@ class Wishlist extends BaseSuperClass */ private $name; + /** + * @var User + * + * @ORM\OneToOne(targetEntity="User", inversedBy="wishlist") + */ + private $user; + /** * @var \Doctrine\Common\Collections\ArrayCollection * @@ -62,6 +69,30 @@ public function getName() return $this->name; } + /** + * Set user + * + * @param \AppBundle\Entity\User $user + * + * @return Wishlist + */ + public function setUser(\AppBundle\Entity\User $user = null) + { + $this->user = $user; + + return $this; + } + + /** + * Get user + * + * @return \AppBundle\Entity\User + */ + public function getUser() + { + return $this->user; + } + /** * Add word * diff --git a/src/AppBundle/Security/AppVoter.php b/src/AppBundle/Security/AppVoter.php index 7674b07..4d73029 100644 --- a/src/AppBundle/Security/AppVoter.php +++ b/src/AppBundle/Security/AppVoter.php @@ -2,6 +2,7 @@ namespace AppBundle\Security; +use AppBundle\Entity\Wishlist; use AppBundle\Entity\Word; use AppBundle\Entity\User; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; @@ -43,7 +44,11 @@ protected function supports($attribute, $subject) } // only vote on this objects inside this voter - if (!($subject instanceof Word || $subject instanceof User)) { + if (!( + $subject instanceof Word || + $subject instanceof User || + $subject instanceof Wishlist + )) { return false; } From b1bd09ef3d99041b48f819662bcafd29f21d24de Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Mon, 6 Feb 2017 00:32:04 +0200 Subject: [PATCH 05/13] Added string translations --- app/config/config.yml | 2 + app/config/routing.yml | 3 ++ src/AppBundle/Controller/UserController.php | 13 +++--- .../Controller/WishlistController.php | 2 +- src/AppBundle/Controller/WordController.php | 10 ++--- src/AppBundle/Form/LoginType.php | 4 +- src/AppBundle/Form/UserType.php | 5 ++- src/AppBundle/Form/WordType.php | 9 ++-- .../Resources/translations/messages.en.yml | 41 +++++++++++++++++++ .../Resources/translations/messages.es.yml | 41 +++++++++++++++++++ .../Resources/translations/messages.fr.yml | 41 +++++++++++++++++++ .../Resources/translations/messages.ru.yml | 41 +++++++++++++++++++ .../Resources/translations/messages.uk.yml | 41 +++++++++++++++++++ src/AppBundle/Resources/views/base.html.twig | 2 +- .../Resources/views/base/_header.html.twig | 6 +-- .../views/default/_navbar_top_links.html.twig | 24 ++++++++--- .../user/{form.html.twig => login.html.twig} | 10 +++-- .../Resources/views/user/signup.html.twig | 26 ++++++++++++ .../Resources/views/word/edit.html.twig | 18 ++++++++ .../Resources/views/word/index.html.twig | 20 ++++----- .../form.html.twig => word/new.html.twig} | 5 ++- 21 files changed, 320 insertions(+), 44 deletions(-) create mode 100644 src/AppBundle/Resources/translations/messages.en.yml create mode 100644 src/AppBundle/Resources/translations/messages.es.yml create mode 100644 src/AppBundle/Resources/translations/messages.fr.yml create mode 100644 src/AppBundle/Resources/translations/messages.ru.yml create mode 100644 src/AppBundle/Resources/translations/messages.uk.yml rename src/AppBundle/Resources/views/user/{form.html.twig => login.html.twig} (62%) create mode 100644 src/AppBundle/Resources/views/user/signup.html.twig create mode 100644 src/AppBundle/Resources/views/word/edit.html.twig rename src/AppBundle/Resources/views/{default/form.html.twig => word/new.html.twig} (62%) diff --git a/app/config/config.yml b/app/config/config.yml index ae0cee0..5c6c7c6 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -33,6 +33,8 @@ framework: assets: ~ php_errors: log: true + translator: { fallbacks: [en] } + default_locale: en # Twig Configuration twig: diff --git a/app/config/routing.yml b/app/config/routing.yml index 8eadc31..14bcb82 100644 --- a/app/config/routing.yml +++ b/app/config/routing.yml @@ -1,3 +1,6 @@ app: resource: "@AppBundle/Controller/" type: annotation + prefix: /{_locale} + requirements: + _locale: "|en|uk|ru|fr|es" diff --git a/src/AppBundle/Controller/UserController.php b/src/AppBundle/Controller/UserController.php index 48cdfb8..871476b 100644 --- a/src/AppBundle/Controller/UserController.php +++ b/src/AppBundle/Controller/UserController.php @@ -23,7 +23,7 @@ class UserController extends Controller * * @return Response */ - public function newAction(Request $request) + public function signupAction(Request $request) { $user = new User(); $form = $this->createForm(UserType::class, $user); @@ -47,10 +47,9 @@ public function newAction(Request $request) return $this->redirectToRoute('homepage'); } - return $this->render('AppBundle:user:form.html.twig', array( - 'formTitle' => 'Registration', - 'form' => $form->createView(), - 'error' => null + return $this->render('AppBundle:user:signup.html.twig', array( + 'title' => $this->get('translator')->trans('user.signup'), + 'form' => $form->createView() )); } @@ -74,8 +73,8 @@ public function loginAction() '_username' => $lastUsername )); - return $this->render('AppBundle:user:form.html.twig', array( - 'formTitle' => 'Login', + return $this->render('AppBundle:user:login.html.twig', array( + 'title' => $this->get('translator')->trans('user.login'), 'form' => $form->createView(), 'error' => $error )); diff --git a/src/AppBundle/Controller/WishlistController.php b/src/AppBundle/Controller/WishlistController.php index a1e9ef0..e4b235a 100644 --- a/src/AppBundle/Controller/WishlistController.php +++ b/src/AppBundle/Controller/WishlistController.php @@ -42,7 +42,7 @@ public function showAction(Wishlist $wishlist, $page = 1) ); return $this->render('AppBundle:word:index.html.twig', array( - 'title' => 'Wishlist', + 'title' => $this->get('translator')->trans('wishlist.title'), 'pagination' => $pagination )); } diff --git a/src/AppBundle/Controller/WordController.php b/src/AppBundle/Controller/WordController.php index 8a07e94..062eafd 100644 --- a/src/AppBundle/Controller/WordController.php +++ b/src/AppBundle/Controller/WordController.php @@ -36,7 +36,7 @@ public function indexAction($page = 1) ); return $this->render('AppBundle:word:index.html.twig', array( - 'title' => 'Words', + 'title' => $this->get('translator')->trans('word.titleMany'), 'pagination' => $pagination )); } @@ -72,8 +72,8 @@ public function newAction(Request $request) return $this->redirectToRoute('word_index'); } - return $this->render('AppBundle:default:form.html.twig', array( - 'formTitle' => 'Add new word', + return $this->render('AppBundle:word:new.html.twig', array( + 'title' => $this->get('translator')->trans('word.new'), 'form' => $form->createView() )); } @@ -107,8 +107,8 @@ public function editAction(Request $request, Word $word) return $this->redirectToRoute('word_index'); } - return $this->render('AppBundle:default:form.html.twig', array( - 'formTitle' => 'Edit word', + return $this->render('AppBundle:word:edit.html.twig', array( + 'title' => $this->get('translator')->trans('word.edit'), 'form' => $form->createView() )); } diff --git a/src/AppBundle/Form/LoginType.php b/src/AppBundle/Form/LoginType.php index 66fd05e..3504d58 100644 --- a/src/AppBundle/Form/LoginType.php +++ b/src/AppBundle/Form/LoginType.php @@ -18,7 +18,9 @@ public function buildForm(FormBuilderInterface $builder, array $options) $builder ->add('_username') ->add('_password', PasswordType::class) - ->add('login', SubmitType::class); + ->add('login', SubmitType::class, array( + 'label' => 'user.login' + )); } /** diff --git a/src/AppBundle/Form/UserType.php b/src/AppBundle/Form/UserType.php index c33d3d5..f38c554 100644 --- a/src/AppBundle/Form/UserType.php +++ b/src/AppBundle/Form/UserType.php @@ -27,8 +27,9 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'first_options' => array('label' => 'Password'), 'second_options' => array('label' => 'Repeat Password'), )) - ->add('userProfile', UserProfileType::class) - ->add('Register', SubmitType::class) + ->add('userProfile', UserProfileType::class, array( + 'label' => false + )) ; } diff --git a/src/AppBundle/Form/WordType.php b/src/AppBundle/Form/WordType.php index baef1dd..2012f5c 100644 --- a/src/AppBundle/Form/WordType.php +++ b/src/AppBundle/Form/WordType.php @@ -6,6 +6,7 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\TextareaType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; @@ -25,17 +26,17 @@ public function buildForm(FormBuilderInterface $builder, array $options) $this->authorizationChecker = $options['authorizationChecker']; $builder - ->add('word'); + ->add('word', TextType::class, array( + 'label' => 'word.titleOne' + )); if (isset($this->authorizationChecker) && $this->authorizationChecker->isGranted('ROLE_ADMIN')) { $builder->add('user', EntityType::class, array( 'class' => 'AppBundle:User', 'choice_label' => 'userProfile.firstName userProfile.lastName', - 'label' => 'Author', + 'label' => 'base.author' )); } - - $builder->add('save', SubmitType::class); } /** diff --git a/src/AppBundle/Resources/translations/messages.en.yml b/src/AppBundle/Resources/translations/messages.en.yml new file mode 100644 index 0000000..ebc997b --- /dev/null +++ b/src/AppBundle/Resources/translations/messages.en.yml @@ -0,0 +1,41 @@ +base: + siteTitle: Vocabulary + search: Search + save: Save + edit: Edit + update: Update + delete: Delete + author: Author + created: Created + updated: Updated + actions: Actions + 'Hello, %name%': Hello, %name%! + +user: + signup: Sign Up + login: Login + logout: Logout + loggedin: You are logged in. + profile: + title: My Profile + +wishlist: + title: Wishlist + add: Add to wishlist + remove: Remove from wishlist + +word: + titleOne: Word + titleMany: Words + new: Add new word + edit: Edit word + +Email: Email +Username: Username +Password: Password +Repeat Password: Repeat Password +First name: First name +Last name: Last name + +Next: false +Previous: false diff --git a/src/AppBundle/Resources/translations/messages.es.yml b/src/AppBundle/Resources/translations/messages.es.yml new file mode 100644 index 0000000..f4816bc --- /dev/null +++ b/src/AppBundle/Resources/translations/messages.es.yml @@ -0,0 +1,41 @@ +base: + siteTitle: Vocabulario + search: Buscar + save: Guardar + edit: Editar + update: Actualización + delete: Eliminar + author: Autor + created: Creado + updated: Actualizado + actions: Acciones + 'Hello, %name%': Hola, %name%! + +user: + signup: Registrarse + login: Iniciar sesión + logout: Cerrar sesión + loggedin: Has iniciado sesión. + profile: + title: Mi perfil + +wishlist: + title: Lista de deseos + add: Agregar a la lista de deseos + remove: Eliminar de la lista de deseos + +word: + titleOne: Palabra + titleMany: Palabras + new: Añadir nueva palabra + edit: Editar palabra + +Email: Correo electrónico +Username: Nombre de usuario +Password: Contraseña +Repeat Password: Repetir contraseña +First name: Nombre de pila +Last name: Apellido + +Next: false +Previous: false diff --git a/src/AppBundle/Resources/translations/messages.fr.yml b/src/AppBundle/Resources/translations/messages.fr.yml new file mode 100644 index 0000000..5f678a9 --- /dev/null +++ b/src/AppBundle/Resources/translations/messages.fr.yml @@ -0,0 +1,41 @@ +base: + siteTitle: Vocabulaire + search: Rechercher + save: Enregistrer + edit: Modifier + update: Mise à jour + delete: Supprimer + author: Auteur + created: Créé + updated: Mis à jour + actions: Actions + 'Hello, %name%': Bonjour, %name%! + +user: + signup: Inscription + login: Connexion + logout: Déconnexion + loggedin: Vous êtes connecté. + profile: + title: Mon profil + +wishlist: + title: Liste de souhaits + add: Ajouter à la liste d'envies + remove: Supprimer de la liste + +word: + titleOne: Mot + titleMany: Mots + new: Ajouter un nouveau mot + edit: Modifier le mot + +Email: Courriel +Username: Nom d'utilisateur +Password: Mot de passe +Repeat Password: Répétez le mot de passe +First name: Prénom +Last name: Nom Prénom + +Next: false +Previous: false diff --git a/src/AppBundle/Resources/translations/messages.ru.yml b/src/AppBundle/Resources/translations/messages.ru.yml new file mode 100644 index 0000000..2708317 --- /dev/null +++ b/src/AppBundle/Resources/translations/messages.ru.yml @@ -0,0 +1,41 @@ +base: + siteTitle: Словарь + search: Поиск + save: Сохранить + edit: Редактировать + update: Обновить + delete: Удалить + author: Автор + created: Создано + updated: Обновлено + actions: Действия + 'Hello,% name%': Привет, % name%! + +user: + signup: Зарегистрироваться + login: Вход + logout: Выход + loggedin: Вы вошли в систему. + profile: + title: Мой профиль + +wishlist: + title: Список желаний + add: Добавить в список желаний + remove: Удалить из списка желаний + +word: + titleOne: Слово + titleMany: Слова + new: Добавить новое слово + edit: Изменить слово + +Email: Электронная почта +Username: Имя пользователя +Password: Пароль +Repeat Password: Повторить пароль +First name: Имя +Last name: Фамилия + +Next: false +Previous: false diff --git a/src/AppBundle/Resources/translations/messages.uk.yml b/src/AppBundle/Resources/translations/messages.uk.yml new file mode 100644 index 0000000..f9d7561 --- /dev/null +++ b/src/AppBundle/Resources/translations/messages.uk.yml @@ -0,0 +1,41 @@ +base: + siteTitle: Словник + search: Пошук + save: Зберегти + edit: Редагувати + update: Оновити + delete: Видалити + author: Автор + created: Створено + updated: Оновлено + actions: Дії + 'Hello, %name%': Привіт, %name%! + +user: + signup: Зареєструватися + login: Вхід + logout: Вихід + loggedin: Ви увійшли у систему. + profile: + title: Мій профіль + +wishlist: + title: Список бажань + add: Додати до списку бажань + remove: Видалити зі списку бажань + +word: + titleOne: Слово + titleMany: Слова + new: Додати нове слово + edit: Редагувати слово + +Email: Електронна пошта +Username: Ім'я користувача +Password: Пароль +Repeat Password: Повторити пароль +First name: Ім'я +Last name: Прізвище + +Next: false +Previous: false diff --git a/src/AppBundle/Resources/views/base.html.twig b/src/AppBundle/Resources/views/base.html.twig index 2f124c5..09ac0f6 100644 --- a/src/AppBundle/Resources/views/base.html.twig +++ b/src/AppBundle/Resources/views/base.html.twig @@ -4,7 +4,7 @@ - {% block docTitle 'Vocabulary' %} + {% block docTitle %}{{ 'base.siteTitle'|trans }}{% endblock %} {% block head %} {% include 'AppBundle:base:_head.html.twig' %} {% endblock %} diff --git a/src/AppBundle/Resources/views/base/_header.html.twig b/src/AppBundle/Resources/views/base/_header.html.twig index 8a4f465..cf15d0c 100644 --- a/src/AppBundle/Resources/views/base/_header.html.twig +++ b/src/AppBundle/Resources/views/base/_header.html.twig @@ -9,7 +9,7 @@ - Vocabulary + {{ 'base.siteTitle'|trans }} {% include 'AppBundle:default:_navbar_top_links.html.twig' %} @@ -26,9 +26,9 @@ diff --git a/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig b/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig index 5615b38..af52603 100644 --- a/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig +++ b/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig @@ -2,17 +2,29 @@ {% if is_granted('IS_AUTHENTICATED_FULLY') %} {% else %} -
  • Sign Up
  • -
  • Login
  • +
  • {{ 'user.signup'|trans }}
  • +
  • {{ 'user.login'|trans }}
  • {% endif %} + diff --git a/src/AppBundle/Resources/views/user/form.html.twig b/src/AppBundle/Resources/views/user/login.html.twig similarity index 62% rename from src/AppBundle/Resources/views/user/form.html.twig rename to src/AppBundle/Resources/views/user/login.html.twig index 5c44cc0..64b85e1 100644 --- a/src/AppBundle/Resources/views/user/form.html.twig +++ b/src/AppBundle/Resources/views/user/login.html.twig @@ -3,11 +3,15 @@ {% block main %}
    -
    +
    {% if is_granted('IS_AUTHENTICATED_FULLY') %} -

    You are logged in. Logout

    +

    + {{ 'base.Hello, %name%'|trans({'%name%': app.user.userProfile.firstName}) }} + {{ 'user.loggedin'|trans }} + {{ 'user.logout'|trans }} +

    {% else %} -

    {{ formTitle }}

    +

    {{ title }}

    {% if error %}
    diff --git a/src/AppBundle/Resources/views/user/signup.html.twig b/src/AppBundle/Resources/views/user/signup.html.twig new file mode 100644 index 0000000..f5811c6 --- /dev/null +++ b/src/AppBundle/Resources/views/user/signup.html.twig @@ -0,0 +1,26 @@ +{% extends 'AppBundle::base.html.twig' %} + +{% block main %} +
    +
    +
    + {% if is_granted('IS_AUTHENTICATED_FULLY') %} +

    + {{ 'base.Hello, %name%'|trans({'%name%': app.user.userProfile.firstName}) }} + {{ 'user.loggedin'|trans }} + {{ 'user.logout'|trans }} +

    + {% else %} +

    {{ title }}

    + + {{ form_start(form) }} + {{ form_widget(form) }} +
    + +
    + {{ form_end(form) }} + {% endif %} +
    +
    +
    +{% endblock %} diff --git a/src/AppBundle/Resources/views/word/edit.html.twig b/src/AppBundle/Resources/views/word/edit.html.twig new file mode 100644 index 0000000..9ca72fd --- /dev/null +++ b/src/AppBundle/Resources/views/word/edit.html.twig @@ -0,0 +1,18 @@ +{% extends 'AppBundle::base.html.twig' %} + +{% block main %} +
    +
    +
    +

    {{ title }}

    + + {{ form_start(form) }} + {{ form_widget(form) }} +
    + +
    + {{ form_end(form) }} +
    +
    +
    +{% endblock %} diff --git a/src/AppBundle/Resources/views/word/index.html.twig b/src/AppBundle/Resources/views/word/index.html.twig index 550473d..e88cd36 100644 --- a/src/AppBundle/Resources/views/word/index.html.twig +++ b/src/AppBundle/Resources/views/word/index.html.twig @@ -9,19 +9,19 @@

    {{ title }}

    {% if is_granted('create_word', app.user) %} -

    Add new word

    +

    {{ 'word.new'|trans }}

    {% endif %}
    - - - - + + + + {% if is_granted('edit_word', app.user) %} - + {% endif %} @@ -35,14 +35,14 @@ diff --git a/src/AppBundle/Resources/views/default/form.html.twig b/src/AppBundle/Resources/views/word/new.html.twig similarity index 62% rename from src/AppBundle/Resources/views/default/form.html.twig rename to src/AppBundle/Resources/views/word/new.html.twig index aa010ab..57658a7 100644 --- a/src/AppBundle/Resources/views/default/form.html.twig +++ b/src/AppBundle/Resources/views/word/new.html.twig @@ -4,10 +4,13 @@
    -

    {{ formTitle }}

    +

    {{ title }}

    {{ form_start(form) }} {{ form_widget(form) }} +
    + +
    {{ form_end(form) }}
    From 8b0474f4c234845f9f937edb9c3e61400557a0f2 Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Mon, 6 Feb 2017 22:39:16 +0200 Subject: [PATCH 06/13] Added twig filter to translate language switcher (use Intl extension) --- app/config/services.yml | 6 +++++ .../Resources/translations/messages.ru.yml | 2 +- .../views/default/_navbar_top_links.html.twig | 10 +++---- src/AppBundle/Twig/AppExtension.php | 27 +++++++++++++++++++ 4 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 src/AppBundle/Twig/AppExtension.php diff --git a/app/config/services.yml b/app/config/services.yml index c62ba4f..1de76dd 100644 --- a/app/config/services.yml +++ b/app/config/services.yml @@ -14,3 +14,9 @@ services: public: false tags: - { name: security.voter } + + app.twig_extension: + class: AppBundle\Twig\AppExtension + public: false + tags: + - { name: twig.extension } diff --git a/src/AppBundle/Resources/translations/messages.ru.yml b/src/AppBundle/Resources/translations/messages.ru.yml index 2708317..bba1c73 100644 --- a/src/AppBundle/Resources/translations/messages.ru.yml +++ b/src/AppBundle/Resources/translations/messages.ru.yml @@ -9,7 +9,7 @@ base: created: Создано updated: Обновлено actions: Действия - 'Hello,% name%': Привет, % name%! + 'Hello, %name%': Привет, %name%! user: signup: Зарегистрироваться diff --git a/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig b/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig index af52603..e5827e7 100644 --- a/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig +++ b/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig @@ -20,11 +20,11 @@ diff --git a/src/AppBundle/Twig/AppExtension.php b/src/AppBundle/Twig/AppExtension.php new file mode 100644 index 0000000..9668f40 --- /dev/null +++ b/src/AppBundle/Twig/AppExtension.php @@ -0,0 +1,27 @@ +getLocaleName($locale); + + return $localeName; + } + + public function getName() + { + return 'app_extension'; + } +} From 17ac5d0ae468abce2f653fe50d94f492e02a578e Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Tue, 7 Feb 2017 03:11:55 +0200 Subject: [PATCH 07/13] Translated database content (used: KnpBehaviorsBundle + A2lixTranslationFormBundle) --- app/AppKernel.php | 2 + app/config/config.yml | 16 ++- composer.json | 4 +- composer.lock | 136 +++++++++++++++++- src/AppBundle/DataFixtures/ORM/fixtures.yml | 10 +- src/AppBundle/Entity/Word.php | 72 +++++----- src/AppBundle/Entity/WordTranslation.php | 52 +++++++ src/AppBundle/Form/WordType.php | 15 +- .../Resources/views/word/index.html.twig | 12 +- 9 files changed, 266 insertions(+), 53 deletions(-) create mode 100644 src/AppBundle/Entity/WordTranslation.php diff --git a/app/AppKernel.php b/app/AppKernel.php index 74597b1..91a77c6 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -18,6 +18,8 @@ public function registerBundles() new AppBundle\AppBundle(), new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(), new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(), + new Knp\DoctrineBehaviors\Bundle\DoctrineBehaviorsBundle(), + new A2lix\TranslationFormBundle\A2lixTranslationFormBundle(), ]; if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { diff --git a/app/config/config.yml b/app/config/config.yml index 5c6c7c6..5b384b1 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -52,10 +52,10 @@ doctrine: dbname: "%database_name%" user: "%database_user%" password: "%database_password%" - charset: utf8mb4 + charset: utf8 default_table_options: - charset: utf8mb4 - collate: utf8mb4_unicode_ci + charset: utf8 + collate: utf8_general_ci # if using pdo_sqlite as your database driver: # 1. add the path in parameters.yml # e.g. database_path: "%kernel.root_dir%/../var/data/data.sqlite" @@ -83,6 +83,16 @@ stof_doctrine_extensions: default: timestampable: true +knp_doctrine_behaviors: + translatable: true + +a2lix_translation_form: + locale_provider: default + locales: [en, uk, ru, fr, es] + default_locale: en + required_locales: [en] + templating: "A2lixTranslationFormBundle::default.html.twig" + knp_paginator: page_range: 5 # default page range used in pagination control default_options: diff --git a/composer.json b/composer.json index 72a62a7..365d204 100644 --- a/composer.json +++ b/composer.json @@ -29,7 +29,9 @@ "sensio/framework-extra-bundle": "^3.0.2", "incenteev/composer-parameter-handler": "^2.0", "stof/doctrine-extensions-bundle": "^1.2", - "knplabs/knp-paginator-bundle": "^2.5" + "knplabs/knp-paginator-bundle": "^2.5", + "knplabs/doctrine-behaviors": "~1.1", + "a2lix/translation-form-bundle": "^2.1" }, "require-dev": { "sensio/generator-bundle": "^3.0", diff --git a/composer.lock b/composer.lock index 6df39a8..c9da76a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,75 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "23ccd7418d03cdee7337d5ec74aa786f", - "content-hash": "89cd2ff4948e7648e6f33d8d75c319b9", + "hash": "71dbd87d7df943996ea5ecb2c794d4f9", + "content-hash": "5cc0904e75af628b056c0076e12f7c77", "packages": [ + { + "name": "a2lix/translation-form-bundle", + "version": "2.1.2", + "target-dir": "A2lix/TranslationFormBundle", + "source": { + "type": "git", + "url": "https://github.com/a2lix/TranslationFormBundle.git", + "reference": "a04a8db282caabc084cf9fcccd82d2fcfbee36af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/a2lix/TranslationFormBundle/zipball/a04a8db282caabc084cf9fcccd82d2fcfbee36af", + "reference": "a04a8db282caabc084cf9fcccd82d2fcfbee36af", + "shasum": "" + }, + "require": { + "symfony/symfony": ">=2.3" + }, + "require-dev": { + "doctrine/common": "~2.3", + "gedmo/doctrine-extensions": "~2.4", + "knplabs/doctrine-behaviors": "1.0.*", + "phpunit/phpunit": "~4.1" + }, + "suggest": { + "a2lix/i18n-doctrine-bundle": "For A2lix strategy", + "gedmo/doctrine-extensions": "For Gedmo strategy", + "knplabs/doctrine-behaviors": "For Knp strategy", + "prezent/doctrine-translatable-bundle": "For Prezent strategy" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-0": { + "A2lix\\TranslationFormBundle": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "David ALLIX", + "homepage": "http://a2lix.fr" + } + ], + "description": "Translate your doctrine objects easily with some helps", + "homepage": "https://github.com/a2lix/TranslationFormBundle", + "keywords": [ + "Symfony2", + "doctrine2", + "form", + "gedmo", + "i18n", + "internationalization", + "knplabs", + "translatable", + "translation" + ], + "time": "2016-04-11 12:49:49" + }, { "name": "behat/transliterator", "version": "v1.1.0", @@ -996,6 +1062,72 @@ ], "time": "2014-01-12 16:20:24" }, + { + "name": "knplabs/doctrine-behaviors", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/KnpLabs/DoctrineBehaviors.git", + "reference": "c41433f5519d791d2fbdb2164633035c173b9db1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/KnpLabs/DoctrineBehaviors/zipball/c41433f5519d791d2fbdb2164633035c173b9db1", + "reference": "c41433f5519d791d2fbdb2164633035c173b9db1", + "shasum": "" + }, + "require": { + "behat/transliterator": "~1.0", + "doctrine/common": ">=2.2", + "php": ">=5.4" + }, + "require-dev": { + "doctrine/orm": ">=2.2", + "ext-pdo_mysql": "*", + "ext-pdo_pgsql": "*", + "ext-pdo_sqlite": "*", + "hexmedia/yaml-linter": "~0.1", + "jakub-onderka/php-parallel-lint": "~0.8", + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "symfony/framework-bundle": "To be able to use it as a bundle" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Knp\\DoctrineBehaviors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Knplabs", + "homepage": "http://knplabs.com" + } + ], + "description": "Doctrine2 behavior traits", + "homepage": "http://knplabs.com", + "keywords": [ + "Blameable", + "behaviors", + "doctrine2", + "filterable", + "softdeletable", + "timestampable", + "translatable", + "tree" + ], + "time": "2016-09-30 06:03:12" + }, { "name": "knplabs/knp-components", "version": "1.3.4", diff --git a/src/AppBundle/DataFixtures/ORM/fixtures.yml b/src/AppBundle/DataFixtures/ORM/fixtures.yml index 581da2a..853f7a0 100644 --- a/src/AppBundle/DataFixtures/ORM/fixtures.yml +++ b/src/AppBundle/DataFixtures/ORM/fixtures.yml @@ -1,7 +1,6 @@ AppBundle\Entity\User: userAdminDefault1: userProfile (unique): '@uProfile1' - #wishlist (unique): '@wishlist1' username (unique): admin password: admin email: admin@example.com @@ -10,7 +9,6 @@ AppBundle\Entity\User: dateUpdated: '' userDefault2: userProfile (unique): '@uProfile2' - #wishlist (unique): '@wishlist2' username (unique): user password: user email: user@example.com @@ -19,7 +17,6 @@ AppBundle\Entity\User: dateUpdated: '' user{3..12}: userProfile (unique): '@uProfile' - #wishlist (unique): '@wishlist' username (unique): '' password: '' email (unique): '' @@ -37,10 +34,15 @@ AppBundle\Entity\UserProfile: AppBundle\Entity\Word: word{1..30}: user: '@user*' - word: '' dateCreated: '' dateUpdated: '' +AppBundle\Entity\WordTranslation: + wTranslation{1..150}: + translatable: '@word*' + word: '' + locale: '' + AppBundle\Entity\Wishlist: wishlist1: words: ['@word*'] diff --git a/src/AppBundle/Entity/Word.php b/src/AppBundle/Entity/Word.php index 6aaad4d..f810c0a 100644 --- a/src/AppBundle/Entity/Word.php +++ b/src/AppBundle/Entity/Word.php @@ -3,27 +3,29 @@ namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; -use Gedmo\Mapping\Annotation as Gedmo; +use Knp\DoctrineBehaviors\Model as ORMBehaviors; use Symfony\Component\Validator\Constraints as Assert; /** - * Post + * Word * * @ORM\Table(name="word") * @ORM\Entity(repositoryClass="AppBundle\Repository\WordRepository") */ class Word extends BaseSuperClass { - /** - * @var string - * - * @ORM\Column(name="word", type="string", length=150) - * - * @Assert\NotBlank() - * @Assert\Type("string") - * @Assert\Length(min="3", max="150") - */ - private $word; + use ORMBehaviors\Translatable\Translatable; + +// /** +// * @var string +// * +// * @ORM\Column(name="word", type="string", length=150) +// * +// * @Assert\NotBlank() +// * @Assert\Type("string") +// * @Assert\Length(min="3", max="150") +// */ +// private $word; /** * @var User @@ -47,29 +49,29 @@ public function __construct() $this->wishlists = new \Doctrine\Common\Collections\ArrayCollection(); } - /** - * Set word - * - * @param string $word - * - * @return Word - */ - public function setWord($word) - { - $this->word = $word; - - return $this; - } - - /** - * Get word - * - * @return string - */ - public function getWord() - { - return $this->word; - } +// /** +// * Set word +// * +// * @param string $word +// * +// * @return Word +// */ +// public function setWord($word) +// { +// $this->word = $word; +// +// return $this; +// } +// +// /** +// * Get word +// * +// * @return string +// */ +// public function getWord() +// { +// return $this->word; +// } /** * Set user diff --git a/src/AppBundle/Entity/WordTranslation.php b/src/AppBundle/Entity/WordTranslation.php new file mode 100644 index 0000000..e4d3bc0 --- /dev/null +++ b/src/AppBundle/Entity/WordTranslation.php @@ -0,0 +1,52 @@ +word = $word; + + return $this; + } + + /** + * Get word + * + * @return string + */ + public function getWord() + { + return $this->word; + } +} diff --git a/src/AppBundle/Form/WordType.php b/src/AppBundle/Form/WordType.php index 2012f5c..85284f0 100644 --- a/src/AppBundle/Form/WordType.php +++ b/src/AppBundle/Form/WordType.php @@ -4,12 +4,11 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\Extension\Core\Type\SubmitType; -use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; +use A2lix\TranslationFormBundle\Form\Type\TranslationsType; class WordType extends AbstractType { @@ -25,10 +24,14 @@ public function buildForm(FormBuilderInterface $builder, array $options) { $this->authorizationChecker = $options['authorizationChecker']; - $builder - ->add('word', TextType::class, array( - 'label' => 'word.titleOne' - )); + $builder->add('translations', TranslationsType::class, array( + 'label' => false, + 'fields' => array( + 'word' => array( + 'label' => 'word.titleOne' + ) + ) + )); if (isset($this->authorizationChecker) && $this->authorizationChecker->isGranted('ROLE_ADMIN')) { $builder->add('user', EntityType::class, array( diff --git a/src/AppBundle/Resources/views/word/index.html.twig b/src/AppBundle/Resources/views/word/index.html.twig index e88cd36..baf6f06 100644 --- a/src/AppBundle/Resources/views/word/index.html.twig +++ b/src/AppBundle/Resources/views/word/index.html.twig @@ -16,7 +16,11 @@
    WordAuthorCreatedUpdated{{ 'word.titleOne'|trans }}{{ 'base.author'|trans }}{{ 'base.created'|trans }}{{ 'base.updated'|trans }}Actions{{ 'base.actions'|trans }}
    {% if is_granted('edit_word', app.user) %} {% if word in app.user.wishlist.words %} - Remove from wishlist + {{ 'wishlist.remove'|trans }} {% else %} - Add to wishlist + {{ 'wishlist.add'|trans }} {% endif %} - Edit + {{ 'base.edit'|trans }} {% endif %} {% if is_granted('edit', word) %} - Delete + {{ 'base.delete'|trans }} {% endif %}
    - + + + + + @@ -28,7 +32,11 @@ {% for word in pagination %} - + + + + + From 38be5a479602880468228b21c77a982e82127630 Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Tue, 7 Feb 2017 22:54:05 +0200 Subject: [PATCH 08/13] Updated fixtures --- src/AppBundle/DataFixtures/ORM/fixtures.yml | 26 ++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/AppBundle/DataFixtures/ORM/fixtures.yml b/src/AppBundle/DataFixtures/ORM/fixtures.yml index 853f7a0..48e22f7 100644 --- a/src/AppBundle/DataFixtures/ORM/fixtures.yml +++ b/src/AppBundle/DataFixtures/ORM/fixtures.yml @@ -38,10 +38,30 @@ AppBundle\Entity\Word: dateUpdated: '' AppBundle\Entity\WordTranslation: - wTranslation{1..150}: - translatable: '@word*' + wTranslation{1..29}: + translatable: '@word' word: '' - locale: '' + locale: 'en' + wTranslation30en: + translatable: '@word30' + word: 'word' + locale: 'en' + wTranslation30uk: + translatable: '@word30' + word: 'слово' + locale: 'uk' + wTranslation30ru: + translatable: '@word30' + word: 'слово' + locale: 'ru' + wTranslation30fr: + translatable: '@word30' + word: 'mot' + locale: 'fr' + wTranslation30es: + translatable: '@word30' + word: 'palabra' + locale: 'es' AppBundle\Entity\Wishlist: wishlist1: From 3d9ba687450d0167b6a364724371825afb581b6c Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Thu, 9 Feb 2017 00:12:04 +0200 Subject: [PATCH 09/13] Fixed user wishlist. Changed user profile fields to NOT NULL --- app/config/security.yml | 4 ++-- src/AppBundle/Controller/UserController.php | 3 ++- src/AppBundle/Entity/UserProfile.php | 6 ++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/app/config/security.yml b/app/config/security.yml index 75939b4..36199d1 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -35,8 +35,8 @@ security: login_path: login check_path: login logout: - path: /logout - target: /login + path: logout + target: login provider: app_db_provider role_hierarchy: diff --git a/src/AppBundle/Controller/UserController.php b/src/AppBundle/Controller/UserController.php index 871476b..bbe62e3 100644 --- a/src/AppBundle/Controller/UserController.php +++ b/src/AppBundle/Controller/UserController.php @@ -38,9 +38,10 @@ public function signupAction(Request $request) $user->setRoles(array('ROLE_USER')); $wishlist = new Wishlist(); - $user->setWishlist($wishlist); + $wishlist->setUser($user); $em = $this->getDoctrine()->getManager(); + $em->persist($wishlist); $em->persist($user); $em->flush(); diff --git a/src/AppBundle/Entity/UserProfile.php b/src/AppBundle/Entity/UserProfile.php index a6df60e..452643d 100644 --- a/src/AppBundle/Entity/UserProfile.php +++ b/src/AppBundle/Entity/UserProfile.php @@ -16,8 +16,9 @@ class UserProfile extends BaseSuperClass /** * @var string * - * @ORM\Column(name="first_name", type="string", length=45, nullable=true) + * @ORM\Column(name="first_name", type="string", length=45) * + * @Assert\NotBlank() * @Assert\Length(max="45") */ private $firstName; @@ -25,8 +26,9 @@ class UserProfile extends BaseSuperClass /** * @var string * - * @ORM\Column(name="last_name", type="string", length=45, nullable=true) + * @ORM\Column(name="last_name", type="string", length=45) * + * @Assert\NotBlank() * @Assert\Length(max="45") */ private $lastName; From 13a72d3892fd7185a944d24be08ec3ee35092a9a Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Mon, 13 Feb 2017 23:50:59 +0200 Subject: [PATCH 10/13] Added UserController actions: show, edit, delete --- src/AppBundle/Controller/UserController.php | 95 +++++++++++++++++++ src/AppBundle/Entity/User.php | 2 +- src/AppBundle/Entity/Word.php | 40 +------- src/AppBundle/Form/UserType.php | 32 ++++++- .../views/default/_navbar_top_links.html.twig | 2 +- .../Resources/views/user/edit.html.twig | 18 ++++ .../Resources/views/user/show.html.twig | 79 +++++++++++++++ .../Resources/views/word/index.html.twig | 10 +- 8 files changed, 233 insertions(+), 45 deletions(-) create mode 100644 src/AppBundle/Resources/views/user/edit.html.twig create mode 100644 src/AppBundle/Resources/views/user/show.html.twig diff --git a/src/AppBundle/Controller/UserController.php b/src/AppBundle/Controller/UserController.php index bbe62e3..bd5eacd 100644 --- a/src/AppBundle/Controller/UserController.php +++ b/src/AppBundle/Controller/UserController.php @@ -9,8 +9,10 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Component\Finder\Exception\AccessDeniedException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Class UserController. @@ -54,6 +56,99 @@ public function signupAction(Request $request) )); } + /** + * @Route("/users/{id}/{page}", requirements={"id": "\d+", "page": "\d+"}, name="user_show") + * @Method("GET") + * + * @param User $user + * @param int $page + * + * @return Response + */ + public function showAction(User $user, $page = 1) + { + $words = $this->getDoctrine() + ->getRepository('AppBundle:Word') + ->findby(array( + 'user' => $user + )); + + $pagination = $this->get('knp_paginator')->paginate( + $words, $page, 5 + ); + + return $this->render('AppBundle:user:show.html.twig', array( + 'title' => $this->get('translator')->trans('word.titleMany'), + 'user' => $user, + 'pagination' => $pagination + )); + } + + /** + * @Route("/users/{id}/edit", name="user_edit") + * @Method({"GET", "POST"}) + * + * @param Request $request + * @param User $user + * + * @return Response + */ + public function editAction(Request $request, User $user) + { + if ($this->getUser() != $user && !$this->isGranted('ROLE_ADMIN')) { + throw $this->createAccessDeniedException(); + } + + $form = $this->createForm(UserType::class, $user, array( + 'authorizationChecker' => $this->get('security.authorization_checker') + )); + + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { + $userData = $form->getData(); + + if (!empty($user->getPlainPassword())) { + $password = $this->get('security.password_encoder') + ->encodePassword($user, $user->getPlainPassword()); + $user->setPassword($password); + } + + $em = $this->getDoctrine()->getManager(); + $em->persist($userData); + $em->persist($user); + $em->flush(); + + return $this->redirectToRoute('homepage'); + } + + return $this->render('AppBundle:user:edit.html.twig', array( + 'title' => $this->get('translator')->trans('user.profile.title'), + 'form' => $form->createView() + )); + } + + /** + * @Route("/users/{id}/delete", requirements={"id": "\d+"}, name="user_delete") + * @Method({"GET", "POST"}) + * + * @param User $user + * + * @return Response + */ + public function deleteAction(User $user) + { + if (!$this->isGranted('ROLE_ADMIN')) { + throw $this->createAccessDeniedException(); + } + + $em = $this->getDoctrine()->getManager(); + + $em->remove($user); + $em->flush(); + + return $this->redirectToRoute('word_index'); + } + /** * @Route("/login", name="login") * @Method({"GET", "POST"}) diff --git a/src/AppBundle/Entity/User.php b/src/AppBundle/Entity/User.php index 1b92c03..7e3412b 100644 --- a/src/AppBundle/Entity/User.php +++ b/src/AppBundle/Entity/User.php @@ -31,7 +31,7 @@ class User extends BaseSuperClass implements AdvancedUserInterface, \Serializabl /** * @var string * - * @Assert\NotBlank() + * @Assert\NotBlank(groups={"signup"}) * @Assert\Length(min="8", max="4096") */ private $plainPassword; diff --git a/src/AppBundle/Entity/Word.php b/src/AppBundle/Entity/Word.php index f810c0a..d3d6862 100644 --- a/src/AppBundle/Entity/Word.php +++ b/src/AppBundle/Entity/Word.php @@ -16,17 +16,6 @@ class Word extends BaseSuperClass { use ORMBehaviors\Translatable\Translatable; -// /** -// * @var string -// * -// * @ORM\Column(name="word", type="string", length=150) -// * -// * @Assert\NotBlank() -// * @Assert\Type("string") -// * @Assert\Length(min="3", max="150") -// */ -// private $word; - /** * @var User * @@ -41,6 +30,11 @@ class Word extends BaseSuperClass */ private $wishlists; + /** + * @Assert\Valid + */ + protected $translations; + /** * Constructor */ @@ -49,30 +43,6 @@ public function __construct() $this->wishlists = new \Doctrine\Common\Collections\ArrayCollection(); } -// /** -// * Set word -// * -// * @param string $word -// * -// * @return Word -// */ -// public function setWord($word) -// { -// $this->word = $word; -// -// return $this; -// } -// -// /** -// * Get word -// * -// * @return string -// */ -// public function getWord() -// { -// return $this->word; -// } - /** * Set user * diff --git a/src/AppBundle/Form/UserType.php b/src/AppBundle/Form/UserType.php index f38c554..ef0b5b0 100644 --- a/src/AppBundle/Form/UserType.php +++ b/src/AppBundle/Form/UserType.php @@ -4,26 +4,36 @@ use AppBundle\Entity\User; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormInterface; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Form\Extension\Core\Type\EmailType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\Extension\Core\Type\PasswordType; +use Symfony\Component\Security\Core\Authorization\AuthorizationChecker; class UserType extends AbstractType { + /** + * @var AuthorizationChecker + */ + private $authorizationChecker; + /** * {@inheritdoc} */ public function buildForm(FormBuilderInterface $builder, array $options) { + $this->authorizationChecker = $options['authorizationChecker']; + $builder ->add('email', EmailType::class) ->add('username', TextType::class) ->add('plainPassword', RepeatedType::class, array( - 'type' => PasswordType::class, + 'type' => PasswordType::class, 'first_options' => array('label' => 'Password'), 'second_options' => array('label' => 'Repeat Password'), )) @@ -31,6 +41,14 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'label' => false )) ; + + if (isset($this->authorizationChecker) && $this->authorizationChecker->isGranted('ROLE_ADMIN')) { + $builder->add('roles', ChoiceType::class, array( + 'choices' => array('ROLE_ADMIN' => 'ROLE_ADMIN', 'ROLE_USER' => 'ROLE_USER'), + 'expanded' => true, + 'multiple' => true, + )); + } } /** @@ -39,8 +57,16 @@ public function buildForm(FormBuilderInterface $builder, array $options) public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( - 'data_class' => User::class, - 'attr' => array('novalidate' => 'novalidate') + 'data_class' => User::class, + 'attr' => array('novalidate' => 'novalidate'), + 'validation_groups' => function(FormInterface $form) { + if ($form->getData() !== null && null !== $form->getData()->getId()) + { + return array('Default'); + } + return array('Default', 'signup'); + }, + 'authorizationChecker' => null )); } diff --git a/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig b/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig index e5827e7..0057d45 100644 --- a/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig +++ b/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig @@ -5,7 +5,7 @@ {{ 'base.Hello, %name%'|trans({'%name%': app.user.userProfile.firstName}) }}
    {{ 'word.titleOne'|trans }}{{ 'word.titleOne'|trans }} (en){{ 'word.titleOne'|trans }} (uk){{ 'word.titleOne'|trans }} (ru){{ 'word.titleOne'|trans }} (fr){{ 'word.titleOne'|trans }} (es) {{ 'base.author'|trans }} {{ 'base.created'|trans }} {{ 'base.updated'|trans }}
    {{ word.word }}{{ word.translate('en').word }}{{ word.translate('uk').word }}{{ word.translate('ru').word }}{{ word.translate('fr').word }}{{ word.translate('es').word }} {{ word.user.userProfile.firstName }} {{ word.user.userProfile.lastName }} {{ word.dateCreated|date("d.m.Y") }} {{ word.dateUpdated|date("d.m.Y") }}
    + + + + + + + + + + + {% if is_granted('edit_word', app.user) %} + + {% endif %} + + + + {% for word in pagination %} + + + + + + + + + + + + {% endfor %} + +
    {{ 'word.titleOne'|trans }} (en){{ 'word.titleOne'|trans }} (uk){{ 'word.titleOne'|trans }} (ru){{ 'word.titleOne'|trans }} (fr){{ 'word.titleOne'|trans }} (es){{ 'base.author'|trans }}{{ 'base.created'|trans }}{{ 'base.updated'|trans }}{{ 'base.actions'|trans }}
    {{ word.translate('en').word }}{{ word.translate('uk').word }}{{ word.translate('ru').word }}{{ word.translate('fr').word }}{{ word.translate('es').word }}{{ word.user.userProfile.firstName }} {{ word.user.userProfile.lastName }}{{ word.dateCreated|date("d.m.Y") }}{{ word.dateUpdated|date("d.m.Y") }} + {% if is_granted('edit_word', app.user) %} + {% if word in app.user.wishlist.words %} + {{ 'wishlist.remove'|trans }} + {% else %} + {{ 'wishlist.add'|trans }} + {% endif %} + {{ 'base.edit'|trans }} + {% endif %} + {% if is_granted('edit', word) %} + {{ 'base.delete'|trans }} + {% endif %} +
    +
    + +
    + +
    + {{ knp_pagination_render(pagination) }} +
    + +
    +
    +{% endblock %} diff --git a/src/AppBundle/Resources/views/word/index.html.twig b/src/AppBundle/Resources/views/word/index.html.twig index baf6f06..58ef242 100644 --- a/src/AppBundle/Resources/views/word/index.html.twig +++ b/src/AppBundle/Resources/views/word/index.html.twig @@ -37,20 +37,20 @@ {{ word.translate('ru').word }} {{ word.translate('fr').word }} {{ word.translate('es').word }} - {{ word.user.userProfile.firstName }} {{ word.user.userProfile.lastName }} + {{ word.user.userProfile.firstName }} {{ word.user.userProfile.lastName }} {{ word.dateCreated|date("d.m.Y") }} {{ word.dateUpdated|date("d.m.Y") }} {% if is_granted('edit_word', app.user) %} {% if word in app.user.wishlist.words %} - {{ 'wishlist.remove'|trans }} + {{ 'wishlist.remove'|trans }} {% else %} - {{ 'wishlist.add'|trans }} + {{ 'wishlist.add'|trans }} {% endif %} - {{ 'base.edit'|trans }} + {{ 'base.edit'|trans }} {% endif %} {% if is_granted('edit', word) %} - {{ 'base.delete'|trans }} + {{ 'base.delete'|trans }} {% endif %} From aa59e0a3a271387c7b695ede2004e3c9c1d24ca0 Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Sat, 18 Feb 2017 16:49:24 +0200 Subject: [PATCH 11/13] Remove StofDoctrineBundle. General improvements --- README.md | 6 + app/AppKernel.php | 1 - app/config/config.yml | 8 +- composer.json | 1 - composer.lock | 144 +----------------- src/AppBundle/DataFixtures/ORM/fixtures.yml | 32 ++-- src/AppBundle/Entity/BaseSuperClass.php | 72 +-------- src/AppBundle/Entity/User.php | 6 +- src/AppBundle/Form/WordType.php | 2 +- src/AppBundle/Repository/WordRepository.php | 4 +- .../Resources/translations/messages.en.yml | 4 + .../Resources/views/user/show.html.twig | 6 +- .../Resources/views/word/index.html.twig | 4 +- 13 files changed, 43 insertions(+), 247 deletions(-) diff --git a/README.md b/README.md index 98ecebb..db16153 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,12 @@ $ composer install $ php bin/console doctrine:fixtures:load ``` +####Default users: +login: admin
    +password: admin + +login: user
    +password: user Homework 14: Vocabulary ========== diff --git a/app/AppKernel.php b/app/AppKernel.php index 91a77c6..0760d7d 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -16,7 +16,6 @@ public function registerBundles() new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new AppBundle\AppBundle(), - new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(), new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(), new Knp\DoctrineBehaviors\Bundle\DoctrineBehaviorsBundle(), new A2lix\TranslationFormBundle\A2lixTranslationFormBundle(), diff --git a/app/config/config.yml b/app/config/config.yml index 5b384b1..85613be 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -76,15 +76,9 @@ swiftmailer: password: "%mailer_password%" spool: { type: memory } -# StofDoctrineExtensionsBundle Configuration -stof_doctrine_extensions: - default_locale: en_US - orm: - default: - timestampable: true - knp_doctrine_behaviors: translatable: true + timestampable: true a2lix_translation_form: locale_provider: default diff --git a/composer.json b/composer.json index 365d204..9ae9ecb 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,6 @@ "sensio/distribution-bundle": "^5.0", "sensio/framework-extra-bundle": "^3.0.2", "incenteev/composer-parameter-handler": "^2.0", - "stof/doctrine-extensions-bundle": "^1.2", "knplabs/knp-paginator-bundle": "^2.5", "knplabs/doctrine-behaviors": "~1.1", "a2lix/translation-form-bundle": "^2.1" diff --git a/composer.lock b/composer.lock index c9da76a..e23d6ed 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "71dbd87d7df943996ea5ecb2c794d4f9", - "content-hash": "5cc0904e75af628b056c0076e12f7c77", + "hash": "a0b8098c3300bc0cf6d88fb3caab38b4", + "content-hash": "fcdb31d7b819cb68a9d12495c93c36ba", "packages": [ { "name": "a2lix/translation-form-bundle", @@ -882,85 +882,6 @@ ], "time": "2016-12-18 15:42:34" }, - { - "name": "gedmo/doctrine-extensions", - "version": "v2.4.26", - "source": { - "type": "git", - "url": "https://github.com/Atlantic18/DoctrineExtensions.git", - "reference": "983dd85d6860f87fb7dffd0d9f7ad1462e20a09d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Atlantic18/DoctrineExtensions/zipball/983dd85d6860f87fb7dffd0d9f7ad1462e20a09d", - "reference": "983dd85d6860f87fb7dffd0d9f7ad1462e20a09d", - "shasum": "" - }, - "require": { - "behat/transliterator": "~1.0", - "doctrine/common": "~2.4", - "php": ">=5.3.2" - }, - "require-dev": { - "doctrine/common": ">=2.5.0", - "doctrine/mongodb-odm": ">=1.0.2", - "doctrine/orm": ">=2.5.0", - "phpunit/phpunit": "~4.4", - "phpunit/phpunit-mock-objects": "~2.3", - "symfony/yaml": "~2.6" - }, - "suggest": { - "doctrine/mongodb-odm": "to use the extensions with the MongoDB ODM", - "doctrine/orm": "to use the extensions with the ORM" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.4.x-dev" - } - }, - "autoload": { - "psr-0": { - "Gedmo\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "David Buchmann", - "email": "david@liip.ch" - }, - { - "name": "Gediminas Morkevicius", - "email": "gediminas.morkevicius@gmail.com" - }, - { - "name": "Gustavo Falco", - "email": "comfortablynumb84@gmail.com" - } - ], - "description": "Doctrine2 behavioral extensions", - "homepage": "http://gediminasm.org/", - "keywords": [ - "Blameable", - "behaviors", - "doctrine2", - "extensions", - "gedmo", - "loggable", - "nestedset", - "sluggable", - "sortable", - "timestampable", - "translatable", - "tree", - "uploadable" - ], - "time": "2016-12-21 13:46:54" - }, { "name": "incenteev/composer-parameter-handler", "version": "v2.1.2", @@ -1643,67 +1564,6 @@ "description": "A security checker for your composer.lock", "time": "2016-09-23 18:09:57" }, - { - "name": "stof/doctrine-extensions-bundle", - "version": "v1.2.2", - "source": { - "type": "git", - "url": "https://github.com/stof/StofDoctrineExtensionsBundle.git", - "reference": "4e7499d25dc5d0862da09fa8e336164948a29a25" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/stof/StofDoctrineExtensionsBundle/zipball/4e7499d25dc5d0862da09fa8e336164948a29a25", - "reference": "4e7499d25dc5d0862da09fa8e336164948a29a25", - "shasum": "" - }, - "require": { - "gedmo/doctrine-extensions": "^2.3.1", - "php": ">=5.3.2", - "symfony/framework-bundle": "~2.1|~3.0" - }, - "suggest": { - "doctrine/doctrine-bundle": "to use the ORM extensions", - "doctrine/mongodb-odm-bundle": "to use the MongoDB ODM extensions" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "psr-4": { - "Stof\\DoctrineExtensionsBundle\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Christophe Coevoet", - "email": "stof@notk.org" - } - ], - "description": "Integration of the gedmo/doctrine-extensions with Symfony2", - "homepage": "https://github.com/stof/StofDoctrineExtensionsBundle", - "keywords": [ - "behaviors", - "doctrine2", - "extensions", - "gedmo", - "loggable", - "nestedset", - "sluggable", - "sortable", - "timestampable", - "translatable", - "tree" - ], - "time": "2016-01-26 23:58:32" - }, { "name": "swiftmailer/swiftmailer", "version": "v5.4.5", diff --git a/src/AppBundle/DataFixtures/ORM/fixtures.yml b/src/AppBundle/DataFixtures/ORM/fixtures.yml index 48e22f7..692ce1c 100644 --- a/src/AppBundle/DataFixtures/ORM/fixtures.yml +++ b/src/AppBundle/DataFixtures/ORM/fixtures.yml @@ -5,37 +5,37 @@ AppBundle\Entity\User: password: admin email: admin@example.com roles: ["ROLE_ADMIN"] - dateCreated: '' - dateUpdated: '' + createdAt: '' + updatedAt: '' userDefault2: userProfile (unique): '@uProfile2' username (unique): user password: user email: user@example.com roles: ["ROLE_USER"] - dateCreated: '' - dateUpdated: '' + createdAt: '' + updatedAt: '' user{3..12}: userProfile (unique): '@uProfile' username (unique): '' password: '' email (unique): '' roles: '' - dateCreated: '' - dateUpdated: '' + createdAt: '' + updatedAt: '' AppBundle\Entity\UserProfile: uProfile{1..12}: firstName: '' lastName: '' - dateCreated: '' - dateUpdated: '' + createdAt: '' + updatedAt: '' AppBundle\Entity\Word: word{1..30}: user: '@user*' - dateCreated: '' - dateUpdated: '' + createdAt: '' + updatedAt: '' AppBundle\Entity\WordTranslation: wTranslation{1..29}: @@ -67,15 +67,15 @@ AppBundle\Entity\Wishlist: wishlist1: words: ['@word*'] user: '@userAdminDefault1' - dateCreated: '' - dateUpdated: '' + createdAt: '' + updatedAt: '' wishlist2: words: ['@word*'] user: '@userDefault2' - dateCreated: '' - dateUpdated: '' + createdAt: '' + updatedAt: '' wishlist{3..12}: words: ['@word*'] user (unique): '@user' - dateCreated: '' - dateUpdated: '' + createdAt: '' + updatedAt: '' diff --git a/src/AppBundle/Entity/BaseSuperClass.php b/src/AppBundle/Entity/BaseSuperClass.php index 4bdaaef..988b80f 100644 --- a/src/AppBundle/Entity/BaseSuperClass.php +++ b/src/AppBundle/Entity/BaseSuperClass.php @@ -3,7 +3,7 @@ namespace AppBundle\Entity; use Doctrine\ORM\Mapping as ORM; -use Gedmo\Mapping\Annotation as Gedmo; +use Knp\DoctrineBehaviors\Model as ORMBehaviors; use Symfony\Component\Validator\Constraints as Assert; /** @@ -13,6 +13,8 @@ */ abstract class BaseSuperClass { + use ORMBehaviors\Timestampable\Timestampable; + /** * @var int * @@ -22,26 +24,6 @@ abstract class BaseSuperClass */ protected $id; - /** - * @var \DateTime - * - * @ORM\Column(type="datetime") - * @Gedmo\Timestampable(on="create") - * - * @Assert\DateTime() - */ - private $dateCreated; - - /** - * @var \DateTime - * - * @ORM\Column(type="datetime") - * @Gedmo\Timestampable(on="update") - * - * @Assert\DateTime() - */ - private $dateUpdated; - /** * Get id * @@ -51,52 +33,4 @@ public function getId() { return $this->id; } - - /** - * Set dateCreated - * - * @param \DateTime $dateCreated - * - * @return BaseSuperClass - */ - public function setDateCreated($dateCreated) - { - $this->dateCreated = $dateCreated; - - return $this; - } - - /** - * Get dateCreated - * - * @return \DateTime - */ - public function getDateCreated() - { - return $this->dateCreated; - } - - /** - * Set dateUpdated - * - * @param \DateTime $dateUpdated - * - * @return BaseSuperClass - */ - public function setDateUpdated($dateUpdated) - { - $this->dateUpdated = $dateUpdated; - - return $this; - } - - /** - * Get dateUpdated - * - * @return \DateTime - */ - public function getDateUpdated() - { - return $this->dateUpdated; - } } diff --git a/src/AppBundle/Entity/User.php b/src/AppBundle/Entity/User.php index 7e3412b..797aad4 100644 --- a/src/AppBundle/Entity/User.php +++ b/src/AppBundle/Entity/User.php @@ -71,7 +71,7 @@ class User extends BaseSuperClass implements AdvancedUserInterface, \Serializabl /** * @var UserProfile * - * @ORM\OneToOne(targetEntity="UserProfile", cascade={"persist"}) + * @ORM\OneToOne(targetEntity="UserProfile", cascade={"persist", "remove"}) * * @Assert\Valid */ @@ -80,14 +80,14 @@ class User extends BaseSuperClass implements AdvancedUserInterface, \Serializabl /** * @var Wishlist * - * @ORM\OneToOne(targetEntity="Wishlist", mappedBy="user", cascade={"persist"}) + * @ORM\OneToOne(targetEntity="Wishlist", mappedBy="user", cascade={"persist", "remove"}) */ private $wishlist; /** * @var \Doctrine\Common\Collections\ArrayCollection * - * @ORM\OneToMany(targetEntity="Word", mappedBy="user") + * @ORM\OneToMany(targetEntity="Word", mappedBy="user", cascade={"remove"}) */ private $words; diff --git a/src/AppBundle/Form/WordType.php b/src/AppBundle/Form/WordType.php index 85284f0..280557e 100644 --- a/src/AppBundle/Form/WordType.php +++ b/src/AppBundle/Form/WordType.php @@ -36,7 +36,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) if (isset($this->authorizationChecker) && $this->authorizationChecker->isGranted('ROLE_ADMIN')) { $builder->add('user', EntityType::class, array( 'class' => 'AppBundle:User', - 'choice_label' => 'userProfile.firstName userProfile.lastName', + 'choice_label' => 'username', 'label' => 'base.author' )); } diff --git a/src/AppBundle/Repository/WordRepository.php b/src/AppBundle/Repository/WordRepository.php index b8c40f4..4b57631 100644 --- a/src/AppBundle/Repository/WordRepository.php +++ b/src/AppBundle/Repository/WordRepository.php @@ -13,7 +13,7 @@ class WordRepository extends \Doctrine\ORM\EntityRepository public function findAllWords() { $query = $this->createQueryBuilder('w') - ->orderBy('w.dateCreated', 'DESC') + ->orderBy('w.createdAt', 'DESC') ; return $query; @@ -29,7 +29,7 @@ public function findAllByWishlist($wishlistId) $query = $this->createQueryBuilder('word') ->innerJoin('word.wishlists', 'w', 'WITH', 'w.id = :wishlistId') ->setParameter('wishlistId', $wishlistId) - ->orderBy('word.dateCreated', 'DESC') + ->orderBy('word.createdAt', 'DESC') ; return $query; diff --git a/src/AppBundle/Resources/translations/messages.en.yml b/src/AppBundle/Resources/translations/messages.en.yml index ebc997b..aac357c 100644 --- a/src/AppBundle/Resources/translations/messages.en.yml +++ b/src/AppBundle/Resources/translations/messages.en.yml @@ -39,3 +39,7 @@ Last name: Last name Next: false Previous: false + +Roles: Roles +ROLE_ADMIN: ROLE_ADMIN +ROLE_USER: ROLE_USER diff --git a/src/AppBundle/Resources/views/user/show.html.twig b/src/AppBundle/Resources/views/user/show.html.twig index 040bd5d..34c6726 100644 --- a/src/AppBundle/Resources/views/user/show.html.twig +++ b/src/AppBundle/Resources/views/user/show.html.twig @@ -6,7 +6,7 @@

    {{ user.userProfile.firstName }} {{ user.userProfile.lastName }}

    - {% if app.user.id == user.id or is_granted('ROLE_ADMIN') %} + {% if is_granted('IS_AUTHENTICATED_FULLY') and (app.user.id == user.id or is_granted('ROLE_ADMIN')) %}

    {{ 'base.edit'|trans }}

    {% endif %} {% if is_granted('ROLE_ADMIN') %} @@ -47,8 +47,8 @@ {{ word.translate('fr').word }} {{ word.translate('es').word }} {{ word.user.userProfile.firstName }} {{ word.user.userProfile.lastName }} - {{ word.dateCreated|date("d.m.Y") }} - {{ word.dateUpdated|date("d.m.Y") }} + {{ word.createdAt|date("d.m.Y") }} + {{ word.updatedAt|date("d.m.Y") }} {% if is_granted('edit_word', app.user) %} {% if word in app.user.wishlist.words %} diff --git a/src/AppBundle/Resources/views/word/index.html.twig b/src/AppBundle/Resources/views/word/index.html.twig index 58ef242..9d38fe0 100644 --- a/src/AppBundle/Resources/views/word/index.html.twig +++ b/src/AppBundle/Resources/views/word/index.html.twig @@ -38,8 +38,8 @@ {{ word.translate('fr').word }} {{ word.translate('es').word }} {{ word.user.userProfile.firstName }} {{ word.user.userProfile.lastName }} - {{ word.dateCreated|date("d.m.Y") }} - {{ word.dateUpdated|date("d.m.Y") }} + {{ word.createdAt|date("d.m.Y") }} + {{ word.updatedAt|date("d.m.Y") }} {% if is_granted('edit_word', app.user) %} {% if word in app.user.wishlist.words %} From 1f4311b1808807383d8d3bfbd72ee36b2aa8bfed Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Mon, 20 Feb 2017 02:15:00 +0200 Subject: [PATCH 12/13] Added tests --- README.md | 11 +- app/config/config_test.yml | 5 + bin/console | 0 bin/symfony_requirements | 0 composer.json | 3 +- composer.lock | 1247 ++++++++++++++++- src/AppBundle/Repository/WordRepository.php | 4 +- .../ApplicationAvailabilityFunctionalTest.php | 59 + .../Controller/DefaultControllerTest.php | 18 - .../Controller/WordControllerTest.php | 111 ++ 10 files changed, 1410 insertions(+), 48 deletions(-) mode change 100755 => 100644 bin/console mode change 100755 => 100644 bin/symfony_requirements create mode 100644 tests/AppBundle/Controller/ApplicationAvailabilityFunctionalTest.php delete mode 100644 tests/AppBundle/Controller/DefaultControllerTest.php create mode 100644 tests/AppBundle/Controller/WordControllerTest.php diff --git a/README.md b/README.md index db16153..3011eb9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -Geekhub PHP HomeWork#14: Symfony Vocabulary Application - Translations +Geekhub PHP HomeWork#16: Symfony Vocabulary Application - Tests = ####EER Diagram: @@ -7,12 +7,17 @@ https://docs.google.com/drawings/d/1gXIQH6vCcoeqFa2ess2fpVgOADpIkfmPAOGW7HD2LCs/ ####Setup: -Note: Before continue, install Node.js. +Setup database in "app/config/parameters.yml". + +Note: Before continue, install Node.js.
    +Note 2: "composer install" runs commands "npm i" and "./node_modules/.bin/bower install" ```bash -$ git clone -b hw14-andrey-lukashenko https://github.com/AndreyLuka/geekhub-php-vocabulary.git +$ git clone -b hw16-andrey-lukashenko https://github.com/AndreyLuka/geekhub-php-vocabulary.git $ cd geekhub-php-vocabulary $ composer install +$ php bin/console doctrine:database:create +$ php bin/console doctrine:schema:create $ php bin/console doctrine:fixtures:load ``` diff --git a/app/config/config_test.yml b/app/config/config_test.yml index 2f6d925..6beda7d 100644 --- a/app/config/config_test.yml +++ b/app/config/config_test.yml @@ -14,3 +14,8 @@ web_profiler: swiftmailer: disable_delivery: true + +security: + firewalls: + main: + http_basic: ~ diff --git a/bin/console b/bin/console old mode 100755 new mode 100644 diff --git a/bin/symfony_requirements b/bin/symfony_requirements old mode 100755 new mode 100644 diff --git a/composer.json b/composer.json index 9ae9ecb..9d21441 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,8 @@ "sensio/generator-bundle": "^3.0", "symfony/phpunit-bridge": "^3.0", "nelmio/alice": "2.1.4", - "doctrine/doctrine-fixtures-bundle": "^2.3" + "doctrine/doctrine-fixtures-bundle": "^2.3", + "phpunit/phpunit": "5.7.9" }, "scripts": { "symfony-scripts": [ diff --git a/composer.lock b/composer.lock index e23d6ed..5bafff9 100644 --- a/composer.lock +++ b/composer.lock @@ -2444,29 +2444,932 @@ ], "time": "2016-04-29 12:21:54" }, + { + "name": "myclabs/deep-copy", + "version": "1.6.0", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "5a5a9fc8025a08d8919be87d6884d5a92520cefe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/5a5a9fc8025a08d8919be87d6884d5a92520cefe", + "reference": "5a5a9fc8025a08d8919be87d6884d5a92520cefe", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2017-01-26 22:05:40" + }, { "name": "nelmio/alice", "version": "2.1.4", "source": { "type": "git", - "url": "https://github.com/nelmio/alice.git", - "reference": "c8cb3413ab5d1fa76ee84296dafe356b0c703014" + "url": "https://github.com/nelmio/alice.git", + "reference": "c8cb3413ab5d1fa76ee84296dafe356b0c703014" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nelmio/alice/zipball/c8cb3413ab5d1fa76ee84296dafe356b0c703014", + "reference": "c8cb3413ab5d1fa76ee84296dafe356b0c703014", + "shasum": "" + }, + "require": { + "fzaninotto/faker": "~1.0", + "php": ">=5.4", + "symfony/yaml": "~2.0|~3.0" + }, + "require-dev": { + "doctrine/common": "~2.3", + "phpunit/phpunit": "~4.0", + "symfony/property-access": "~2.2|~3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Nelmio\\Alice\\": "src/Nelmio/Alice" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + }, + { + "name": "Tim Shelburne", + "email": "shelburt02@gmail.com" + } + ], + "description": "Expressive fixtures generator", + "keywords": [ + "Fixture", + "data", + "orm", + "test" + ], + "time": "2016-01-07 14:44:47" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27 11:43:31" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.2.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2016-09-30 07:12:33" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.2.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2016-11-25 06:54:22" + }, + { + "name": "phpspec/prophecy", + "version": "v1.6.2", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "6c52c2722f8460122f96f86346600e1077ce22cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb", + "reference": "6c52c2722f8460122f96f86346600e1077ce22cb", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1", + "sebastian/recursion-context": "^1.0|^2.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.0", + "phpunit/phpunit": "^4.8 || ^5.6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2016-11-21 14:58:47" + }, + { + "name": "phpunit/php-code-coverage", + "version": "4.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "c19cfc7cbb0e9338d8c469c7eedecc2a428b0971" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c19cfc7cbb0e9338d8c469c7eedecc2a428b0971", + "reference": "c19cfc7cbb0e9338d8c469c7eedecc2a428b0971", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "^1.4.2", + "sebastian/code-unit-reverse-lookup": "~1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "~1.0|~2.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.4.0", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2017-01-20 15:06:43" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2016-10-03 07:40:28" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21 13:50:34" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/38e9124049cf1a164f1e4537caf19c99bf1eb260", + "reference": "38e9124049cf1a164f1e4537caf19c99bf1eb260", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4|~5" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2016-05-12 18:03:57" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b", + "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2016-11-15 14:06:22" + }, + { + "name": "phpunit/phpunit", + "version": "5.7.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "69f832b87c731d5cacad7f91948778fe98335fdd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/69f832b87c731d5cacad7f91948778fe98335fdd", + "reference": "69f832b87c731d5cacad7f91948778fe98335fdd", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", + "phpspec/prophecy": "^1.6.2", + "phpunit/php-code-coverage": "^4.0.4", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "~1.2.2", + "sebastian/diff": "~1.2", + "sebastian/environment": "^1.3.4 || ^2.0", + "sebastian/exporter": "~2.0", + "sebastian/global-state": "^1.0 || ^2.0", + "sebastian/object-enumerator": "~2.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "~1.0|~2.0", + "symfony/yaml": "~2.1|~3.0" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-xdebug": "*", + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2017-01-28 06:14:33" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", + "reference": "3ab72b65b39b491e0c011e2e09bb2206c2aa8e24", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2 || ^2.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2016-12-08 20:27:08" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2016-02-13 06:45:14" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-01-29 09:50:25" + }, + { + "name": "sebastian/diff", + "version": "1.4.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", + "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2015-12-08 07:14:41" + }, + { + "name": "sebastian/environment", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-11-26 07:53:53" + }, + { + "name": "sebastian/exporter", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nelmio/alice/zipball/c8cb3413ab5d1fa76ee84296dafe356b0c703014", - "reference": "c8cb3413ab5d1fa76ee84296dafe356b0c703014", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", "shasum": "" }, "require": { - "fzaninotto/faker": "~1.0", - "php": ">=5.4", - "symfony/yaml": "~2.0|~3.0" + "php": ">=5.3.3", + "sebastian/recursion-context": "~2.0" }, "require-dev": { - "doctrine/common": "~2.3", - "phpunit/phpunit": "~4.0", - "symfony/property-access": "~2.2|~3.0" + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" }, "type": "library", "extra": { @@ -2475,32 +3378,278 @@ } }, "autoload": { - "psr-4": { - "Nelmio\\Alice\\": "src/Nelmio/Alice" - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" }, { - "name": "Tim Shelburne", - "email": "shelburt02@gmail.com" + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" } ], - "description": "Expressive fixtures generator", + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", "keywords": [ - "Fixture", - "data", - "orm", - "test" + "export", + "exporter" ], - "time": "2016-01-07 14:44:47" + "time": "2016-11-19 08:54:04" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12 03:26:01" + }, + { + "name": "sebastian/object-enumerator", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35", + "reference": "96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2016-11-19 07:35:10" + }, + { + "name": "sebastian/recursion-context", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2016-11-19 07:33:16" + }, + { + "name": "sebastian/resource-operations", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "shasum": "" + }, + "require": { + "php": ">=5.6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28 20:34:47" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2016-10-03 07:35:21" }, { "name": "sensio/generator-bundle", @@ -2611,6 +3760,56 @@ "description": "Symfony PHPUnit Bridge", "homepage": "https://symfony.com", "time": "2017-01-06 17:19:17" + }, + { + "name": "webmozart/assert", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2016-11-23 20:04:58" } ], "aliases": [], diff --git a/src/AppBundle/Repository/WordRepository.php b/src/AppBundle/Repository/WordRepository.php index 4b57631..b9876e5 100644 --- a/src/AppBundle/Repository/WordRepository.php +++ b/src/AppBundle/Repository/WordRepository.php @@ -8,7 +8,7 @@ class WordRepository extends \Doctrine\ORM\EntityRepository { /** - * @return \Doctrine\ORM\Query + * @return \Doctrine\ORM\QueryBuilder */ public function findAllWords() { @@ -22,7 +22,7 @@ public function findAllWords() /** * @param int $wishlistId * - * @return \Doctrine\ORM\Query + * @return \Doctrine\ORM\QueryBuilder */ public function findAllByWishlist($wishlistId) { diff --git a/tests/AppBundle/Controller/ApplicationAvailabilityFunctionalTest.php b/tests/AppBundle/Controller/ApplicationAvailabilityFunctionalTest.php new file mode 100644 index 0000000..d944c24 --- /dev/null +++ b/tests/AppBundle/Controller/ApplicationAvailabilityFunctionalTest.php @@ -0,0 +1,59 @@ +request('GET', $url); + $this->assertTrue( + $client->getResponse()->isSuccessful(), + sprintf('The %s public URL loads correctly.', $url) + ); + } + + /** + * @dataProvider getSecureUrls + */ + public function testSecureUrls($url) + { + $client = self::createClient(); + + $client->request('GET', $url); + $this->assertTrue($client->getResponse()->isRedirect()); + $this->assertEquals( + 'http://localhost/en/login', + $client->getResponse()->getTargetUrl(), + sprintf('The %s secure URL redirects to the login form.', $url) + ); + } + + public function getPublicUrls() + { + return array( + array('/'), + array('/en/2'), + array('/en/signup'), + array('/en/login'), + array('/en/users/2'), + ); + } + + public function getSecureUrls() + { + return array( + array('/en/users/2/edit'), + array('/en/words/new'), + array('/en/words/1/edit'), + array('/en/wishlist/2'), + ); + } +} diff --git a/tests/AppBundle/Controller/DefaultControllerTest.php b/tests/AppBundle/Controller/DefaultControllerTest.php deleted file mode 100644 index 594803c..0000000 --- a/tests/AppBundle/Controller/DefaultControllerTest.php +++ /dev/null @@ -1,18 +0,0 @@ -request('GET', '/'); - - $this->assertEquals(200, $client->getResponse()->getStatusCode()); - $this->assertContains('Welcome to Symfony', $crawler->filter('#container h1')->text()); - } -} diff --git a/tests/AppBundle/Controller/WordControllerTest.php b/tests/AppBundle/Controller/WordControllerTest.php new file mode 100644 index 0000000..812c216 --- /dev/null +++ b/tests/AppBundle/Controller/WordControllerTest.php @@ -0,0 +1,111 @@ + 'user', + 'PHP_AUTH_PW' => 'user', + ); + + public function testIndex() + { + $client = static::createClient(); + + $crawler = $client->request('GET', '/'); + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertContains('Vocabulary', $crawler->filter('.navbar-brand')->text()); + $this->assertEquals(5, $crawler->filter('table tbody tr')->count(), '5 words per page.'); + } + + public function testNew() + { + $client = static::createClient(array(), $this->defaultUser); + + $crawler = $client->request('GET', '/en/words/new'); + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + + $form = $crawler->filter('form[name=appbundle_word]')->form(); + $crawler = $client->submit($form); + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertRegexp( + '/This value should not be blank/', + $client->getResponse()->getContent() + ); + + $form['appbundle_word[translations][en][word]'] = 'NewWordEn'; + $form['appbundle_word[translations][uk][word]'] = 'NewWordUk'; + $form['appbundle_word[translations][ru][word]'] = 'NewWordRu'; + $form['appbundle_word[translations][fr][word]'] = 'NewWordFr'; + $form['appbundle_word[translations][es][word]'] = 'NewWordEs'; + $crawler = $client->submit($form); + $this->assertTrue($client->getResponse()->isRedirect()); + $client->followRedirect(); + $this->assertContains( + 'NewWordEn', + $client->getResponse()->getContent() + ); + $this->assertContains( + 'NewWordUk', + $client->getResponse()->getContent() + ); + $this->assertContains( + 'NewWordRu', + $client->getResponse()->getContent() + ); + $this->assertContains( + 'NewWordFr', + $client->getResponse()->getContent() + ); + $this->assertContains( + 'NewWordEs', + $client->getResponse()->getContent() + ); + } + + public function testEdit() + { + $client = static::createClient(array(), $this->defaultUser); + + $container = self::$kernel->getContainer(); + $em = $container->get('doctrine')->getManager(); + $word = $em->getRepository('AppBundle:WordTranslation') + ->findOneBy(array('word' => 'NewWordEn')); + + $crawler = $client->request('GET', '/en/words/'.$word->getTranslatable()->getId().'/edit'); + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + + $form = $crawler->filter('form[name=appbundle_word]')->form(); + $form['appbundle_word[translations][en][word]'] = 'NewWordEnEdited'; + $form['appbundle_word[translations][uk][word]'] = 'NewWordUkEdited'; + $form['appbundle_word[translations][ru][word]'] = 'NewWordRuEdited'; + $form['appbundle_word[translations][fr][word]'] = 'NewWordFrEdited'; + $form['appbundle_word[translations][es][word]'] = 'NewWordEsEdited'; + $crawler = $client->submit($form); + $this->assertTrue($client->getResponse()->isRedirect()); + $client->followRedirect(); + $this->assertContains( + 'NewWordEnEdited', + $client->getResponse()->getContent() + ); + $this->assertContains( + 'NewWordUkEdited', + $client->getResponse()->getContent() + ); + $this->assertContains( + 'NewWordRuEdited', + $client->getResponse()->getContent() + ); + $this->assertContains( + 'NewWordFrEdited', + $client->getResponse()->getContent() + ); + $this->assertContains( + 'NewWordEsEdited', + $client->getResponse()->getContent() + ); + } +} From 9241d04d53fa2e73c2b8587170496e089111cd63 Mon Sep 17 00:00:00 2001 From: Andrey Lukashenko Date: Mon, 20 Feb 2017 02:38:50 +0200 Subject: [PATCH 13/13] Fixed permissions --- bin/console | 0 bin/symfony_requirements | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/console mode change 100644 => 100755 bin/symfony_requirements diff --git a/bin/console b/bin/console old mode 100644 new mode 100755 diff --git a/bin/symfony_requirements b/bin/symfony_requirements old mode 100644 new mode 100755