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/README.md b/README.md index 20ae887..3011eb9 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,33 @@ +Geekhub PHP HomeWork#16: Symfony Vocabulary Application - Tests += + +####EER Diagram: + +https://docs.google.com/drawings/d/1gXIQH6vCcoeqFa2ess2fpVgOADpIkfmPAOGW7HD2LCs/edit?usp=sharing + +####Setup: + +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 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 +``` + +####Default users: +login: admin
+password: admin + +login: user
+password: user + Homework 14: Vocabulary ========== diff --git a/app/AppKernel.php b/app/AppKernel.php index 3789b32..0760d7d 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -16,6 +16,9 @@ public function registerBundles() new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new AppBundle\AppBundle(), + new Knp\Bundle\PaginatorBundle\KnpPaginatorBundle(), + new Knp\DoctrineBehaviors\Bundle\DoctrineBehaviorsBundle(), + new A2lix\TranslationFormBundle\A2lixTranslationFormBundle(), ]; if (in_array($this->getEnvironment(), ['dev', 'test'], true)) { @@ -23,6 +26,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/config.yml b/app/config/config.yml index cfb0391..85613be 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -33,11 +33,15 @@ framework: assets: ~ php_errors: log: true + translator: { fallbacks: [en] } + default_locale: en # Twig Configuration twig: debug: "%kernel.debug%" strict_variables: "%kernel.debug%" + form_themes: + - bootstrap_3_layout.html.twig # Doctrine Configuration doctrine: @@ -48,7 +52,10 @@ doctrine: dbname: "%database_name%" user: "%database_user%" password: "%database_password%" - charset: UTF8 + charset: utf8 + default_table_options: + 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" @@ -68,3 +75,25 @@ swiftmailer: username: "%mailer_user%" password: "%mailer_password%" spool: { type: memory } + +knp_doctrine_behaviors: + translatable: true + timestampable: 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: + 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/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/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/app/config/security.yml b/app/config/security.yml index 343eb49..36199d1 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -1,12 +1,20 @@ # 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: 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: @@ -22,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..1de76dd 100644 --- a/app/config/services.yml +++ b/app/config/services.yml @@ -7,3 +7,16 @@ 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 } + + app.twig_extension: + class: AppBundle\Twig\AppExtension + public: false + tags: + - { name: twig.extension } 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 5017df0..9d21441 100644 --- a/composer.json +++ b/composer.json @@ -27,11 +27,17 @@ "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", + "knplabs/knp-paginator-bundle": "^2.5", + "knplabs/doctrine-behaviors": "~1.1", + "a2lix/translation-form-bundle": "^2.1" }, "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", + "phpunit/phpunit": "5.7.9" }, "scripts": { "symfony-scripts": [ @@ -43,7 +49,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/composer.lock b/composer.lock index 7dc1557..5bafff9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,115 @@ "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": "a0b8098c3300bc0cf6d88fb3caab38b4", + "content-hash": "fcdb31d7b819cb68a9d12495c93c36ba", "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", + "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 +179,7 @@ "docblock", "parser" ], - "time": "2016-12-30T15:59:45+00:00" + "time": "2016-12-30 15:59:45" }, { "name": "doctrine/cache", @@ -142,7 +249,7 @@ "cache", "caching" ], - "time": "2016-10-29T11:16:17+00:00" + "time": "2016-10-29 11:16:17" }, { "name": "doctrine/collections", @@ -209,7 +316,7 @@ "collections", "iterator" ], - "time": "2017-01-03T10:49:41+00:00" + "time": "2017-01-03 10:49:41" }, { "name": "doctrine/common", @@ -282,7 +389,7 @@ "persistence", "spl" ], - "time": "2017-01-13T14:02:13+00:00" + "time": "2017-01-13 14:02:13" }, { "name": "doctrine/dbal", @@ -353,7 +460,7 @@ "persistence", "queryobject" ], - "time": "2017-01-23T23:17:10+00:00" + "time": "2017-01-23 23:17:10" }, { "name": "doctrine/doctrine-bundle", @@ -434,7 +541,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 +629,7 @@ "cache", "caching" ], - "time": "2016-01-26T17:28:51+00:00" + "time": "2016-01-26 17:28:51" }, { "name": "doctrine/inflector", @@ -589,7 +696,7 @@ "singularize", "string" ], - "time": "2015-11-06T14:35:42+00:00" + "time": "2015-11-06 14:35:42" }, { "name": "doctrine/instantiator", @@ -643,7 +750,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2015-06-14 21:17:01" }, { "name": "doctrine/lexer", @@ -697,7 +804,7 @@ "lexer", "parser" ], - "time": "2014-09-09T13:34:57+00:00" + "time": "2014-09-09 13:34:57" }, { "name": "doctrine/orm", @@ -773,7 +880,7 @@ "database", "orm" ], - "time": "2016-12-18T15:42:34+00:00" + "time": "2016-12-18 15:42:34" }, { "name": "incenteev/composer-parameter-handler", @@ -824,7 +931,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 +981,205 @@ "highlight", "sql" ], - "time": "2014-01-12T16:20:24+00:00" + "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", + "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 +1257,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 +1305,7 @@ "pseudorandom", "random" ], - "time": "2016-11-07T23:38:38+00:00" + "time": "2016-11-07 23:38:38" }, { "name": "psr/cache", @@ -1046,7 +1351,7 @@ "psr", "psr-6" ], - "time": "2016-08-06T20:24:11+00:00" + "time": "2016-08-06 20:24:11" }, { "name": "psr/log", @@ -1093,7 +1398,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 +1450,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 +1518,7 @@ "annotations", "controllers" ], - "time": "2017-01-10T19:42:56+00:00" + "time": "2017-01-10 19:42:56" }, { "name": "sensiolabs/security-checker", @@ -1257,7 +1562,7 @@ } ], "description": "A security checker for your composer.lock", - "time": "2016-09-23T18:09:57+00:00" + "time": "2016-09-23 18:09:57" }, { "name": "swiftmailer/swiftmailer", @@ -1311,7 +1616,7 @@ "mail", "mailer" ], - "time": "2016-12-29T10:02:40+00:00" + "time": "2016-12-29 10:02:40" }, { "name": "symfony/monolog-bundle", @@ -1371,7 +1676,7 @@ "log", "logging" ], - "time": "2017-01-10T20:01:51+00:00" + "time": "2017-01-10 20:01:51" }, { "name": "symfony/polyfill-apcu", @@ -1424,7 +1729,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 +1787,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-mbstring", @@ -1541,7 +1846,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php56", @@ -1597,7 +1902,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php70", @@ -1656,7 +1961,7 @@ "portable", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-util", @@ -1708,7 +2013,7 @@ "polyfill", "shim" ], - "time": "2016-11-14T01:06:16+00:00" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/swiftmailer-bundle", @@ -1767,7 +2072,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 +2214,7 @@ "keywords": [ "framework" ], - "time": "2017-01-12T21:36:55+00:00" + "time": "2017-01-12 21:36:55" }, { "name": "twig/twig", @@ -1971,48 +2276,51 @@ "keywords": [ "templating" ], - "time": "2017-01-11T19:39:01+00:00" + "time": "2017-01-11 19:39:01" } ], "packages-dev": [ { - "name": "sensio/generator-bundle", - "version": "v3.1.2", + "name": "doctrine/data-fixtures", + "version": "v1.2.2", "source": { "type": "git", - "url": "https://github.com/sensiolabs/SensioGeneratorBundle.git", - "reference": "ec278c0bd530edf155c4a00900577b5cb80f559e" + "url": "https://github.com/doctrine/data-fixtures.git", + "reference": "17fa5bfe6ff52e35cb3d9ec37c934a2f4bd1fa2e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sensiolabs/SensioGeneratorBundle/zipball/ec278c0bd530edf155c4a00900577b5cb80f559e", - "reference": "ec278c0bd530edf155c4a00900577b5cb80f559e", + "url": "https://api.github.com/repos/doctrine/data-fixtures/zipball/17fa5bfe6ff52e35cb3d9ec37c934a2f4bd1fa2e", + "reference": "17fa5bfe6ff52e35cb3d9ec37c934a2f4bd1fa2e", "shasum": "" }, "require": { - "symfony/console": "~2.7|~3.0", - "symfony/framework-bundle": "~2.7|~3.0", - "symfony/process": "~2.7|~3.0", - "symfony/yaml": "~2.7|~3.0", - "twig/twig": "^1.28.2|^2.0" + "doctrine/common": "~2.2", + "php": "^5.6 || ^7.0" + }, + "conflict": { + "doctrine/orm": "< 2.4" }, "require-dev": { - "doctrine/orm": "~2.4", - "symfony/doctrine-bridge": "~2.7|~3.0" + "doctrine/dbal": "^2.5.4", + "doctrine/orm": "^2.5.4", + "phpunit/phpunit": "^5.4.6" }, - "type": "symfony-bundle", + "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": "3.1.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { - "psr-4": { - "Sensio\\Bundle\\GeneratorBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "psr-0": { + "Doctrine\\Common\\DataFixtures": "lib/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2020,52 +2328,47 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" } ], - "description": "This bundle generates code for you", - "time": "2016-12-05T16:01:19+00:00" + "description": "Data Fixtures for all Doctrine Object Managers", + "homepage": "http://www.doctrine-project.org", + "keywords": [ + "database" + ], + "time": "2016-09-20 10:07:57" }, { - "name": "symfony/phpunit-bridge", - "version": "v3.2.2", + "name": "doctrine/doctrine-fixtures-bundle", + "version": "2.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "d32e4062c3a3dfb95709d2ca6dd89a327ae51c3b" + "url": "https://github.com/doctrine/DoctrineFixturesBundle.git", + "reference": "0f1a2f91b349e10f5c343f75ab71d23aace5b029" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/d32e4062c3a3dfb95709d2ca6dd89a327ae51c3b", - "reference": "d32e4062c3a3dfb95709d2ca6dd89a327ae51c3b", + "url": "https://api.github.com/repos/doctrine/DoctrineFixturesBundle/zipball/0f1a2f91b349e10f5c343f75ab71d23aace5b029", + "reference": "0f1a2f91b349e10f5c343f75ab71d23aace5b029", "shasum": "" }, "require": { - "php": ">=5.3.3" - }, - "suggest": { - "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + "doctrine/data-fixtures": "~1.0", + "doctrine/doctrine-bundle": "~1.0", + "php": ">=5.3.2", + "symfony/doctrine-bridge": "~2.3|~3.0" }, - "bin": [ - "bin/simple-phpunit" - ], - "type": "symfony-bridge", + "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "3.2-dev" + "dev-master": "2.2.x-dev" } }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Bridge\\PhpUnit\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Doctrine\\Bundle\\FixturesBundle\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2073,17 +2376,1440 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Doctrine Project", + "homepage": "http://www.doctrine-project.org" + }, + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" } ], - "description": "Symfony PHPUnit Bridge", - "homepage": "https://symfony.com", - "time": "2017-01-06T17:19:17+00:00" + "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": "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" + }, + "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/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "ext-mbstring": "*", + "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": "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": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "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", + "version": "v3.1.2", + "source": { + "type": "git", + "url": "https://github.com/sensiolabs/SensioGeneratorBundle.git", + "reference": "ec278c0bd530edf155c4a00900577b5cb80f559e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sensiolabs/SensioGeneratorBundle/zipball/ec278c0bd530edf155c4a00900577b5cb80f559e", + "reference": "ec278c0bd530edf155c4a00900577b5cb80f559e", + "shasum": "" + }, + "require": { + "symfony/console": "~2.7|~3.0", + "symfony/framework-bundle": "~2.7|~3.0", + "symfony/process": "~2.7|~3.0", + "symfony/yaml": "~2.7|~3.0", + "twig/twig": "^1.28.2|^2.0" + }, + "require-dev": { + "doctrine/orm": "~2.4", + "symfony/doctrine-bridge": "~2.7|~3.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Sensio\\Bundle\\GeneratorBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + } + ], + "description": "This bundle generates code for you", + "time": "2016-12-05 16:01:19" + }, + { + "name": "symfony/phpunit-bridge", + "version": "v3.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/phpunit-bridge.git", + "reference": "d32e4062c3a3dfb95709d2ca6dd89a327ae51c3b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/d32e4062c3a3dfb95709d2ca6dd89a327ae51c3b", + "reference": "d32e4062c3a3dfb95709d2ca6dd89a327ae51c3b", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + }, + "bin": [ + "bin/simple-phpunit" + ], + "type": "symfony-bridge", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Bridge\\PhpUnit\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony 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/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..bd5eacd --- /dev/null +++ b/src/AppBundle/Controller/UserController.php @@ -0,0 +1,185 @@ +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(); + $wishlist->setUser($user); + + $em = $this->getDoctrine()->getManager(); + $em->persist($wishlist); + $em->persist($user); + $em->flush(); + + return $this->redirectToRoute('homepage'); + } + + return $this->render('AppBundle:user:signup.html.twig', array( + 'title' => $this->get('translator')->trans('user.signup'), + 'form' => $form->createView() + )); + } + + /** + * @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"}) + * + * @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:login.html.twig', array( + 'title' => $this->get('translator')->trans('user.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..e4b235a --- /dev/null +++ b/src/AppBundle/Controller/WishlistController.php @@ -0,0 +1,104 @@ +denyAccessUnlessGranted('edit', $wishlist); + + $words = $this->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' => $this->get('translator')->trans('wishlist.title'), + '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) + { + $this->denyAccessUnlessGranted('edit', $wishlist); + + $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) + { + $this->denyAccessUnlessGranted('edit', $wishlist); + + $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..062eafd --- /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' => $this->get('translator')->trans('word.titleMany'), + '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:word:new.html.twig', array( + 'title' => $this->get('translator')->trans('word.new'), + '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:word:edit.html.twig', array( + 'title' => $this->get('translator')->trans('word.edit'), + '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/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..692ce1c --- /dev/null +++ b/src/AppBundle/DataFixtures/ORM/fixtures.yml @@ -0,0 +1,81 @@ +AppBundle\Entity\User: + userAdminDefault1: + userProfile (unique): '@uProfile1' + username (unique): admin + password: admin + email: admin@example.com + roles: ["ROLE_ADMIN"] + createdAt: '' + updatedAt: '' + userDefault2: + userProfile (unique): '@uProfile2' + username (unique): user + password: user + email: user@example.com + roles: ["ROLE_USER"] + createdAt: '' + updatedAt: '' + user{3..12}: + userProfile (unique): '@uProfile' + username (unique): '' + password: '' + email (unique): '' + roles: '' + createdAt: '' + updatedAt: '' + +AppBundle\Entity\UserProfile: + uProfile{1..12}: + firstName: '' + lastName: '' + createdAt: '' + updatedAt: '' + +AppBundle\Entity\Word: + word{1..30}: + user: '@user*' + createdAt: '' + updatedAt: '' + +AppBundle\Entity\WordTranslation: + wTranslation{1..29}: + translatable: '@word' + word: '' + 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: + words: ['@word*'] + user: '@userAdminDefault1' + createdAt: '' + updatedAt: '' + wishlist2: + words: ['@word*'] + user: '@userDefault2' + createdAt: '' + updatedAt: '' + wishlist{3..12}: + words: ['@word*'] + user (unique): '@user' + createdAt: '' + updatedAt: '' diff --git a/src/AppBundle/Entity/BaseSuperClass.php b/src/AppBundle/Entity/BaseSuperClass.php new file mode 100644 index 0000000..988b80f --- /dev/null +++ b/src/AppBundle/Entity/BaseSuperClass.php @@ -0,0 +1,36 @@ +id; + } +} diff --git a/src/AppBundle/Entity/User.php b/src/AppBundle/Entity/User.php new file mode 100644 index 0000000..797aad4 --- /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..452643d --- /dev/null +++ b/src/AppBundle/Entity/UserProfile.php @@ -0,0 +1,83 @@ +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..996b909 --- /dev/null +++ b/src/AppBundle/Entity/Wishlist.php @@ -0,0 +1,132 @@ +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; + } + + /** + * 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 + * + * @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..d3d6862 --- /dev/null +++ b/src/AppBundle/Entity/Word.php @@ -0,0 +1,106 @@ +wishlists = new \Doctrine\Common\Collections\ArrayCollection(); + } + + /** + * 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/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/LoginType.php b/src/AppBundle/Form/LoginType.php new file mode 100644 index 0000000..3504d58 --- /dev/null +++ b/src/AppBundle/Form/LoginType.php @@ -0,0 +1,43 @@ +add('_username') + ->add('_password', PasswordType::class) + ->add('login', SubmitType::class, array( + 'label' => 'user.login' + )); + } + + /** + * {@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..ef0b5b0 --- /dev/null +++ b/src/AppBundle/Form/UserType.php @@ -0,0 +1,80 @@ +authorizationChecker = $options['authorizationChecker']; + + $builder + ->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, array( + '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, + )); + } + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefaults(array( + '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 + )); + } + + /** + * {@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..280557e --- /dev/null +++ b/src/AppBundle/Form/WordType.php @@ -0,0 +1,64 @@ +authorizationChecker = $options['authorizationChecker']; + + $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( + 'class' => 'AppBundle:User', + 'choice_label' => 'username', + 'label' => 'base.author' + )); + } + } + + /** + * {@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/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 @@ +createQueryBuilder('w') + ->orderBy('w.createdAt', 'DESC') + ; + + return $query; + } + + /** + * @param int $wishlistId + * + * @return \Doctrine\ORM\QueryBuilder + */ + public function findAllByWishlist($wishlistId) + { + $query = $this->createQueryBuilder('word') + ->innerJoin('word.wishlists', 'w', 'WITH', 'w.id = :wishlistId') + ->setParameter('wishlistId', $wishlistId) + ->orderBy('word.createdAt', 'DESC') + ; + + return $query; + } +} diff --git a/src/AppBundle/Resources/translations/messages.en.yml b/src/AppBundle/Resources/translations/messages.en.yml new file mode 100644 index 0000000..aac357c --- /dev/null +++ b/src/AppBundle/Resources/translations/messages.en.yml @@ -0,0 +1,45 @@ +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 + +Roles: Roles +ROLE_ADMIN: ROLE_ADMIN +ROLE_USER: ROLE_USER 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..bba1c73 --- /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 new file mode 100644 index 0000000..09ac0f6 --- /dev/null +++ b/src/AppBundle/Resources/views/base.html.twig @@ -0,0 +1,29 @@ + + + + + + + {% block docTitle %}{{ 'base.siteTitle'|trans }}{% endblock %} + {% 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..cf15d0c --- /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..0057d45 --- /dev/null +++ b/src/AppBundle/Resources/views/default/_navbar_top_links.html.twig @@ -0,0 +1,30 @@ + diff --git a/src/AppBundle/Resources/views/user/edit.html.twig b/src/AppBundle/Resources/views/user/edit.html.twig new file mode 100644 index 0000000..9259a54 --- /dev/null +++ b/src/AppBundle/Resources/views/user/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/user/login.html.twig b/src/AppBundle/Resources/views/user/login.html.twig new file mode 100644 index 0000000..64b85e1 --- /dev/null +++ b/src/AppBundle/Resources/views/user/login.html.twig @@ -0,0 +1,29 @@ +{% 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 }}

+ + {% 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/user/show.html.twig b/src/AppBundle/Resources/views/user/show.html.twig new file mode 100644 index 0000000..34c6726 --- /dev/null +++ b/src/AppBundle/Resources/views/user/show.html.twig @@ -0,0 +1,79 @@ +{% extends 'AppBundle::base.html.twig' %} + +{% block main %} +
+
+ +
+

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

+ {% 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') %} +

{{ 'base.delete'|trans }}

+ {% endif %} +
+ +
+ +

{{ title }}

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

{{ 'word.new'|trans }}

+ {% endif %} + +
+ + + + + + + + + + + + {% 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.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 %} + {{ '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/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 new file mode 100644 index 0000000..9d38fe0 --- /dev/null +++ b/src/AppBundle/Resources/views/word/index.html.twig @@ -0,0 +1,71 @@ +{% extends 'AppBundle::base.html.twig' %} + +{% block main %} +
+
+
+ +
+ +

{{ title }}

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

{{ 'word.new'|trans }}

+ {% endif %} + +
+ + + + + + + + + + + + {% 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.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 %} + {{ '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/new.html.twig b/src/AppBundle/Resources/views/word/new.html.twig new file mode 100644 index 0000000..57658a7 --- /dev/null +++ b/src/AppBundle/Resources/views/word/new.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/Security/AppVoter.php b/src/AppBundle/Security/AppVoter.php new file mode 100644 index 0000000..4d73029 --- /dev/null +++ b/src/AppBundle/Security/AppVoter.php @@ -0,0 +1,123 @@ +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 || + $subject instanceof Wishlist + )) { + 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/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'; + } +} 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() + ); + } +} 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; + } +}