├── .editorconfig ├── .env ├── .env.test ├── .github └── workflows │ └── symfony.yml ├── .gitignore ├── .php_cs.dist ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── appveyor.yml ├── assets ├── js │ ├── admin.js │ ├── app.js │ ├── doclinks.js │ ├── highlight.js │ ├── jquery.instantSearch.js │ ├── login.js │ └── search.js └── scss │ ├── admin.scss │ ├── app.scss │ └── bootstrap-tagsinput.scss ├── bin ├── console └── phpunit ├── composer.json ├── composer.lock ├── config ├── bootstrap.php ├── bundles.php ├── packages │ ├── acme_foo.yaml │ ├── assets.yaml │ ├── cache.yaml │ ├── dev │ │ ├── debug.yaml │ │ ├── mailer.yaml │ │ ├── monolog.yaml │ │ ├── routing.yaml │ │ └── web_profiler.yaml │ ├── doctrine.yaml │ ├── doctrine_migrations.yaml │ ├── framework.yaml │ ├── html_sanitizer.yaml │ ├── mailer.yaml │ ├── prod │ │ ├── doctrine.yaml │ │ ├── monolog.yaml │ │ ├── routing.yaml │ │ └── webpack_encore.yaml │ ├── routing.yaml │ ├── security.yaml │ ├── sensio_framework_extra.yaml │ ├── test │ │ ├── dama_doctrine_test_bundle.yaml │ │ ├── framework.yaml │ │ ├── mailer.yaml │ │ ├── monolog.yaml │ │ ├── routing.yaml │ │ ├── security.yaml │ │ ├── twig.yaml │ │ ├── validator.yaml │ │ ├── web_profiler.yaml │ │ └── webpack_encore.yaml │ ├── translation.yaml │ ├── twig.yaml │ ├── validator.yaml │ └── webpack_encore.yaml ├── routes.yaml ├── routes │ ├── annotations.yaml │ └── dev │ │ ├── framework.yaml │ │ └── web_profiler.yaml └── services.yaml ├── data ├── database.sqlite └── database_test.sqlite ├── lib └── acme │ └── foo-bundle │ ├── .gitignore │ ├── .travis │ ├── AcmeFooBundle.php │ ├── Controller │ └── AcmeFooController.php │ ├── DTO │ ├── CarDTO.php │ └── CarDTOBuilder.php │ ├── DependencyInjection │ ├── AcmeFooExtension.php │ └── Configuration.php │ ├── Entity │ ├── Car.php │ └── CarRepository.php │ ├── LICENSE │ ├── README.md │ ├── Resources │ ├── config │ │ ├── doctrine │ │ │ └── Car.orm.xml │ │ └── services.xml │ ├── doc │ │ ├── index.rst │ │ └── logo.png │ ├── public │ │ └── .gitkeep │ ├── translations │ │ ├── messages.en.yml │ │ └── messages.es.yml │ └── views │ │ └── acme_foo_widget.html.twig │ ├── Service │ └── Service.php │ ├── Tests │ ├── Mock │ │ └── UserMock.php │ ├── ServiceTest.php │ └── bootstrap.php │ ├── composer.json │ └── phpunit.xml.dist ├── package.json ├── phpunit.xml.dist ├── public ├── .htaccess ├── apple-touch-icon.png ├── build │ ├── 0.js │ ├── 1.js │ ├── admin.css │ ├── admin.js │ ├── app.css │ ├── app.js │ ├── entrypoints.json │ ├── fonts │ │ ├── fa-brands-400.088a34f7.eot │ │ ├── fa-brands-400.273dc9bf.ttf │ │ ├── fa-brands-400.822d94f1.woff2 │ │ ├── fa-brands-400.f4920c94.woff │ │ ├── fa-regular-400.3ac49cb3.eot │ │ ├── fa-regular-400.9efb8697.woff2 │ │ ├── fa-regular-400.a57bcf76.woff │ │ ├── fa-regular-400.ece54318.ttf │ │ ├── fa-solid-900.2aa6edf8.ttf │ │ ├── fa-solid-900.7fb1cdd9.eot │ │ ├── fa-solid-900.93f28454.woff │ │ ├── fa-solid-900.f6121be5.woff2 │ │ ├── lato-bold-italic.0b6bb672.woff2 │ │ ├── lato-bold-italic.9c7e4e9e.woff │ │ ├── lato-bold.cccb8974.woff2 │ │ ├── lato-bold.d878b6c2.woff │ │ ├── lato-normal-italic.4eb103b4.woff2 │ │ ├── lato-normal-italic.f28f2d64.woff │ │ ├── lato-normal.27bd77b9.woff │ │ └── lato-normal.bd03a2cc.woff2 │ ├── images │ │ ├── fa-brands-400.d7229311.svg │ │ ├── fa-regular-400.d2e53334.svg │ │ └── fa-solid-900.7a5de9b0.svg │ ├── login.js │ ├── manifest.json │ ├── runtime.js │ └── search.js ├── favicon.ico ├── index.php └── robots.txt ├── src ├── Command │ ├── AddUserCommand.php │ ├── CreateBundleCommand.php │ ├── CreateBundleUtils.php │ ├── DeleteUserCommand.php │ └── ListUsersCommand.php ├── Controller │ ├── Admin │ │ └── BlogController.php │ ├── BlogController.php │ ├── SecurityController.php │ └── UserController.php ├── DataFixtures │ └── AppFixtures.php ├── Entity │ ├── Comment.php │ ├── Post.php │ ├── Tag.php │ └── User.php ├── EventSubscriber │ ├── CheckRequirementsSubscriber.php │ ├── CommentNotificationSubscriber.php │ ├── ControllerSubscriber.php │ └── RedirectToPreferredLocaleSubscriber.php ├── Events │ └── CommentCreatedEvent.php ├── Form │ ├── CommentType.php │ ├── DataTransformer │ │ └── TagArrayToStringTransformer.php │ ├── PostType.php │ ├── Type │ │ ├── ChangePasswordType.php │ │ ├── DateTimePickerType.php │ │ └── TagsInputType.php │ └── UserType.php ├── Kernel.php ├── Migrations │ └── .gitignore ├── Pagination │ └── Paginator.php ├── Repository │ ├── PostRepository.php │ ├── TagRepository.php │ └── UserRepository.php ├── Security │ └── PostVoter.php ├── Twig │ ├── AppExtension.php │ └── SourceCodeExtension.php └── Utils │ ├── Markdown.php │ ├── MomentFormatConverter.php │ └── Validator.php ├── symfony.lock ├── templates ├── admin │ ├── blog │ │ ├── _delete_form.html.twig │ │ ├── _form.html.twig │ │ ├── edit.html.twig │ │ ├── index.html.twig │ │ ├── new.html.twig │ │ └── show.html.twig │ └── layout.html.twig ├── base.html.twig ├── blog │ ├── _comment_form.html.twig │ ├── _delete_post_confirmation.html.twig │ ├── _post_tags.html.twig │ ├── _rss.html.twig │ ├── about.html.twig │ ├── comment_form_error.html.twig │ ├── index.html.twig │ ├── index.xml.twig │ ├── post_show.html.twig │ └── search.html.twig ├── bundles │ └── TwigBundle │ │ └── Exception │ │ ├── error.html.twig │ │ ├── error403.html.twig │ │ ├── error404.html.twig │ │ └── error500.html.twig ├── debug │ └── source_code.html.twig ├── default │ ├── _flash_messages.html.twig │ └── homepage.html.twig ├── form │ ├── fields.html.twig │ └── layout.html.twig ├── security │ └── login.html.twig └── user │ ├── change_password.html.twig │ └── edit.html.twig ├── tests ├── Command │ └── AddUserCommandTest.php ├── Controller │ ├── Admin │ │ └── BlogControllerTest.php │ ├── BlogControllerTest.php │ ├── DefaultControllerTest.php │ └── UserControllerTest.php ├── Form │ └── DataTransformer │ │ └── TagArrayToStringTransformerTest.php └── Utils │ └── ValidatorTest.php ├── translations ├── messages+intl-icu.bg.xlf ├── messages+intl-icu.ca.xlf ├── messages+intl-icu.cs.xlf ├── messages+intl-icu.de.xlf ├── messages+intl-icu.en.xlf ├── messages+intl-icu.es.xlf ├── messages+intl-icu.fr.xlf ├── messages+intl-icu.hr.xlf ├── messages+intl-icu.id.xlf ├── messages+intl-icu.it.xlf ├── messages+intl-icu.ja.xlf ├── messages+intl-icu.lt.xlf ├── messages+intl-icu.nl.xlf ├── messages+intl-icu.pl.xlf ├── messages+intl-icu.pt_BR.xlf ├── messages+intl-icu.ro.xlf ├── messages+intl-icu.ru.xlf ├── messages+intl-icu.sl.xlf ├── messages+intl-icu.tr.xlf ├── messages+intl-icu.uk.xlf ├── messages+intl-icu.zh_CN.xlf ├── validators+intl-icu.bg.xlf ├── validators+intl-icu.ca.xlf ├── validators+intl-icu.cs.xlf ├── validators+intl-icu.de.xlf ├── validators+intl-icu.en.xlf ├── validators+intl-icu.es.xlf ├── validators+intl-icu.fr.xlf ├── validators+intl-icu.hr.xlf ├── validators+intl-icu.id.xlf ├── validators+intl-icu.it.xlf ├── validators+intl-icu.ja.xlf ├── validators+intl-icu.lt.xlf ├── validators+intl-icu.nl.xlf ├── validators+intl-icu.pl.xlf ├── validators+intl-icu.pt_BR.xlf ├── validators+intl-icu.ro.xlf ├── validators+intl-icu.ru.xlf ├── validators+intl-icu.sl.xlf ├── validators+intl-icu.tr.xlf ├── validators+intl-icu.uk.xlf └── validators+intl-icu.zh_CN.xlf ├── var ├── log │ └── .gitkeep └── sessions │ └── .gitkeep ├── webpack.config.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | ; top-most EditorConfig file 2 | root = true 3 | 4 | ; Unix-style newlines 5 | [*] 6 | end_of_line = LF 7 | 8 | [*.php] 9 | indent_style = space 10 | indent_size = 4 11 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # In all environments, the following files are loaded if they exist, 2 | # the latter taking precedence over the former: 3 | # 4 | # * .env contains default values for the environment variables needed by the app 5 | # * .env.local uncommitted file with local overrides 6 | # * .env.$APP_ENV committed environment-specific defaults 7 | # * .env.$APP_ENV.local uncommitted environment-specific overrides 8 | # 9 | # Real environment variables win over .env files. 10 | # 11 | # DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. 12 | # 13 | # Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). 14 | # https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration 15 | 16 | ###> symfony/framework-bundle ### 17 | APP_ENV=dev 18 | APP_SECRET=67d829bf61dc5f87a73fd814e2c9f629 19 | #TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 20 | #TRUSTED_HOSTS='^localhost|example\.com$' 21 | ###< symfony/framework-bundle ### 22 | 23 | ###> doctrine/doctrine-bundle ### 24 | # Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url 25 | # For a MySQL database, use: "mysql://db_user:db_password@127.0.0.1:3306/db_name" 26 | # For a PostgreSQL database, use: "postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=11" 27 | # Configure your db driver and server_version in config/packages/doctrine.yaml 28 | DATABASE_URL=sqlite:///%kernel.project_dir%/data/database.sqlite 29 | ###< doctrine/doctrine-bundle ### 30 | 31 | ###> symfony/mailer ### 32 | # MAILER_DSN=smtp://localhost 33 | ###< symfony/mailer ### 34 | -------------------------------------------------------------------------------- /.env.test: -------------------------------------------------------------------------------- 1 | # define your env variables for the test env here 2 | APP_SECRET='$ecretf0rt3st' 3 | DATABASE_URL=sqlite:///%kernel.project_dir%/data/database_test.sqlite 4 | KERNEL_CLASS='App\Kernel' 5 | SYMFONY_DEPRECATIONS_HELPER=999999 6 | -------------------------------------------------------------------------------- /.github/workflows/symfony.yml: -------------------------------------------------------------------------------- 1 | name: Symfony 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | symfony-tests: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # To automatically get bug fixes and new Php versions for shivammathur/setup-php, 14 | # change this to (see https://github.com/shivammathur/setup-php#bookmark-versioning): 15 | # uses: shivammathur/setup-php@v2 16 | - uses: shivammathur/setup-php@2cb9b829437ee246e9b3cac53555a39208ca6d28 17 | with: 18 | php-version: '8.0' 19 | - uses: actions/checkout@v2 20 | - name: Copy .env.test.local 21 | run: php -r "file_exists('.env.test.local') || copy('.env.test', '.env.test.local');" 22 | - name: Cache Composer packages 23 | id: composer-cache 24 | uses: actions/cache@v2 25 | with: 26 | path: vendor 27 | key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} 28 | restore-keys: | 29 | ${{ runner.os }}-php- 30 | - name: Install Dependencies 31 | run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist 32 | - name: Create Database 33 | run: | 34 | mkdir -p data 35 | touch data/database.sqlite 36 | - name: Execute tests (Unit and Feature tests) via PHPUnit 37 | env: 38 | DATABASE_URL: sqlite:///%kernel.project_dir%/data/database.sqlite 39 | run: vendor/bin/phpunit 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /public/build/fonts/glyphicons-* 2 | /public/build/images/glyphicons-* 3 | 4 | ###> symfony/framework-bundle ### 5 | /.env.local 6 | /.env.local.php 7 | /.env.*.local 8 | /public/bundles/ 9 | /var/ 10 | /vendor/ 11 | ###< symfony/framework-bundle ### 12 | 13 | ###> symfony/phpunit-bridge ### 14 | .phpunit 15 | .phpunit.result.cache 16 | /phpunit.xml 17 | ###< symfony/phpunit-bridge ### 18 | ###> friendsofphp/php-cs-fixer ### 19 | /.php_cs 20 | /.php_cs.cache 21 | ###< friendsofphp/php-cs-fixer ### 22 | 23 | ###> symfony/webpack-encore-bundle ### 24 | /node_modules/ 25 | npm-debug.log 26 | yarn-error.log 27 | ###< symfony/webpack-encore-bundle ### 28 | 29 | ###> Jetbrains (IDE) ### 30 | /.idea 31 | ###< Jetbrains (IDE) ### 32 | 33 | ###> Created bundle ### 34 | /lib 35 | ###< Created bundle ### 36 | 37 | ###> composer.json will be modified with your namespace ### 38 | composer.json 39 | ###< composer.json will be modified with your namespace ### 40 | ###> phpunit/phpunit ### 41 | /phpunit.xml 42 | .phpunit.result.cache 43 | ###< phpunit/phpunit ### 44 | -------------------------------------------------------------------------------- /.php_cs.dist: -------------------------------------------------------------------------------- 1 | 7 | 8 | For the full copyright and license information, please view the LICENSE 9 | file that was distributed with this source code. 10 | COMMENT; 11 | 12 | $finder = PhpCsFixer\Finder::create() 13 | ->in(__DIR__) 14 | ->exclude('config') 15 | ->exclude('var') 16 | ->exclude('public/bundles') 17 | ->exclude('public/build') 18 | // exclude files generated by Symfony Flex recipes 19 | ->notPath('bin/console') 20 | ->notPath('public/index.php') 21 | ; 22 | 23 | return PhpCsFixer\Config::create() 24 | ->setRiskyAllowed(true) 25 | ->setRules([ 26 | '@Symfony' => true, 27 | '@Symfony:risky' => true, 28 | 'array_syntax' => ['syntax' => 'short'], 29 | 'header_comment' => ['header' => $fileHeaderComment, 'separate' => 'both'], 30 | 'linebreak_after_opening_tag' => true, 31 | 'mb_str_functions' => true, 32 | 'no_php4_constructor' => true, 33 | 'no_superfluous_phpdoc_tags' => true, 34 | 'no_unreachable_default_argument_value' => true, 35 | 'no_useless_else' => true, 36 | 'no_useless_return' => true, 37 | 'ordered_imports' => true, 38 | 'php_unit_strict' => true, 39 | 'phpdoc_order' => true, 40 | 'semicolon_after_instruction' => true, 41 | 'strict_comparison' => true, 42 | 'strict_param' => true, 43 | ]) 44 | ->setFinder($finder) 45 | ->setCacheFile(__DIR__.'/var/.php_cs.cache') 46 | ; 47 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | sudo: false 3 | 4 | cache: 5 | yarn: true 6 | directories: 7 | - $HOME/.composer/cache/files 8 | - ./bin/.phpunit 9 | 10 | env: 11 | global: 12 | - SYMFONY_PHPUNIT_DIR=./bin/.phpunit 13 | - SYMFONY_DEPRECATIONS_HELPER=9 14 | - ACTION="install" 15 | 16 | matrix: 17 | fast_finish: true 18 | include: 19 | - php: 7.3 20 | env: SYMFONY="5.0.*" 21 | ACTION="update" 22 | - php: 7.4 23 | - php: 8.0 24 | 25 | before_install: 26 | - '[[ "$TRAVIS_PHP_VERSION" == "7.4snapshot" ]] || phpenv config-rm xdebug.ini' 27 | - composer self-update 28 | # Set memory to max (memory fail) 29 | - '[[ "$ACTION" == "install" ]] || echo "memory_limit=-1" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini' 30 | # Set stability to dev to allow 4.4dev and 5.0dev 31 | - '[[ "$ACTION" == "install" ]] || composer config minimum-stability dev' 32 | # Change version of symfony when need 33 | - '[[ "$ACTION" == "install" ]] || composer config extra.symfony.require $SYMFONY' 34 | 35 | install: 36 | - php -r "echo ini_get('memory_limit').PHP_EOL;" 37 | # install or update 38 | - composer $ACTION 39 | - ./bin/phpunit install 40 | 41 | script: 42 | - ./bin/phpunit 43 | # this checks that the source code follows the Symfony Code Syntax rules 44 | - '[[ "$TRAVIS_PHP_VERSION" == "7.4" ]] || ./vendor/bin/php-cs-fixer fix --diff --dry-run -v' 45 | # this checks that the YAML config files contain no syntax errors 46 | - ./bin/console lint:yaml config --parse-tags 47 | # this checks that the Twig template files contain no syntax errors 48 | - ./bin/console lint:twig templates --env=prod 49 | # this checks that the XLIFF translations contain no syntax errors 50 | - ./bin/console lint:xliff translations 51 | # this checks that arguments injected into services match type declarations 52 | - ./bin/console lint:container 53 | # TODO: replace the old security checker by the new checker provided by the 'symfony' binary 54 | # this checks that the application doesn't use dependencies with known security vulnerabilities 55 | #- ./bin/console security:check 56 | # this checks that Doctrine's mapping configurations are valid 57 | - ./bin/console doctrine:schema:validate --skip-sync -vvv --no-interaction 58 | # Fail CI if the repo is in a dirty state after building assets (only for current release ie install) 59 | #- if [[ "$ACTION" == "install" ]]; then yarn install && yarn encore production && git add --all && git diff --staged --exit-code; fi 60 | - composer validate 61 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | ============ 3 | 4 | The Symfony Demo application is an open source project. Contributions made by 5 | the community are welcome. Send us your ideas, code reviews, pull requests and 6 | feature requests to help us improve this project. All contributions must follow 7 | the [usual Symfony contribution requirements](https://symfony.com/doc/current/contributing/index.html). 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2020 Fabien Potencier 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | build: false 2 | clone_depth: 1 3 | clone_folder: c:\projects\symfony-demo 4 | 5 | cache: 6 | - '%LOCALAPPDATA%\Composer\files' 7 | - '%LOCALAPPDATA%\SymfonyBridge\phpunit' 8 | - c:\projects\symfony-demo\composer.phar 9 | 10 | init: 11 | - SET PATH=c:\php;%PATH% 12 | - SET COMPOSER_NO_INTERACTION=1 13 | - SET SYMFONY_DEPRECATIONS_HELPER=strict 14 | - SET SYMFONY_PHPUNIT_DIR=%LOCALAPPDATA%\SymfonyBridge\phpunit 15 | - SET ANSICON=121x90 (121x90) 16 | - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f 17 | 18 | install: 19 | - mkdir c:\php && cd c:\php 20 | - appveyor DownloadFile https://raw.githubusercontent.com/symfony/binary-utils/master/cacert.pem 21 | - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php-7.1.3-Win32-VC14-x86.zip 22 | - 7z x php-7.1.3-Win32-VC14-x86.zip -y >nul 23 | - del /Q *.zip 24 | - cd ext 25 | - appveyor DownloadFile https://github.com/symfony/binary-utils/releases/download/v0.1/php_apcu-5.1.8-7.1-ts-vc14-x86.zip 26 | - 7z x php_apcu-5.1.8-7.1-ts-vc14-x86.zip -y >nul 27 | - del /Q *.zip 28 | - cd .. 29 | - copy /Y php.ini-development php.ini 30 | - echo max_execution_time=1200 >> php.ini 31 | - echo date.timezone="America/Los_Angeles" >> php.ini 32 | - echo extension_dir=ext >> php.ini 33 | - echo zend_extension=php_opcache.dll >> php.ini 34 | - echo opcache.enable_cli=1 >> php.ini 35 | - echo extension=php_openssl.dll >> php.ini 36 | - echo extension=php_apcu.dll >> php.ini 37 | - echo apc.enable_cli=1 >> php.ini 38 | - echo extension=php_intl.dll >> php.ini 39 | - echo extension=php_mbstring.dll >> php.ini 40 | - echo extension=php_fileinfo.dll >> php.ini 41 | - echo extension=php_pdo_sqlite.dll >> php.ini 42 | - echo extension=php_curl.dll >> php.ini 43 | - echo curl.cainfo=c:\php\cacert.pem >> php.ini 44 | - cd c:\projects\symfony-demo 45 | - IF NOT EXIST composer.phar (appveyor DownloadFile https://getcomposer.org/download/1.3.0/composer.phar) 46 | - php composer.phar self-update 47 | - IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev) 48 | - php composer.phar update --no-progress --ansi 49 | - SET COMPOSER_ROOT_VERSION= 50 | - vendor\bin\simple-phpunit install 51 | 52 | test_script: 53 | - cd c:\projects\symfony-demo 54 | - vendor/bin/simple-phpunit 55 | -------------------------------------------------------------------------------- /assets/js/admin.js: -------------------------------------------------------------------------------- 1 | import '../scss/admin.scss'; 2 | import 'eonasdan-bootstrap-datetimepicker'; 3 | import 'typeahead.js'; 4 | import Bloodhound from "bloodhound-js"; 5 | import 'bootstrap-tagsinput'; 6 | 7 | $(function() { 8 | // Datetime picker initialization. 9 | // See https://eonasdan.github.io/bootstrap-datetimepicker/ 10 | $('[data-toggle="datetimepicker"]').datetimepicker({ 11 | icons: { 12 | time: 'fa fa-clock-o', 13 | date: 'fa fa-calendar', 14 | up: 'fa fa-chevron-up', 15 | down: 'fa fa-chevron-down', 16 | previous: 'fa fa-chevron-left', 17 | next: 'fa fa-chevron-right', 18 | today: 'fa fa-check-circle-o', 19 | clear: 'fa fa-trash', 20 | close: 'fa fa-remove' 21 | } 22 | }); 23 | 24 | // Bootstrap-tagsinput initialization 25 | // https://bootstrap-tagsinput.github.io/bootstrap-tagsinput/examples/ 26 | var $input = $('input[data-toggle="tagsinput"]'); 27 | if ($input.length) { 28 | var source = new Bloodhound({ 29 | local: $input.data('tags'), 30 | queryTokenizer: Bloodhound.tokenizers.whitespace, 31 | datumTokenizer: Bloodhound.tokenizers.whitespace 32 | }); 33 | source.initialize(); 34 | 35 | $input.tagsinput({ 36 | trimValue: true, 37 | focusClass: 'focus', 38 | typeaheadjs: { 39 | name: 'tags', 40 | source: source.ttAdapter() 41 | } 42 | }); 43 | } 44 | }); 45 | 46 | // Handling the modal confirmation message. 47 | $(document).on('submit', 'form[data-confirmation]', function (event) { 48 | var $form = $(this), 49 | $confirm = $('#confirmationModal'); 50 | 51 | if ($confirm.data('result') !== 'yes') { 52 | //cancel submit event 53 | event.preventDefault(); 54 | 55 | $confirm 56 | .off('click', '#btnYes') 57 | .on('click', '#btnYes', function () { 58 | $confirm.data('result', 'yes'); 59 | $form.find('input[type="submit"]').attr('disabled', 'disabled'); 60 | $form.submit(); 61 | }) 62 | .modal('show'); 63 | } 64 | }); 65 | -------------------------------------------------------------------------------- /assets/js/app.js: -------------------------------------------------------------------------------- 1 | import '../scss/app.scss'; 2 | 3 | // loads the Bootstrap jQuery plugins 4 | import 'bootstrap-sass/assets/javascripts/bootstrap/transition.js'; 5 | import 'bootstrap-sass/assets/javascripts/bootstrap/alert.js'; 6 | import 'bootstrap-sass/assets/javascripts/bootstrap/collapse.js'; 7 | import 'bootstrap-sass/assets/javascripts/bootstrap/dropdown.js'; 8 | import 'bootstrap-sass/assets/javascripts/bootstrap/modal.js'; 9 | import 'jquery' 10 | 11 | // loads the code syntax highlighting library 12 | import './highlight.js'; 13 | 14 | // Creates links to the Symfony documentation 15 | import './doclinks.js'; 16 | -------------------------------------------------------------------------------- /assets/js/doclinks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // Wraps some elements in anchor tags referencing to the Symfony documentation 4 | $(function() { 5 | var $modal = $('#sourceCodeModal'); 6 | var $controllerCode = $modal.find('code.php'); 7 | var $templateCode = $modal.find('code.twig'); 8 | 9 | function anchor(url, content) { 10 | return '' + content + ''; 11 | }; 12 | 13 | // Wraps links to the Symfony documentation 14 | $modal.find('.hljs-comment').each(function() { 15 | $(this).html($(this).html().replace(/https:\/\/symfony.com\/doc\/[\w/.#-]+/g, function(url) { 16 | return anchor(url, url); 17 | })); 18 | }); 19 | 20 | // Wraps Symfony's annotations 21 | var annotations = { 22 | '@Cache': 'https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/cache.html', 23 | '@IsGranted': 'https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html#isgranted', 24 | '@ParamConverter': 'https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html', 25 | '@Route': 'https://symfony.com/doc/current/routing.html#creating-routes-as-annotations', 26 | '@Security': 'https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/security.html#security' 27 | }; 28 | 29 | $controllerCode.find('.hljs-doctag').each(function() { 30 | var annotation = $(this).text(); 31 | 32 | if (annotations[annotation]) { 33 | $(this).html(anchor(annotations[annotation], annotation)); 34 | } 35 | }); 36 | 37 | // Wraps Twig's tags 38 | $templateCode.find('.hljs-template-tag > .hljs-name').each(function() { 39 | var tag = $(this).text(); 40 | 41 | if ('else' === tag || tag.match(/^end/)) { 42 | return; 43 | } 44 | 45 | var url = 'https://twig.symfony.com/doc/3.x/tags/' + tag + '.html#' + tag; 46 | 47 | $(this).html(anchor(url, tag)); 48 | }); 49 | 50 | // Wraps Twig's functions 51 | $templateCode.find('.hljs-template-variable > .hljs-name').each(function() { 52 | var func = $(this).text(); 53 | 54 | var url = 'https://twig.symfony.com/doc/3.x/functions/' + func + '.html#' + func; 55 | 56 | $(this).html(anchor(url, func)); 57 | }); 58 | }); 59 | -------------------------------------------------------------------------------- /assets/js/highlight.js: -------------------------------------------------------------------------------- 1 | import hljs from 'highlight.js/lib/highlight'; 2 | import php from 'highlight.js/lib/languages/php'; 3 | import twig from 'highlight.js/lib/languages/twig'; 4 | 5 | hljs.registerLanguage('php', php); 6 | hljs.registerLanguage('twig', twig); 7 | 8 | hljs.initHighlightingOnLoad(); 9 | -------------------------------------------------------------------------------- /assets/js/login.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | var usernameEl = $('#username'); 3 | var passwordEl = $('#password'); 4 | 5 | // in a real application, the user/password should never be hardcoded 6 | // but for the demo application it's very convenient to do so 7 | if (!usernameEl.val() || 'jane_admin' === usernameEl.val()) { 8 | usernameEl.val('jane_admin'); 9 | passwordEl.val('kitten'); 10 | } 11 | }); 12 | -------------------------------------------------------------------------------- /assets/js/search.js: -------------------------------------------------------------------------------- 1 | import './jquery.instantSearch.js'; 2 | 3 | $(function() { 4 | $('.search-field').instantSearch({ 5 | delay: 100, 6 | }); 7 | }); 8 | -------------------------------------------------------------------------------- /assets/scss/admin.scss: -------------------------------------------------------------------------------- 1 | @import "~bootswatch/flatly/variables"; 2 | @import "~eonasdan-bootstrap-datetimepicker/src/sass/bootstrap-datetimepicker-build.scss"; 3 | @import "bootstrap-tagsinput.scss"; 4 | 5 | /* Page: 'Backend post index' 6 | ------------------------------------------------------------------------- */ 7 | body#admin_post_index .item-actions { 8 | white-space: nowrap 9 | } 10 | 11 | body#admin_post_index .item-actions a.btn + a.btn { 12 | margin-left: 4px 13 | } 14 | 15 | /* Page: 'Backend post show' 16 | ------------------------------------------------------------------------- */ 17 | body#admin_post_show .post-tags .label-default { 18 | background-color: #e9ecec; 19 | color: #6D8283; 20 | font-size: 16px; 21 | margin-right: 10px; 22 | padding: .4em 1em .5em; 23 | } 24 | body#admin_post_show .post-tags .label-default i { 25 | color: #95A6A7; 26 | } 27 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | getParameterOption(['--env', '-e'], null, true)) { 23 | putenv('APP_ENV='.$_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = $env); 24 | } 25 | 26 | if ($input->hasParameterOption('--no-debug', true)) { 27 | putenv('APP_DEBUG='.$_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = '0'); 28 | } 29 | 30 | require dirname(__DIR__).'/config/bootstrap.php'; 31 | 32 | if ($_SERVER['APP_DEBUG']) { 33 | umask(0000); 34 | 35 | if (class_exists(Debug::class)) { 36 | Debug::enable(); 37 | } 38 | } 39 | 40 | $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']); 41 | $application = new Application($kernel); 42 | $application->run($input); 43 | -------------------------------------------------------------------------------- /bin/phpunit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | = 7.4", 13 | "ext-pdo_sqlite": "*", 14 | "doctrine/doctrine-bundle": "^1.12|^2.0", 15 | "doctrine/doctrine-migrations-bundle": "^1.3|^2.0", 16 | "doctrine/orm": "^2.5.11", 17 | "erusev/parsedown": "^1.6", 18 | "sensio/framework-extra-bundle": "^5.1", 19 | "symfony/apache-pack": "^1.0", 20 | "symfony/asset": "5.0.*", 21 | "symfony/console": "5.0.*", 22 | "symfony/dotenv": "5.0.*", 23 | "symfony/expression-language": "*", 24 | "symfony/flex": "^1.1", 25 | "symfony/form": "5.0.*", 26 | "symfony/framework-bundle": "*", 27 | "symfony/intl": "5.0.*", 28 | "symfony/mailer": "5.0.*", 29 | "symfony/monolog-bundle": "^3.1", 30 | "symfony/polyfill-intl-messageformatter": "^1.12", 31 | "symfony/security-bundle": "5.0.*", 32 | "symfony/string": "5.0.*", 33 | "symfony/translation": "5.0.*", 34 | "symfony/twig-bundle": "5.0.*", 35 | "symfony/validator": "5.0.*", 36 | "symfony/webpack-encore-bundle": "^1.4", 37 | "symfony/yaml": "5.0.*", 38 | "tgalopin/html-sanitizer-bundle": "^1.1", 39 | "twig/intl-extra": "^3.0", 40 | "twig/twig": "^3.0" 41 | }, 42 | "require-dev": { 43 | "dama/doctrine-test-bundle": "^6.2", 44 | "doctrine/doctrine-fixtures-bundle": "^3.0", 45 | "friendsofphp/php-cs-fixer": "3.0.x-dev", 46 | "symfony/browser-kit": "5.0.*", 47 | "symfony/css-selector": "5.0.*", 48 | "symfony/debug-bundle": "5.0.*", 49 | "symfony/maker-bundle": "^1.11", 50 | "symfony/phpunit-bridge": "5.0.*", 51 | "symfony/stopwatch": "5.0.*", 52 | "symfony/web-profiler-bundle": "5.0.*" 53 | }, 54 | "config": { 55 | "platform": { 56 | "php": "7.4" 57 | }, 58 | "preferred-install": { 59 | "*": "dist" 60 | }, 61 | "sort-packages": true 62 | }, 63 | "autoload": { 64 | "psr-4": { 65 | "App\\": "src/", 66 | "Acme\\FooBundle\\": "lib/acme/foo-bundle/" 67 | } 68 | }, 69 | "autoload-dev": { 70 | "psr-4": { 71 | "App\\Tests\\": "tests/", 72 | "Acme\\FooBundle\\": "lib/acme/foo-bundle/" 73 | } 74 | }, 75 | "scripts": { 76 | "auto-scripts": { 77 | "cache:clear": "symfony-cmd", 78 | "assets:install --symlink --relative %PUBLIC_DIR%": "symfony-cmd" 79 | }, 80 | "post-install-cmd": [ 81 | "@auto-scripts" 82 | ], 83 | "post-update-cmd": [ 84 | "@auto-scripts" 85 | ] 86 | }, 87 | "conflict": { 88 | "symfony/symfony": "*" 89 | }, 90 | "extra": { 91 | "symfony": { 92 | "allow-contrib": true, 93 | "require": "5.0.*" 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /config/bootstrap.php: -------------------------------------------------------------------------------- 1 | =1.2) 9 | if (is_array($env = @include dirname(__DIR__).'/.env.local.php') && ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $env['APP_ENV']) === $env['APP_ENV']) { 10 | foreach ($env as $k => $v) { 11 | $_ENV[$k] = $_ENV[$k] ?? (isset($_SERVER[$k]) && 0 !== strpos($k, 'HTTP_') ? $_SERVER[$k] : $v); 12 | } 13 | } elseif (!class_exists(Dotenv::class)) { 14 | throw new RuntimeException('Please run "composer require symfony/dotenv" to load the ".env" files configuring the application.'); 15 | } else { 16 | // load all the .env files 17 | (new Dotenv(false))->loadEnv(dirname(__DIR__).'/.env'); 18 | } 19 | 20 | $_SERVER += $_ENV; 21 | $_SERVER['APP_ENV'] = $_ENV['APP_ENV'] = ($_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? null) ?: 'dev'; 22 | $_SERVER['APP_DEBUG'] = $_SERVER['APP_DEBUG'] ?? $_ENV['APP_DEBUG'] ?? 'prod' !== $_SERVER['APP_ENV']; 23 | $_SERVER['APP_DEBUG'] = $_ENV['APP_DEBUG'] = (int) $_SERVER['APP_DEBUG'] || filter_var($_SERVER['APP_DEBUG'], FILTER_VALIDATE_BOOLEAN) ? '1' : '0'; 24 | -------------------------------------------------------------------------------- /config/bundles.php: -------------------------------------------------------------------------------- 1 | ['all' => true], 5 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], 6 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], 7 | Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class => ['all' => true], 8 | Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], 9 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], 10 | Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true], 11 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], 12 | DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true], 13 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], 14 | Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], 15 | Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], 16 | HtmlSanitizer\Bundle\HtmlSanitizerBundle::class => ['all' => true], 17 | Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], 18 | Acme\FooBundle\AcmeFooBundle::class => ['all' => true], 19 | ]; 20 | -------------------------------------------------------------------------------- /config/packages/acme_foo.yaml: -------------------------------------------------------------------------------- 1 | acme_foo: 2 | user_provider: \App\Entity\User 3 | bar: 4 | - acme_foo.ipsum 5 | - acme_foo.lorem 6 | integer_foo: 50 7 | integer_bar: 2 -------------------------------------------------------------------------------- /config/packages/assets.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | assets: 3 | json_manifest_path: '%kernel.project_dir%/public/build/manifest.json' 4 | -------------------------------------------------------------------------------- /config/packages/cache.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | cache: 3 | # Unique name of your app: used to compute stable namespaces for cache keys. 4 | #prefix_seed: your_vendor_name/app_name 5 | 6 | # The "app" cache stores to the filesystem by default. 7 | # The data in this cache should persist between deploys. 8 | # Other options include: 9 | 10 | # Redis 11 | #app: cache.adapter.redis 12 | #default_redis_provider: redis://localhost 13 | 14 | # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) 15 | #app: cache.adapter.apcu 16 | 17 | # Namespaced pools use the above "app" backend by default 18 | #pools: 19 | #my.dedicated.cache: null 20 | -------------------------------------------------------------------------------- /config/packages/dev/debug.yaml: -------------------------------------------------------------------------------- 1 | debug: 2 | # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser. 3 | # See the "server:dump" command to start a new server. 4 | dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%" 5 | -------------------------------------------------------------------------------- /config/packages/dev/mailer.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | mailer: 3 | # this disables delivery of messages entirely 4 | dsn: 'null://null' 5 | -------------------------------------------------------------------------------- /config/packages/dev/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: stream 5 | path: "%kernel.logs_dir%/%kernel.environment%.log" 6 | level: debug 7 | channels: ["!event"] 8 | # uncomment to get logging in your browser 9 | # you may have to allow bigger header sizes in your Web server configuration 10 | #firephp: 11 | # type: firephp 12 | # level: info 13 | #chromephp: 14 | # type: chromephp 15 | # level: info 16 | console: 17 | type: console 18 | process_psr_3_messages: false 19 | channels: ["!event", "!doctrine", "!console"] 20 | -------------------------------------------------------------------------------- /config/packages/dev/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: true 4 | -------------------------------------------------------------------------------- /config/packages/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: true 3 | intercept_redirects: false 4 | 5 | framework: 6 | profiler: { only_exceptions: false } 7 | -------------------------------------------------------------------------------- /config/packages/doctrine.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | # Adds a fallback DATABASE_URL if the env var is not set. This allows you 3 | # to run cache:warmup even if your environment variables are not available 4 | # yet. You should not need to change this value. 5 | env(DATABASE_URL): '' 6 | 7 | doctrine: 8 | dbal: 9 | url: '%env(resolve:DATABASE_URL)%' 10 | 11 | # IMPORTANT: when not use SQLite, you MUST configure your db driver and 12 | # server version, either here or in the DATABASE_URL env var (see .env file) 13 | # driver: 'pdo_sqlite' 14 | # server_version: '3.15' 15 | 16 | # Only needed for MySQL (ignored otherwise) 17 | # charset: utf8mb4 18 | # default_table_options: 19 | # collate: utf8mb4_unicode_ci 20 | orm: 21 | auto_generate_proxy_classes: true 22 | naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware 23 | auto_mapping: true 24 | mappings: 25 | App: 26 | is_bundle: false 27 | type: annotation 28 | dir: '%kernel.project_dir%/src/Entity' 29 | prefix: 'App\Entity' 30 | alias: App 31 | -------------------------------------------------------------------------------- /config/packages/doctrine_migrations.yaml: -------------------------------------------------------------------------------- 1 | doctrine_migrations: 2 | dir_name: '%kernel.project_dir%/src/Migrations' 3 | # namespace is arbitrary but should be different from App\Migrations 4 | # as migrations classes should NOT be autoloaded 5 | namespace: DoctrineMigrations 6 | -------------------------------------------------------------------------------- /config/packages/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | secret: '%env(APP_SECRET)%' 3 | csrf_protection: true 4 | http_method_override: true 5 | trusted_hosts: null 6 | 7 | # Enables session support. Note that the session will ONLY be started if you read or write from it. 8 | # Remove or comment this section to explicitly disable session support. 9 | session: 10 | handler_id: null 11 | cookie_secure: auto 12 | cookie_samesite: lax 13 | 14 | # When using the HTTP Cache, ESI allows to render page fragments separately 15 | # and with different cache configurations for each fragment 16 | # https://symfony.com/doc/current/http_cache/esi.html 17 | esi: true 18 | fragments: true 19 | 20 | php_errors: 21 | log: true 22 | 23 | # The 'ide' option turns all of the file paths in an exception page 24 | # into clickable links that open the given file using your favorite IDE. 25 | # When 'ide' is set to null the file is opened in your web browser. 26 | # See https://symfony.com/doc/current/reference/configuration/framework.html#ide 27 | ide: null 28 | -------------------------------------------------------------------------------- /config/packages/html_sanitizer.yaml: -------------------------------------------------------------------------------- 1 | html_sanitizer: 2 | default_sanitizer: 'default' 3 | sanitizers: 4 | default: 5 | # Read https://github.com/tgalopin/html-sanitizer/blob/master/docs/1-getting-started.md#extensions 6 | # to learn more about which extensions you would like to enable. 7 | extensions: 8 | - 'basic' 9 | - 'list' 10 | - 'table' 11 | - 'image' 12 | - 'code' 13 | 14 | # Read https://github.com/tgalopin/html-sanitizer/blob/master/docs/3-configuration-reference.md 15 | # to discover all the available options for each extension. 16 | -------------------------------------------------------------------------------- /config/packages/mailer.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | mailer: 3 | dsn: '%env(MAILER_DSN)%' 4 | -------------------------------------------------------------------------------- /config/packages/prod/doctrine.yaml: -------------------------------------------------------------------------------- 1 | doctrine: 2 | orm: 3 | auto_generate_proxy_classes: false 4 | metadata_cache_driver: 5 | type: pool 6 | id: doctrine.system_cache_provider 7 | query_cache_driver: 8 | type: pool 9 | id: doctrine.system_cache_provider 10 | result_cache_driver: 11 | type: pool 12 | id: doctrine.result_cache_provider 13 | 14 | framework: 15 | cache: 16 | pools: 17 | doctrine.result_cache_pool: 18 | adapter: cache.app 19 | doctrine.system_cache_pool: 20 | adapter: cache.system 21 | -------------------------------------------------------------------------------- /config/packages/prod/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: fingers_crossed 5 | action_level: error 6 | handler: nested 7 | excluded_http_codes: [404, 405] 8 | nested: 9 | type: stream 10 | path: "%kernel.logs_dir%/%kernel.environment%.log" 11 | level: debug 12 | console: 13 | type: console 14 | process_psr_3_messages: false 15 | channels: ["!event", "!doctrine"] 16 | deprecation: 17 | type: stream 18 | path: "%kernel.logs_dir%/%kernel.environment%.deprecations.log" 19 | deprecation_filter: 20 | type: filter 21 | handler: deprecation 22 | max_level: info 23 | channels: ["php"] 24 | -------------------------------------------------------------------------------- /config/packages/prod/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: null 4 | -------------------------------------------------------------------------------- /config/packages/prod/webpack_encore.yaml: -------------------------------------------------------------------------------- 1 | #webpack_encore: 2 | # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes) 3 | # Available in version 1.2 4 | #cache: true 5 | -------------------------------------------------------------------------------- /config/packages/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | utf8: true 4 | -------------------------------------------------------------------------------- /config/packages/security.yaml: -------------------------------------------------------------------------------- 1 | security: 2 | encoders: 3 | # Our user class and the algorithm we'll use to encode passwords 4 | # 'auto' means to let Symfony choose the best possible password hasher (Argon2 or Bcrypt) 5 | # https://symfony.com/doc/current/security.html#c-encoding-passwords 6 | App\Entity\User: 'auto' 7 | 8 | providers: 9 | # https://symfony.com/doc/current/security/user_provider.html 10 | # In this example, users are stored via Doctrine in the database 11 | # To see the users at src/App/DataFixtures/ORM/LoadFixtures.php 12 | # To load users from somewhere else: https://symfony.com/doc/current/security/user_provider.html#creating-a-custom-user-provider 13 | database_users: 14 | entity: { class: App\Entity\User, property: username } 15 | 16 | # https://symfony.com/doc/current/security.html#a-authentication-firewalls 17 | firewalls: 18 | dev: 19 | pattern: ^/(_(profiler|wdt)|css|images|js)/ 20 | security: false 21 | 22 | main: 23 | # this firewall applies to all URLs 24 | pattern: ^/ 25 | 26 | # but the firewall does not require login on every page 27 | # denying access is done in access_control or in your controllers 28 | anonymous: lazy 29 | 30 | # This allows the user to login by submitting a username and password 31 | # Reference: https://symfony.com/doc/current/security/form_login_setup.html 32 | form_login: 33 | # The route name that the login form submits to 34 | check_path: security_login 35 | # The name of the route where the login form lives 36 | # When the user tries to access a protected page, they are redirected here 37 | login_path: security_login 38 | # Secure the login form against CSRF 39 | # Reference: https://symfony.com/doc/current/security/csrf.html#csrf-protection-in-login-forms 40 | csrf_token_generator: security.csrf.token_manager 41 | # The page users are redirect to when there is no previous page stored in the 42 | # session (for example when the users access directly to the login page). 43 | default_target_path: blog_index 44 | 45 | logout: 46 | # The route name the user can go to in order to logout 47 | path: security_logout 48 | # The name of the route to redirect to after logging out 49 | target: homepage 50 | 51 | # Used to restrict access for large sections of your site 52 | # Note: Only the *first* access control that matches will be used 53 | access_control: 54 | # this is a catch-all for the admin area 55 | # additional security lives in the controllers 56 | - { path: '^/(%app_locales%)/admin', roles: ROLE_ADMIN } 57 | 58 | role_hierarchy: 59 | ROLE_ADMIN: ROLE_USER 60 | -------------------------------------------------------------------------------- /config/packages/sensio_framework_extra.yaml: -------------------------------------------------------------------------------- 1 | sensio_framework_extra: 2 | router: 3 | annotations: false 4 | -------------------------------------------------------------------------------- /config/packages/test/dama_doctrine_test_bundle.yaml: -------------------------------------------------------------------------------- 1 | dama_doctrine_test: 2 | enable_static_connection: true 3 | enable_static_meta_data_cache: true 4 | enable_static_query_cache: true 5 | -------------------------------------------------------------------------------- /config/packages/test/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | test: true 3 | session: 4 | storage_id: session.storage.mock_file 5 | -------------------------------------------------------------------------------- /config/packages/test/mailer.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | mailer: 3 | # this disables delivery of messages entirely 4 | dsn: 'null://null' 5 | -------------------------------------------------------------------------------- /config/packages/test/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | handlers: 3 | main: 4 | type: stream 5 | path: "%kernel.logs_dir%/%kernel.environment%.log" 6 | level: debug 7 | channels: ["!event"] 8 | -------------------------------------------------------------------------------- /config/packages/test/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | strict_requirements: true 4 | -------------------------------------------------------------------------------- /config/packages/test/security.yaml: -------------------------------------------------------------------------------- 1 | # this configuration simplifies testing URLs protected by the security mechanism 2 | # See https://symfony.com/doc/current/testing/http_authentication.html 3 | security: 4 | firewalls: 5 | main: 6 | http_basic: ~ 7 | -------------------------------------------------------------------------------- /config/packages/test/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | strict_variables: true 3 | -------------------------------------------------------------------------------- /config/packages/test/validator.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | validation: 3 | not_compromised_password: false 4 | -------------------------------------------------------------------------------- /config/packages/test/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler: 2 | toolbar: false 3 | intercept_redirects: false 4 | 5 | framework: 6 | profiler: { collect: false } 7 | -------------------------------------------------------------------------------- /config/packages/test/webpack_encore.yaml: -------------------------------------------------------------------------------- 1 | #webpack_encore: 2 | # strict_mode: false 3 | -------------------------------------------------------------------------------- /config/packages/translation.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | default_locale: '%locale%' 3 | translator: 4 | default_path: '%kernel.project_dir%/translations' 5 | fallbacks: 6 | - '%locale%' 7 | -------------------------------------------------------------------------------- /config/packages/twig.yaml: -------------------------------------------------------------------------------- 1 | twig: 2 | default_path: '%kernel.project_dir%/templates' 3 | debug: '%kernel.debug%' 4 | strict_variables: '%kernel.debug%' 5 | exception_controller: null 6 | form_themes: 7 | - 'form/layout.html.twig' 8 | - 'form/fields.html.twig' 9 | -------------------------------------------------------------------------------- /config/packages/validator.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | validation: 3 | enable_annotations: true 4 | email_validation_mode: html5 5 | 6 | # Enables validator auto-mapping support. 7 | # For instance, basic validation constraints will be inferred from Doctrine's metadata. 8 | auto_mapping: 9 | App\Entity\: [] 10 | -------------------------------------------------------------------------------- /config/packages/webpack_encore.yaml: -------------------------------------------------------------------------------- 1 | webpack_encore: 2 | # The path where Encore is building the assets - i.e. Encore.setOutputPath() 3 | output_path: '%kernel.project_dir%/public/build' 4 | # If multiple builds are defined (as shown below), you can disable the default build: 5 | # output_path: false 6 | 7 | # if using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials') 8 | # crossorigin: 'anonymous' 9 | 10 | # preload all rendered script and link tags automatically via the http2 Link header 11 | # preload: true 12 | 13 | # Throw an exception if the entrypoints.json file is missing or an entry is missing from the data 14 | # strict_mode: false 15 | 16 | # if you have multiple builds: 17 | # builds: 18 | # pass "frontend" as the 3rg arg to the Twig functions 19 | # {{ encore_entry_script_tags('entry1', null, 'frontend') }} 20 | 21 | # frontend: '%kernel.project_dir%/public/frontend/build' 22 | 23 | # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes) 24 | # Put in config/packages/prod/webpack_encore.yaml 25 | # cache: true 26 | -------------------------------------------------------------------------------- /config/routes.yaml: -------------------------------------------------------------------------------- 1 | # These lines define a route using YAML configuration. The controller used by 2 | # the route (FrameworkBundle:Template:template) is a convenient shortcut when 3 | # the template can be rendered without executing any logic in your own controller. 4 | # See https://symfony.com/doc/current/templates.html#rendering-a-template-directly-from-a-route 5 | homepage: 6 | path: /{_locale} 7 | controller: Symfony\Bundle\FrameworkBundle\Controller\TemplateController::templateAction 8 | requirements: 9 | _locale: '%app_locales%' 10 | defaults: 11 | template: default/homepage.html.twig 12 | _locale: '%locale%' 13 | -------------------------------------------------------------------------------- /config/routes/annotations.yaml: -------------------------------------------------------------------------------- 1 | controllers: 2 | resource: '../../src/Controller/' 3 | type: annotation 4 | prefix: /{_locale} 5 | requirements: 6 | _locale: '%app_locales%' 7 | defaults: 8 | _locale: '%locale%' 9 | -------------------------------------------------------------------------------- /config/routes/dev/framework.yaml: -------------------------------------------------------------------------------- 1 | _errors: 2 | resource: '@FrameworkBundle/Resources/config/routing/errors.xml' 3 | prefix: /_error 4 | -------------------------------------------------------------------------------- /config/routes/dev/web_profiler.yaml: -------------------------------------------------------------------------------- 1 | web_profiler_wdt: 2 | resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' 3 | prefix: /_wdt 4 | 5 | web_profiler_profiler: 6 | resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' 7 | prefix: /_profiler 8 | -------------------------------------------------------------------------------- /config/services.yaml: -------------------------------------------------------------------------------- 1 | # Put parameters here that don't need to change on each machine where the app is deployed 2 | # https://symfony.com/doc/current/best_practices.html#configuration 3 | parameters: 4 | locale: 'en' 5 | # This parameter defines the codes of the locales (languages) enabled in the application 6 | app_locales: en|fr|de|es|cs|nl|ru|uk|ro|pt_BR|pl|it|ja|id|ca|sl|hr|zh_CN|bg|tr|lt 7 | app.notifications.email_sender: anonymous@example.com 8 | 9 | services: 10 | # default configuration for services in *this* file 11 | _defaults: 12 | autowire: true # Automatically injects dependencies in your services. 13 | autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. 14 | bind: # defines the scalar arguments once and apply them to any service defined/created in this file 15 | $locales: '%app_locales%' 16 | $defaultLocale: '%locale%' 17 | $emailSender: '%app.notifications.email_sender%' 18 | 19 | # makes classes in src/ available to be used as services 20 | # this creates a service per class whose id is the fully-qualified class name 21 | App\: 22 | resource: '../src/*' 23 | exclude: '../src/{DependencyInjection,Entity,Migrations,Tests,Kernel.php}' 24 | 25 | # controllers are imported separately to make sure services can be injected 26 | # as action arguments even if you don't extend any base controller class 27 | App\Controller\: 28 | resource: '../src/Controller' 29 | tags: ['controller.service_arguments'] 30 | 31 | # when the service definition only contains arguments, you can omit the 32 | # 'arguments' key and define the arguments just below the service class 33 | App\EventSubscriber\CommentNotificationSubscriber: 34 | $sender: '%app.notifications.email_sender%' 35 | 36 | # needed to activate the filters provided by Twig Intl Extension 37 | Twig\Extra\Intl\IntlExtension: null 38 | -------------------------------------------------------------------------------- /data/database.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/data/database.sqlite -------------------------------------------------------------------------------- /data/database_test.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/data/database_test.sqlite -------------------------------------------------------------------------------- /lib/acme/foo-bundle/.gitignore: -------------------------------------------------------------------------------- 1 | ###> symfony/framework-bundle ### 2 | /vendor/ 3 | ###< symfony/framework-bundle ### 4 | 5 | ###> symfony/phpunit-bridge ### 6 | .phpunit 7 | .phpunit.result.cache 8 | /phpunit.xml 9 | ###< symfony/phpunit-bridge ### 10 | 11 | -------------------------------------------------------------------------------- /lib/acme/foo-bundle/.travis: -------------------------------------------------------------------------------- 1 | language: php 2 | sudo: false 3 | cache: 4 | directories: 5 | - $HOME/.composer/cache/files 6 | 7 | env: 8 | global: 9 | - PHPUNIT_FLAGS="-v" 10 | 11 | matrix: 12 | fast_finish: true 13 | include: 14 | # Minimum supported dependencies with the latest and oldest PHP version 15 | - php: 7.2 16 | - php: 7.3 17 | env: COMPOSER_FLAGS="--prefer-stable --prefer-lowest" SYMFONY_DEPRECATIONS_HELPER="weak_vendors" 18 | 19 | # Test the latest stable release 20 | - php: 7.2 21 | - php: 7.3 22 | env: COVERAGE=true PHPUNIT_FLAGS="-v --coverage-text" 23 | 24 | # Latest commit to master 25 | - php: 7.2 26 | - php: 7.3 27 | env: STABILITY="dev" 28 | 29 | allow_failures: 30 | # Dev-master is allowed to fail. 31 | - env: STABILITY="dev" 32 | 33 | before_install: 34 | - if [[ $COVERAGE != true ]]; then phpenv config-rm xdebug.ini || true; fi 35 | - if ! [ -z "$STABILITY" ]; then composer config minimum-stability ${STABILITY}; fi; 36 | - if ! [ -v "$DEPENDENCIES" ]; then composer require --no-update ${DEPENDENCIES}; fi; 37 | 38 | install: 39 | - composer install 40 | - ./bin/phpunit install 41 | 42 | script: 43 | - composer validate --no-check-lock 44 | # simple-phpunit is the PHPUnit wrapper provided by the PHPUnit Bridge component and 45 | # it helps with testing legacy code and deprecations (composer require symfony/phpunit-bridge) 46 | - ./bin/phpunit $PHPUNIT_FLAGS -------------------------------------------------------------------------------- /lib/acme/foo-bundle/AcmeFooBundle.php: -------------------------------------------------------------------------------- 1 | service = $service; 19 | } 20 | 21 | public function foo(RequestStack $requestStack, $a, $b) 22 | { 23 | $request = $requestStack->getCurrentRequest(); 24 | 25 | if (!$request->isXmlHttpRequest()) { 26 | throw new AccessDeniedException(); 27 | } 28 | 29 | try { 30 | // TODO: Your service call 31 | $result = $this->service->foo($a, $b); 32 | } catch (AccessDeniedException $e) { 33 | // TODO: Catch exception access denied 34 | return $this->json($e->getMessage(), $e->getCode()); 35 | } catch (\Exception $e) { 36 | // TODO: Catch unknown exception 37 | return $this->json($e->getMessage(), $e->getCode()); 38 | } 39 | 40 | return $this->json($result, 200); 41 | } 42 | 43 | public function createCar(RequestStack $requestStack) 44 | { 45 | $request = $requestStack->getCurrentRequest(); 46 | 47 | if (!$request->isXmlHttpRequest()) { 48 | throw new AccessDeniedException(); 49 | } 50 | 51 | try { 52 | // TODO: Example using DTO 53 | $carDTO = CarDTO::fromRequest($request); 54 | $brand = $carDTO->getBrand(); 55 | $model = $carDTO->getModel(); 56 | 57 | $car = $this->service->createCar($brand, $model); 58 | 59 | $carDTO = CarDTO::toDTO($car); 60 | $response = CarDTO::toResponse($carDTO); 61 | 62 | } catch (AccessDeniedException $e) { 63 | // TODO: Catch exception access denied 64 | return $this->json($e->getMessage(), $e->getCode()); 65 | } catch (\Exception $e) { 66 | // TODO: Catch unknown exception 67 | return $this->json('Unknown exception', $e->getCode()); 68 | } 69 | 70 | return $response; 71 | } 72 | } -------------------------------------------------------------------------------- /lib/acme/foo-bundle/DTO/CarDTO.php: -------------------------------------------------------------------------------- 1 | id = $id; 22 | $this->brand = $brand; 23 | $this->model = $model; 24 | } 25 | 26 | public static function fromRequest(Request $request) 27 | { 28 | $builder = new CarDTOBuilder(); 29 | 30 | return $builder 31 | ->withId($request->request->get(self::ID)) 32 | ->withBrand($request->request->get(self::BRAND)) 33 | ->withModel($request->request->get(self::MODEL)) 34 | ->build(); 35 | 36 | } 37 | 38 | public static function toResponse(CarDTO $carDTO) 39 | { 40 | $response = new Response(); 41 | $response->setContent($carDTO->jsonSerialize()); 42 | 43 | return $response; 44 | } 45 | 46 | public static function toDTO(Car $car) 47 | { 48 | $builder = new CarDTOBuilder(); 49 | 50 | return $builder 51 | ->withId($car->getId()) 52 | ->withBrand($car->getBrand()) 53 | ->withModel($car->getModel()) 54 | ->build(); 55 | } 56 | 57 | public function getId() 58 | { 59 | return $this->id; 60 | } 61 | 62 | public function setId($id) 63 | { 64 | $this->id = $id; 65 | } 66 | 67 | public function getBrand() 68 | { 69 | return $this->brand; 70 | } 71 | 72 | public function setBrand($brand) 73 | { 74 | $this->brand = $brand; 75 | } 76 | 77 | public function getModel() 78 | { 79 | return $this->model; 80 | } 81 | 82 | public function setModel($model) 83 | { 84 | $this->model = $model; 85 | } 86 | 87 | public function jsonSerialize() 88 | { 89 | return array( 90 | 'id' => $this->id, 91 | 'brand' => $this->brand, 92 | 'model' => $this->model, 93 | ); 94 | } 95 | } -------------------------------------------------------------------------------- /lib/acme/foo-bundle/DTO/CarDTOBuilder.php: -------------------------------------------------------------------------------- 1 | id = $id; 14 | 15 | return $this; 16 | } 17 | 18 | public function withBrand($brand) 19 | { 20 | $this->brand = $brand; 21 | 22 | return $this; 23 | } 24 | 25 | public function withModel($model) 26 | { 27 | $this->model = $model; 28 | 29 | return $this; 30 | } 31 | 32 | public function build() 33 | { 34 | return new CarDTO( 35 | $this->id, 36 | $this->brand, 37 | $this->model 38 | ); 39 | } 40 | } -------------------------------------------------------------------------------- /lib/acme/foo-bundle/DependencyInjection/AcmeFooExtension.php: -------------------------------------------------------------------------------- 1 | load('services.xml'); 17 | $config = $this->processConfiguration(new Configuration(), $configs); 18 | // TODO: Set custom parameters 19 | $container->setParameter('acme_foo.bar', $config['bar']); 20 | $container->setParameter('acme_foo.integer_foo', $config['integer_foo']); 21 | $container->setParameter('acme_foo.integer_bar', $config['integer_bar']); 22 | } 23 | 24 | public function prepend(ContainerBuilder $container) 25 | { 26 | $configs = $container->getExtensionConfig($this->getAlias()); 27 | $config = $this->processConfiguration(new Configuration(), $configs); 28 | // TODO: Set custom doctrine config 29 | $doctrineConfig = []; 30 | $doctrineConfig['orm']['resolve_target_entities']['Acme\FooBundle\Entity\UserInterface'] = $config['user_provider']; 31 | $doctrineConfig['orm']['mappings'][] = array( 32 | 'name' => 'AcmeFooBundle', 33 | 'is_bundle' => true, 34 | 'type' => 'xml', 35 | 'prefix' => 'Acme\FooBundle\Entity' 36 | ); 37 | $container->prependExtensionConfig('doctrine', $doctrineConfig); 38 | // TODO: Set custom twig config 39 | $twigConfig = []; 40 | $twigConfig['globals']['acme_foo_bar_service'] = "@acme_foo.service"; 41 | $twigConfig['paths'][__DIR__.'/../Resources/views'] = "acme_foo"; 42 | $twigConfig['paths'][__DIR__.'/../Resources/public'] = "acme_foo.public"; 43 | $container->prependExtensionConfig('twig', $twigConfig); 44 | } 45 | 46 | public function getAlias() 47 | { 48 | return 'acme_foo'; 49 | } 50 | } -------------------------------------------------------------------------------- /lib/acme/foo-bundle/DependencyInjection/Configuration.php: -------------------------------------------------------------------------------- 1 | getRootNode(); 20 | $rootNode->children() 21 | ->scalarNode('user_provider') 22 | ->isRequired() 23 | ->defaultValue('\App\Entity\User') 24 | ->end() 25 | ->arrayNode('bar') 26 | ->isRequired() 27 | ->scalarPrototype() 28 | ->defaultValue([ 29 | 'acme_foo.ipsum', 30 | 'acme_foo.lorem', 31 | ]) 32 | ->end() 33 | ->end() 34 | ->integerNode('integer_foo') 35 | ->isRequired() 36 | ->defaultValue(2) 37 | ->min(1) 38 | ->end() 39 | ->integerNode('integer_bar') 40 | ->isRequired() 41 | ->defaultValue(50) 42 | ->min(1) 43 | ->end() 44 | ->end(); 45 | 46 | return $builder; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Entity/Car.php: -------------------------------------------------------------------------------- 1 | createdAt = $now->getTimestamp(); 17 | } 18 | 19 | public function getId() 20 | { 21 | return $this->id; 22 | } 23 | 24 | public function setId($id) 25 | { 26 | $this->id = $id; 27 | } 28 | 29 | public function getBrand() 30 | { 31 | return $this->brand; 32 | } 33 | 34 | public function setBrand($brand) 35 | { 36 | $this->brand = $brand; 37 | } 38 | 39 | public function getModel() 40 | { 41 | return $this->model; 42 | } 43 | 44 | function setModel($model) 45 | { 46 | $this->model = $model; 47 | } 48 | 49 | public function getUser() 50 | { 51 | return $this->user; 52 | } 53 | 54 | public function setUser($user) 55 | { 56 | $this->user = $user; 57 | } 58 | 59 | public function getCreatedAt() 60 | { 61 | return $this->createdAt; 62 | } 63 | 64 | public function setCreatedAt($createdAt) 65 | { 66 | $this->createdAt = $createdAt; 67 | } 68 | } -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Entity/CarRepository.php: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Resources/config/services.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | %acme_foo.bar% 23 | %acme_foo.integer_foo% 24 | %acme_foo.integer_bar% 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Resources/doc/index.rst: -------------------------------------------------------------------------------- 1 | Getting Started With AcmeFooBundle 2 | ================================== 3 | 4 | TODO: Add the bundle description here 5 | 6 | Prerequisites 7 | ------------- 8 | 9 | This version of the bundle requires Symfony 4.0+. 10 | 11 | TODO: Add the the rest of the bundle documentation here. You can also add more files -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Resources/doc/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/lib/acme/foo-bundle/Resources/doc/logo.png -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Resources/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/lib/acme/foo-bundle/Resources/public/.gitkeep -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Resources/translations/messages.en.yml: -------------------------------------------------------------------------------- 1 | acme_foo: 2 | # TODO: Add your translations here 3 | bar: Bar 4 | ipsum: Ipsum 5 | lorem: Lorem 6 | -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Resources/translations/messages.es.yml: -------------------------------------------------------------------------------- 1 | acme_foo: 2 | # TODO: Add your translations here 3 | bar: Ejemplo 4 | ipsum: Ipsum 5 | lorem: Lorem -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Resources/views/acme_foo_widget.html.twig: -------------------------------------------------------------------------------- 1 | {% macro bar(link, num) %} 2 |
3 |
4 | 7 |
8 | {{ acme_foo_bar_service.foo(num, random(50)) }} 9 |
10 |
11 |
12 | {% endmacro bar %} -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Service/Service.php: -------------------------------------------------------------------------------- 1 | em = $em; 60 | $this->token = $token; 61 | $this->request = $requestStack->getCurrentRequest(); 62 | $this->translator = $translator; 63 | $this->bar = $bar; 64 | $this->integerFoo = (int) $integerFoo; 65 | $this->integerBar = (int) $integerBar; 66 | } 67 | 68 | public function foo($a, $b) 69 | { 70 | return 'This is an uncertain ' . $this->translator->trans($this->bar[0]) . ' output ' . ($a + $b) * $this->integerFoo / $this->integerBar; 71 | } 72 | 73 | public function getCars() 74 | { 75 | $user = $this->token->getToken()->getUser(); 76 | if (!method_exists($user, 'getUsername')) { 77 | $user = null; 78 | } 79 | $carRepository = $this->em->getRepository(Car::class); 80 | 81 | return $carRepository->findBy(['user' => $user]); 82 | } 83 | 84 | public function createCar($brand, $model) 85 | { 86 | $car = new Car(); 87 | $user = $this->token->getToken()->getUser(); 88 | 89 | $car->setBrand($brand); 90 | $car->setModel($model); 91 | if (method_exists($user, 'getUsername')) { 92 | $car->setUser($user); 93 | } 94 | 95 | $this->em->persist($car); 96 | $this->em->flush(); 97 | 98 | return $car; 99 | } 100 | } -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Tests/Mock/UserMock.php: -------------------------------------------------------------------------------- 1 | setDefaultMocks(); 27 | $this->setUserMocks(); 28 | $this->translator = new Translator('en'); 29 | } 30 | 31 | protected function setDefaultMocks() 32 | { 33 | $emRepositoryMock = $this->getMockBuilder(ObjectRepository::class)->getMock(); 34 | $this->emMock = $this->getMockBuilder(EntityManagerInterface::class)->getMock(); 35 | $this->emMock->method('getRepository')->willReturn($emRepositoryMock); 36 | 37 | $requestMock = $this->getMockBuilder(Request::class)->getMock(); 38 | $this->requestStackMock = $this->getMockBuilder(RequestStack::class) 39 | ->disableOriginalConstructor() 40 | ->setMethods(array('getCurrentRequest')) 41 | ->getMock(); 42 | $this->requestStackMock->expects($this->any()) 43 | ->method('getCurrentRequest')->willReturn($requestMock); 44 | } 45 | 46 | protected function setUserMocks() 47 | { 48 | $this->userMock = $this->getMockBuilder(UserMock::class) 49 | ->getMock(); 50 | 51 | $tokenMock = $this->getMockBuilder(TokenInterface::class) 52 | ->disableOriginalConstructor() 53 | ->getMock(); 54 | $tokenMock->method('getUser')->willReturn($this->userMock); 55 | 56 | $this->tokenStorageMock = $this->getMockBuilder(TokenStorageInterface::class) 57 | ->disableOriginalConstructor() 58 | ->getMock(); 59 | $this->tokenStorageMock->method('getToken')->willReturn($tokenMock); 60 | } 61 | 62 | public function testFooWithIntegers() 63 | { 64 | $service = new Service($this->emMock, $this->tokenStorageMock, $this->requestStackMock, $this->translator, 'bar', 67, 12); 65 | 66 | $foo = $service->foo(4, 3); 67 | 68 | $this->assertSame('This is an uncertain output' , $foo); 69 | } 70 | } -------------------------------------------------------------------------------- /lib/acme/foo-bundle/Tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | =7.2", 16 | "symfony/framework-bundle": ">=4.0", 17 | "symfony/yaml": ">=4.0" 18 | }, 19 | "require-dev": { 20 | "symfony/phpunit-bridge": ">=4.0" 21 | }, 22 | "config": { 23 | "platform": { 24 | "php": "7.2" 25 | }, 26 | "preferred-install": { 27 | "*": "dist" 28 | }, 29 | "sort-packages": true 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "Acme\\FooBundle\\": "" 34 | }, 35 | "exclude-from-classmap": [ 36 | "/Tests/" 37 | ] 38 | }, 39 | "autoload-dev": { 40 | "psr-4": { 41 | "Acme\\FooBundle\\Tests\\": "tests/" 42 | } 43 | }, 44 | "conflict": { 45 | "symfony/symfony": "<4.0" 46 | }, 47 | "extra": { 48 | "branch-alias": { 49 | "dev-master": "1.1.x-dev" 50 | } 51 | }, 52 | "minimum-stability": "dev", 53 | "prefer-stable": true 54 | } -------------------------------------------------------------------------------- /lib/acme/foo-bundle/phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ./Tests 12 | 13 | 14 | 15 | 16 | ./ 17 | 18 | ./AcmeFooBundle.php 19 | ./Tests 20 | ./vendor 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@fortawesome/fontawesome-free": "^5.8.1", 4 | "@symfony/webpack-encore": "^0.28.0", 5 | "bloodhound-js": "^1.2.3", 6 | "bootstrap-sass": "^3.3.7", 7 | "bootstrap-tagsinput": "^0.7.1", 8 | "bootswatch": "^3.3.7", 9 | "core-js": "^3.0.0", 10 | "eonasdan-bootstrap-datetimepicker": "^4.17.47", 11 | "highlight.js": "^9.12.0", 12 | "imports-loader": "^0.8.0", 13 | "jquery": "^3.3.1", 14 | "lato-font": "^3.0.0", 15 | "node-sass": "^4.9.3", 16 | "sass-loader": "^7.1.0", 17 | "typeahead.js": "^0.11.1" 18 | }, 19 | "license": "UNLICENSED", 20 | "private": true, 21 | "scripts": { 22 | "dev-server": "encore dev-server", 23 | "dev": "encore dev", 24 | "watch": "encore dev --watch", 25 | "build": "encore production --progress" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | tests 21 | 22 | 23 | 24 | 25 | 26 | src 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/build/entrypoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "entrypoints": { 3 | "app": { 4 | "js": [ 5 | "/build/runtime.js", 6 | "/build/0.js", 7 | "/build/1.js", 8 | "/build/app.js" 9 | ], 10 | "css": [ 11 | "/build/app.css" 12 | ] 13 | }, 14 | "login": { 15 | "js": [ 16 | "/build/runtime.js", 17 | "/build/0.js", 18 | "/build/login.js" 19 | ] 20 | }, 21 | "admin": { 22 | "js": [ 23 | "/build/runtime.js", 24 | "/build/0.js", 25 | "/build/1.js", 26 | "/build/admin.js" 27 | ], 28 | "css": [ 29 | "/build/admin.css" 30 | ] 31 | }, 32 | "search": { 33 | "js": [ 34 | "/build/runtime.js", 35 | "/build/0.js", 36 | "/build/1.js", 37 | "/build/search.js" 38 | ] 39 | } 40 | }, 41 | "integrity": { 42 | "/build/runtime.js": "sha384-/Zh0hTCgqMfXwZfeMIiueZzsKiHkvtqEOzKpZAuznIbgqg1DQpUQAwwNlO/9ToVH", 43 | "/build/0.js": "sha384-Wrx5cwFhKwi1w/WOXvdxo03p4HPA9eQMHtWkqik1WyR60ZCk8PX+JarUxeGfRjA8", 44 | "/build/1.js": "sha384-M368MBNwGmbdgpestFWyw3hJbjT/nzlooRthSLKs25w2A4G4p4EvGrn1obv7NR/1", 45 | "/build/app.js": "sha384-wLsk/8sKxgTxKX2XqtLZfspTXR1gnEg3Ixfi7V1oePRvpLHq3wfw4B86FEehY+6k", 46 | "/build/app.css": "sha384-Ume+TDBYwyw/eCW4xF+o7jQIaEEHDCMcU804fNSIWMJwc5IqpPu5XSRyuCEfOPRG", 47 | "/build/login.js": "sha384-w5qwGnj2mp4pazKe9KGCQU+FR1n/717WouCp594UxY7HHGLafcGrZ9mrFR68V6oe", 48 | "/build/admin.js": "sha384-Myur8WXyHPvUQiu90i/uds22Oy3cNHANN18PYmYpUd2sE2c4FP8CWcKKc8IIA8kg", 49 | "/build/admin.css": "sha384-ilLLAgcQxfeIVl6jV3AsZ2jmrWwgECQptl9HYwqc2NpYuTl6FEW46DBpDk5Q76sp", 50 | "/build/search.js": "sha384-LBeNeX+4T5noBlPLpgoU0O8mJaUY4hFEL51W3tJKTqsM2utN17cCY45jpDU01XKv" 51 | } 52 | } -------------------------------------------------------------------------------- /public/build/fonts/fa-brands-400.088a34f7.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-brands-400.088a34f7.eot -------------------------------------------------------------------------------- /public/build/fonts/fa-brands-400.273dc9bf.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-brands-400.273dc9bf.ttf -------------------------------------------------------------------------------- /public/build/fonts/fa-brands-400.822d94f1.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-brands-400.822d94f1.woff2 -------------------------------------------------------------------------------- /public/build/fonts/fa-brands-400.f4920c94.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-brands-400.f4920c94.woff -------------------------------------------------------------------------------- /public/build/fonts/fa-regular-400.3ac49cb3.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-regular-400.3ac49cb3.eot -------------------------------------------------------------------------------- /public/build/fonts/fa-regular-400.9efb8697.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-regular-400.9efb8697.woff2 -------------------------------------------------------------------------------- /public/build/fonts/fa-regular-400.a57bcf76.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-regular-400.a57bcf76.woff -------------------------------------------------------------------------------- /public/build/fonts/fa-regular-400.ece54318.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-regular-400.ece54318.ttf -------------------------------------------------------------------------------- /public/build/fonts/fa-solid-900.2aa6edf8.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-solid-900.2aa6edf8.ttf -------------------------------------------------------------------------------- /public/build/fonts/fa-solid-900.7fb1cdd9.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-solid-900.7fb1cdd9.eot -------------------------------------------------------------------------------- /public/build/fonts/fa-solid-900.93f28454.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-solid-900.93f28454.woff -------------------------------------------------------------------------------- /public/build/fonts/fa-solid-900.f6121be5.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/fa-solid-900.f6121be5.woff2 -------------------------------------------------------------------------------- /public/build/fonts/lato-bold-italic.0b6bb672.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/lato-bold-italic.0b6bb672.woff2 -------------------------------------------------------------------------------- /public/build/fonts/lato-bold-italic.9c7e4e9e.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/lato-bold-italic.9c7e4e9e.woff -------------------------------------------------------------------------------- /public/build/fonts/lato-bold.cccb8974.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/lato-bold.cccb8974.woff2 -------------------------------------------------------------------------------- /public/build/fonts/lato-bold.d878b6c2.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/lato-bold.d878b6c2.woff -------------------------------------------------------------------------------- /public/build/fonts/lato-normal-italic.4eb103b4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/lato-normal-italic.4eb103b4.woff2 -------------------------------------------------------------------------------- /public/build/fonts/lato-normal-italic.f28f2d64.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/lato-normal-italic.f28f2d64.woff -------------------------------------------------------------------------------- /public/build/fonts/lato-normal.27bd77b9.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/lato-normal.27bd77b9.woff -------------------------------------------------------------------------------- /public/build/fonts/lato-normal.bd03a2cc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/public/build/fonts/lato-normal.bd03a2cc.woff2 -------------------------------------------------------------------------------- /public/build/login.js: -------------------------------------------------------------------------------- 1 | (window.webpackJsonp=window.webpackJsonp||[]).push([["login"],{"23AV":function(n,a,i){(function(n){n((function(){var a=n("#username"),i=n("#password");a.val()&&"jane_admin"!==a.val()||(a.val("jane_admin"),i.val("kitten"))}))}).call(this,i("EVdn"))}},[["23AV","runtime",0]]]); -------------------------------------------------------------------------------- /public/build/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "build/0.js": "/build/0.js", 3 | "build/1.js": "/build/1.js", 4 | "build/admin.css": "/build/admin.css", 5 | "build/admin.js": "/build/admin.js", 6 | "build/app.css": "/build/app.css", 7 | "build/app.js": "/build/app.js", 8 | "build/login.js": "/build/login.js", 9 | "build/runtime.js": "/build/runtime.js", 10 | "build/search.js": "/build/search.js", 11 | "build/fonts/fa-brands-400.eot": "/build/fonts/fa-brands-400.088a34f7.eot", 12 | "build/fonts/fa-brands-400.ttf": "/build/fonts/fa-brands-400.273dc9bf.ttf", 13 | "build/fonts/fa-brands-400.woff2": "/build/fonts/fa-brands-400.822d94f1.woff2", 14 | "build/fonts/fa-brands-400.woff": "/build/fonts/fa-brands-400.f4920c94.woff", 15 | "build/fonts/fa-regular-400.eot": "/build/fonts/fa-regular-400.3ac49cb3.eot", 16 | "build/fonts/fa-regular-400.woff2": "/build/fonts/fa-regular-400.9efb8697.woff2", 17 | "build/fonts/fa-regular-400.woff": "/build/fonts/fa-regular-400.a57bcf76.woff", 18 | "build/fonts/fa-regular-400.ttf": "/build/fonts/fa-regular-400.ece54318.ttf", 19 | "build/fonts/fa-solid-900.ttf": "/build/fonts/fa-solid-900.2aa6edf8.ttf", 20 | "build/fonts/fa-solid-900.eot": "/build/fonts/fa-solid-900.7fb1cdd9.eot", 21 | "build/fonts/fa-solid-900.woff": "/build/fonts/fa-solid-900.93f28454.woff", 22 | "build/fonts/fa-solid-900.woff2": "/build/fonts/fa-solid-900.f6121be5.woff2", 23 | "build/fonts/glyphicons-halflings-regular.woff2": "/build/fonts/glyphicons-halflings-regular.448c34a5.woff2", 24 | "build/fonts/glyphicons-halflings-regular.ttf": "/build/fonts/glyphicons-halflings-regular.e18bbf61.ttf", 25 | "build/fonts/glyphicons-halflings-regular.eot": "/build/fonts/glyphicons-halflings-regular.f4769f9b.eot", 26 | "build/fonts/glyphicons-halflings-regular.woff": "/build/fonts/glyphicons-halflings-regular.fa277232.woff", 27 | "build/fonts/lato-bold-italic.woff2": "/build/fonts/lato-bold-italic.0b6bb672.woff2", 28 | "build/fonts/lato-bold-italic.woff": "/build/fonts/lato-bold-italic.9c7e4e9e.woff", 29 | "build/fonts/lato-bold.woff2": "/build/fonts/lato-bold.cccb8974.woff2", 30 | "build/fonts/lato-bold.woff": "/build/fonts/lato-bold.d878b6c2.woff", 31 | "build/fonts/lato-normal-italic.woff2": "/build/fonts/lato-normal-italic.4eb103b4.woff2", 32 | "build/fonts/lato-normal-italic.woff": "/build/fonts/lato-normal-italic.f28f2d64.woff", 33 | "build/fonts/lato-normal.woff": "/build/fonts/lato-normal.27bd77b9.woff", 34 | "build/fonts/lato-normal.woff2": "/build/fonts/lato-normal.bd03a2cc.woff2", 35 | "build/images/fa-brands-400.svg": "/build/images/fa-brands-400.d7229311.svg", 36 | "build/images/fa-regular-400.svg": "/build/images/fa-regular-400.d2e53334.svg", 37 | "build/images/fa-solid-900.svg": "/build/images/fa-solid-900.7a5de9b0.svg", 38 | "build/images/glyphicons-halflings-regular.svg": "/build/images/glyphicons-halflings-regular.89889688.svg" 39 | } -------------------------------------------------------------------------------- /public/build/runtime.js: -------------------------------------------------------------------------------- 1 | !function(e){function r(r){for(var n,l,i=r[0],f=r[1],a=r[2],c=0,s=[];chandle($request); 26 | $response->send(); 27 | $kernel->terminate($request, $response); 28 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | # www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449 3 | 4 | User-agent: * 5 | -------------------------------------------------------------------------------- /src/Controller/SecurityController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Controller; 13 | 14 | use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; 15 | use Symfony\Component\HttpFoundation\Request; 16 | use Symfony\Component\HttpFoundation\Response; 17 | use Symfony\Component\Routing\Annotation\Route; 18 | use Symfony\Component\Security\Core\Security; 19 | use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; 20 | use Symfony\Component\Security\Http\Util\TargetPathTrait; 21 | 22 | /** 23 | * Controller used to manage the application security. 24 | * See https://symfony.com/doc/current/security/form_login_setup.html. 25 | * 26 | * @author Ryan Weaver 27 | * @author Javier Eguiluz 28 | */ 29 | class SecurityController extends AbstractController 30 | { 31 | use TargetPathTrait; 32 | 33 | /** 34 | * @Route("/login", name="security_login") 35 | */ 36 | public function login(Request $request, Security $security, AuthenticationUtils $helper): Response 37 | { 38 | // if user is already logged in, don't display the login page again 39 | if ($security->isGranted('ROLE_USER')) { 40 | return $this->redirectToRoute('blog_index'); 41 | } 42 | 43 | // this statement solves an edge-case: if you change the locale in the login 44 | // page, after a successful login you are redirected to a page in the previous 45 | // locale. This code regenerates the referrer URL whenever the login page is 46 | // browsed, to ensure that its locale is always the current one. 47 | $this->saveTargetPath($request->getSession(), 'main', $this->generateUrl('admin_index')); 48 | 49 | return $this->render('security/login.html.twig', [ 50 | // last username entered by the user (if any) 51 | 'last_username' => $helper->getLastUsername(), 52 | // last authentication error (if any) 53 | 'error' => $helper->getLastAuthenticationError(), 54 | ]); 55 | } 56 | 57 | /** 58 | * This is the route the user can use to logout. 59 | * 60 | * But, this will never be executed. Symfony will intercept this first 61 | * and handle the logout automatically. See logout in config/packages/security.yaml 62 | * 63 | * @Route("/logout", name="security_logout") 64 | */ 65 | public function logout(): void 66 | { 67 | throw new \Exception('This should never be reached!'); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Controller/UserController.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Controller; 13 | 14 | use App\Form\Type\ChangePasswordType; 15 | use App\Form\UserType; 16 | use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted; 17 | use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; 18 | use Symfony\Component\HttpFoundation\Request; 19 | use Symfony\Component\HttpFoundation\Response; 20 | use Symfony\Component\Routing\Annotation\Route; 21 | use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; 22 | 23 | /** 24 | * Controller used to manage current user. 25 | * 26 | * @Route("/profile") 27 | * @IsGranted("ROLE_USER") 28 | * 29 | * @author Romain Monteil 30 | */ 31 | class UserController extends AbstractController 32 | { 33 | /** 34 | * @Route("/edit", methods="GET|POST", name="user_edit") 35 | */ 36 | public function edit(Request $request): Response 37 | { 38 | $user = $this->getUser(); 39 | 40 | $form = $this->createForm(UserType::class, $user); 41 | $form->handleRequest($request); 42 | 43 | if ($form->isSubmitted() && $form->isValid()) { 44 | $this->getDoctrine()->getManager()->flush(); 45 | 46 | $this->addFlash('success', 'user.updated_successfully'); 47 | 48 | return $this->redirectToRoute('user_edit'); 49 | } 50 | 51 | return $this->render('user/edit.html.twig', [ 52 | 'user' => $user, 53 | 'form' => $form->createView(), 54 | ]); 55 | } 56 | 57 | /** 58 | * @Route("/change-password", methods="GET|POST", name="user_change_password") 59 | */ 60 | public function changePassword(Request $request, UserPasswordEncoderInterface $encoder): Response 61 | { 62 | $user = $this->getUser(); 63 | 64 | $form = $this->createForm(ChangePasswordType::class); 65 | $form->handleRequest($request); 66 | 67 | if ($form->isSubmitted() && $form->isValid()) { 68 | $user->setPassword($encoder->encodePassword($user, $form->get('newPassword')->getData())); 69 | 70 | $this->getDoctrine()->getManager()->flush(); 71 | 72 | return $this->redirectToRoute('security_logout'); 73 | } 74 | 75 | return $this->render('user/change_password.html.twig', [ 76 | 'form' => $form->createView(), 77 | ]); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Entity/Tag.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Entity; 13 | 14 | use Doctrine\ORM\Mapping as ORM; 15 | 16 | /** 17 | * @ORM\Entity() 18 | * @ORM\Table(name="symfony_demo_tag") 19 | * 20 | * Defines the properties of the Tag entity to represent the post tags. 21 | * 22 | * See https://symfony.com/doc/current/doctrine.html#creating-an-entity-class 23 | * 24 | * @author Yonel Ceruto 25 | */ 26 | class Tag implements \JsonSerializable 27 | { 28 | /** 29 | * @var int 30 | * 31 | * @ORM\Id 32 | * @ORM\GeneratedValue 33 | * @ORM\Column(type="integer") 34 | */ 35 | private $id; 36 | 37 | /** 38 | * @var string 39 | * 40 | * @ORM\Column(type="string", unique=true) 41 | */ 42 | private $name; 43 | 44 | public function getId(): ?int 45 | { 46 | return $this->id; 47 | } 48 | 49 | public function setName(string $name): void 50 | { 51 | $this->name = $name; 52 | } 53 | 54 | public function getName(): ?string 55 | { 56 | return $this->name; 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | */ 62 | public function jsonSerialize(): string 63 | { 64 | // This entity implements JsonSerializable (http://php.net/manual/en/class.jsonserializable.php) 65 | // so this method is used to customize its JSON representation when json_encode() 66 | // is called, for example in tags|json_encode (templates/form/fields.html.twig) 67 | 68 | return $this->name; 69 | } 70 | 71 | public function __toString(): string 72 | { 73 | return $this->name; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/EventSubscriber/CommentNotificationSubscriber.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\EventSubscriber; 13 | 14 | use App\Entity\Comment; 15 | use App\Events\CommentCreatedEvent; 16 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; 17 | use Symfony\Component\Mailer\MailerInterface; 18 | use Symfony\Component\Mime\Email; 19 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 20 | use Symfony\Contracts\Translation\TranslatorInterface; 21 | 22 | /** 23 | * Notifies post's author about new comments. 24 | * 25 | * @author Oleg Voronkovich 26 | */ 27 | class CommentNotificationSubscriber implements EventSubscriberInterface 28 | { 29 | private $mailer; 30 | private $translator; 31 | private $urlGenerator; 32 | private $sender; 33 | 34 | public function __construct(MailerInterface $mailer, UrlGeneratorInterface $urlGenerator, TranslatorInterface $translator, $sender) 35 | { 36 | $this->mailer = $mailer; 37 | $this->urlGenerator = $urlGenerator; 38 | $this->translator = $translator; 39 | $this->sender = $sender; 40 | } 41 | 42 | public static function getSubscribedEvents(): array 43 | { 44 | return [ 45 | CommentCreatedEvent::class => 'onCommentCreated', 46 | ]; 47 | } 48 | 49 | public function onCommentCreated(CommentCreatedEvent $event): void 50 | { 51 | /** @var Comment $comment */ 52 | $comment = $event->getComment(); 53 | $post = $comment->getPost(); 54 | 55 | $linkToPost = $this->urlGenerator->generate('blog_post', [ 56 | 'slug' => $post->getSlug(), 57 | '_fragment' => 'comment_'.$comment->getId(), 58 | ], UrlGeneratorInterface::ABSOLUTE_URL); 59 | 60 | $subject = $this->translator->trans('notification.comment_created'); 61 | $body = $this->translator->trans('notification.comment_created.description', [ 62 | '%title%' => $post->getTitle(), 63 | '%link%' => $linkToPost, 64 | ]); 65 | 66 | // See https://symfony.com/doc/current/mailer.html 67 | $email = (new Email()) 68 | ->from($this->sender) 69 | ->to($post->getAuthor()->getEmail()) 70 | ->subject($subject) 71 | ->html($body) 72 | ; 73 | 74 | // In config/packages/dev/mailer.yaml the delivery of messages is disabled. 75 | // That's why in the development environment you won't actually receive any email. 76 | // However, you can inspect the contents of those unsent emails using the debug toolbar. 77 | $this->mailer->send($email); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/EventSubscriber/ControllerSubscriber.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\EventSubscriber; 13 | 14 | use App\Twig\SourceCodeExtension; 15 | use Symfony\Component\EventDispatcher\EventSubscriberInterface; 16 | use Symfony\Component\HttpKernel\Event\ControllerEvent; 17 | use Symfony\Component\HttpKernel\KernelEvents; 18 | 19 | /** 20 | * Defines the method that 'listens' to the 'kernel.controller' event, which is 21 | * triggered whenever a controller is executed in the application. 22 | * 23 | * @author Ryan Weaver 24 | * @author Javier Eguiluz 25 | */ 26 | class ControllerSubscriber implements EventSubscriberInterface 27 | { 28 | private $twigExtension; 29 | 30 | public function __construct(SourceCodeExtension $twigExtension) 31 | { 32 | $this->twigExtension = $twigExtension; 33 | } 34 | 35 | public static function getSubscribedEvents(): array 36 | { 37 | return [ 38 | KernelEvents::CONTROLLER => 'registerCurrentController', 39 | ]; 40 | } 41 | 42 | public function registerCurrentController(ControllerEvent $event): void 43 | { 44 | // this check is needed because in Symfony a request can perform any 45 | // number of sub-requests. See 46 | // https://symfony.com/doc/current/components/http_kernel.html#sub-requests 47 | if ($event->isMasterRequest()) { 48 | $this->twigExtension->setController($event->getController()); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Events/CommentCreatedEvent.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Events; 13 | 14 | use App\Entity\Comment; 15 | use Symfony\Contracts\EventDispatcher\Event; 16 | 17 | class CommentCreatedEvent extends Event 18 | { 19 | protected $comment; 20 | 21 | public function __construct(Comment $comment) 22 | { 23 | $this->comment = $comment; 24 | } 25 | 26 | public function getComment(): Comment 27 | { 28 | return $this->comment; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Form/CommentType.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Form; 13 | 14 | use App\Entity\Comment; 15 | use Symfony\Component\Form\AbstractType; 16 | use Symfony\Component\Form\Extension\Core\Type\TextareaType; 17 | use Symfony\Component\Form\FormBuilderInterface; 18 | use Symfony\Component\OptionsResolver\OptionsResolver; 19 | 20 | /** 21 | * Defines the form used to create and manipulate blog comments. Although in this 22 | * case the form is trivial and we could build it inside the controller, a good 23 | * practice is to always define your forms as classes. 24 | * 25 | * See https://symfony.com/doc/current/forms.html#creating-form-classes 26 | * 27 | * @author Ryan Weaver 28 | * @author Javier Eguiluz 29 | */ 30 | class CommentType extends AbstractType 31 | { 32 | /** 33 | * {@inheritdoc} 34 | */ 35 | public function buildForm(FormBuilderInterface $builder, array $options): void 36 | { 37 | // By default, form fields include the 'required' attribute, which enables 38 | // the client-side form validation. This means that you can't test the 39 | // server-side validation errors from the browser. To temporarily disable 40 | // this validation, set the 'required' attribute to 'false': 41 | // $builder->add('content', null, ['required' => false]); 42 | 43 | $builder 44 | ->add('content', TextareaType::class, [ 45 | 'help' => 'help.comment_content', 46 | ]) 47 | ; 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function configureOptions(OptionsResolver $resolver): void 54 | { 55 | $resolver->setDefaults([ 56 | 'data_class' => Comment::class, 57 | ]); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Form/DataTransformer/TagArrayToStringTransformer.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Form\DataTransformer; 13 | 14 | use App\Entity\Tag; 15 | use App\Repository\TagRepository; 16 | use Symfony\Component\Form\DataTransformerInterface; 17 | use function Symfony\Component\String\u; 18 | 19 | /** 20 | * This data transformer is used to translate the array of tags into a comma separated format 21 | * that can be displayed and managed by Bootstrap-tagsinput js plugin (and back on submit). 22 | * 23 | * See https://symfony.com/doc/current/form/data_transformers.html 24 | * 25 | * @author Yonel Ceruto 26 | * @author Jonathan Boyer 27 | */ 28 | class TagArrayToStringTransformer implements DataTransformerInterface 29 | { 30 | private $tags; 31 | 32 | public function __construct(TagRepository $tags) 33 | { 34 | $this->tags = $tags; 35 | } 36 | 37 | /** 38 | * {@inheritdoc} 39 | */ 40 | public function transform($tags): string 41 | { 42 | // The value received is an array of Tag objects generated with 43 | // Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer::transform() 44 | // The value returned is a string that concatenates the string representation of those objects 45 | 46 | /* @var Tag[] $tags */ 47 | return implode(',', $tags); 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function reverseTransform($string): array 54 | { 55 | if (null === $string || u($string)->isEmpty()) { 56 | return []; 57 | } 58 | 59 | $names = array_filter(array_unique(array_map('trim', u($string)->split(',')))); 60 | 61 | // Get the current tags and find the new ones that should be created. 62 | $tags = $this->tags->findBy([ 63 | 'name' => $names, 64 | ]); 65 | $newNames = array_diff($names, $tags); 66 | foreach ($newNames as $name) { 67 | $tag = new Tag(); 68 | $tag->setName($name); 69 | $tags[] = $tag; 70 | 71 | // There's no need to persist these new tags because Doctrine does that automatically 72 | // thanks to the cascade={"persist"} option in the App\Entity\Post::$tags property. 73 | } 74 | 75 | // Return an array of tags to transform them back into a Doctrine Collection. 76 | // See Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer::reverseTransform() 77 | return $tags; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Form/Type/ChangePasswordType.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Form\Type; 13 | 14 | use Symfony\Component\Form\AbstractType; 15 | use Symfony\Component\Form\Extension\Core\Type\PasswordType; 16 | use Symfony\Component\Form\Extension\Core\Type\RepeatedType; 17 | use Symfony\Component\Form\FormBuilderInterface; 18 | use Symfony\Component\Security\Core\Validator\Constraints\UserPassword; 19 | use Symfony\Component\Validator\Constraints\Length; 20 | use Symfony\Component\Validator\Constraints\NotBlank; 21 | 22 | /** 23 | * Defines the custom form field type used to change user's password. 24 | * 25 | * @author Romain Monteil 26 | */ 27 | class ChangePasswordType extends AbstractType 28 | { 29 | /** 30 | * {@inheritdoc} 31 | */ 32 | public function buildForm(FormBuilderInterface $builder, array $options): void 33 | { 34 | $builder 35 | ->add('currentPassword', PasswordType::class, [ 36 | 'constraints' => [ 37 | new UserPassword(), 38 | ], 39 | 'label' => 'label.current_password', 40 | 'attr' => [ 41 | 'autocomplete' => 'off', 42 | ], 43 | ]) 44 | ->add('newPassword', RepeatedType::class, [ 45 | 'type' => PasswordType::class, 46 | 'constraints' => [ 47 | new NotBlank(), 48 | new Length([ 49 | 'min' => 5, 50 | 'max' => 128, 51 | ]), 52 | ], 53 | 'first_options' => [ 54 | 'label' => 'label.new_password', 55 | ], 56 | 'second_options' => [ 57 | 'label' => 'label.new_password_confirm', 58 | ], 59 | ]) 60 | ; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Form/Type/DateTimePickerType.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Form\Type; 13 | 14 | use App\Utils\MomentFormatConverter; 15 | use Symfony\Component\Form\AbstractType; 16 | use Symfony\Component\Form\Extension\Core\Type\DateTimeType; 17 | use Symfony\Component\Form\FormInterface; 18 | use Symfony\Component\Form\FormView; 19 | use Symfony\Component\OptionsResolver\OptionsResolver; 20 | use function Symfony\Component\String\u; 21 | 22 | /** 23 | * Defines the custom form field type used to manipulate datetime values across 24 | * Bootstrap Date\Time Picker javascript plugin. 25 | * 26 | * See https://symfony.com/doc/current/form/create_custom_field_type.html 27 | * 28 | * @author Yonel Ceruto 29 | */ 30 | class DateTimePickerType extends AbstractType 31 | { 32 | private $formatConverter; 33 | 34 | public function __construct(MomentFormatConverter $converter) 35 | { 36 | $this->formatConverter = $converter; 37 | } 38 | 39 | /** 40 | * {@inheritdoc} 41 | */ 42 | public function buildView(FormView $view, FormInterface $form, array $options): void 43 | { 44 | $view->vars['attr']['data-date-format'] = $this->formatConverter->convert($options['format']); 45 | $view->vars['attr']['data-date-locale'] = u(\Locale::getDefault())->replace('_', '-')->lower(); 46 | } 47 | 48 | /** 49 | * {@inheritdoc} 50 | */ 51 | public function configureOptions(OptionsResolver $resolver): void 52 | { 53 | $resolver->setDefaults([ 54 | 'widget' => 'single_text', 55 | // if true, the browser will display the native date picker widget 56 | // however, this app uses a custom JavaScript widget, so it must be set to false 57 | 'html5' => false, 58 | ]); 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | public function getParent() 65 | { 66 | return DateTimeType::class; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/Form/Type/TagsInputType.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Form\Type; 13 | 14 | use App\Form\DataTransformer\TagArrayToStringTransformer; 15 | use App\Repository\TagRepository; 16 | use Symfony\Bridge\Doctrine\Form\DataTransformer\CollectionToArrayTransformer; 17 | use Symfony\Component\Form\AbstractType; 18 | use Symfony\Component\Form\Extension\Core\Type\TextType; 19 | use Symfony\Component\Form\FormBuilderInterface; 20 | use Symfony\Component\Form\FormInterface; 21 | use Symfony\Component\Form\FormView; 22 | 23 | /** 24 | * Defines the custom form field type used to manipulate tags values across 25 | * Bootstrap-tagsinput javascript plugin. 26 | * 27 | * See https://symfony.com/doc/current/form/create_custom_field_type.html 28 | * 29 | * @author Yonel Ceruto 30 | */ 31 | class TagsInputType extends AbstractType 32 | { 33 | private $tags; 34 | 35 | public function __construct(TagRepository $tags) 36 | { 37 | $this->tags = $tags; 38 | } 39 | 40 | /** 41 | * {@inheritdoc} 42 | */ 43 | public function buildForm(FormBuilderInterface $builder, array $options): void 44 | { 45 | $builder 46 | // The Tag collection must be transformed into a comma separated string. 47 | // We could create a custom transformer to do Collection <-> string in one step, 48 | // but here we're doing the transformation in two steps (Collection <-> array <-> string) 49 | // and reuse the existing CollectionToArrayTransformer. 50 | ->addModelTransformer(new CollectionToArrayTransformer(), true) 51 | ->addModelTransformer(new TagArrayToStringTransformer($this->tags), true) 52 | ; 53 | } 54 | 55 | /** 56 | * {@inheritdoc} 57 | */ 58 | public function buildView(FormView $view, FormInterface $form, array $options): void 59 | { 60 | $view->vars['tags'] = $this->tags->findAll(); 61 | } 62 | 63 | /** 64 | * {@inheritdoc} 65 | */ 66 | public function getParent() 67 | { 68 | return TextType::class; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Form/UserType.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Form; 13 | 14 | use App\Entity\User; 15 | use Symfony\Component\Form\AbstractType; 16 | use Symfony\Component\Form\Extension\Core\Type\EmailType; 17 | use Symfony\Component\Form\Extension\Core\Type\TextType; 18 | use Symfony\Component\Form\FormBuilderInterface; 19 | use Symfony\Component\OptionsResolver\OptionsResolver; 20 | 21 | /** 22 | * Defines the form used to edit an user. 23 | * 24 | * @author Romain Monteil 25 | */ 26 | class UserType extends AbstractType 27 | { 28 | /** 29 | * {@inheritdoc} 30 | */ 31 | public function buildForm(FormBuilderInterface $builder, array $options): void 32 | { 33 | // For the full reference of options defined by each form field type 34 | // see https://symfony.com/doc/current/reference/forms/types.html 35 | 36 | // By default, form fields include the 'required' attribute, which enables 37 | // the client-side form validation. This means that you can't test the 38 | // server-side validation errors from the browser. To temporarily disable 39 | // this validation, set the 'required' attribute to 'false': 40 | // $builder->add('title', null, ['required' => false, ...]); 41 | 42 | $builder 43 | ->add('username', TextType::class, [ 44 | 'label' => 'label.username', 45 | 'disabled' => true, 46 | ]) 47 | ->add('fullName', TextType::class, [ 48 | 'label' => 'label.fullname', 49 | ]) 50 | ->add('email', EmailType::class, [ 51 | 'label' => 'label.email', 52 | ]) 53 | ; 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | public function configureOptions(OptionsResolver $resolver): void 60 | { 61 | $resolver->setDefaults([ 62 | 'data_class' => User::class, 63 | ]); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/Kernel.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App; 13 | 14 | use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; 15 | use Symfony\Component\Config\Loader\LoaderInterface; 16 | use Symfony\Component\Config\Resource\FileResource; 17 | use Symfony\Component\DependencyInjection\ContainerBuilder; 18 | use Symfony\Component\HttpKernel\Kernel as BaseKernel; 19 | use Symfony\Component\Routing\RouteCollectionBuilder; 20 | 21 | class Kernel extends BaseKernel 22 | { 23 | use MicroKernelTrait; 24 | 25 | private const CONFIG_EXTS = '.{php,xml,yaml,yml}'; 26 | 27 | public function registerBundles(): iterable 28 | { 29 | $contents = require $this->getProjectDir().'/config/bundles.php'; 30 | foreach ($contents as $class => $envs) { 31 | if ($envs[$this->environment] ?? $envs['all'] ?? false) { 32 | yield new $class(); 33 | } 34 | } 35 | } 36 | 37 | public function getProjectDir(): string 38 | { 39 | return \dirname(__DIR__); 40 | } 41 | 42 | protected function configureContainer(ContainerBuilder $container, LoaderInterface $loader): void 43 | { 44 | $container->addResource(new FileResource($this->getProjectDir().'/config/bundles.php')); 45 | $container->setParameter('container.dumper.inline_class_loader', \PHP_VERSION_ID < 70400 || !ini_get('opcache.preload')); 46 | $container->setParameter('container.dumper.inline_factories', true); 47 | $confDir = $this->getProjectDir().'/config'; 48 | 49 | $loader->load($confDir.'/{packages}/*'.self::CONFIG_EXTS, 'glob'); 50 | $loader->load($confDir.'/{packages}/'.$this->environment.'/*'.self::CONFIG_EXTS, 'glob'); 51 | $loader->load($confDir.'/{services}'.self::CONFIG_EXTS, 'glob'); 52 | $loader->load($confDir.'/{services}_'.$this->environment.self::CONFIG_EXTS, 'glob'); 53 | } 54 | 55 | protected function configureRoutes(RouteCollectionBuilder $routes): void 56 | { 57 | $confDir = $this->getProjectDir().'/config'; 58 | 59 | $routes->import($confDir.'/{routes}/'.$this->environment.'/*'.self::CONFIG_EXTS, '/', 'glob'); 60 | $routes->import($confDir.'/{routes}/*'.self::CONFIG_EXTS, '/', 'glob'); 61 | $routes->import($confDir.'/{routes}'.self::CONFIG_EXTS, '/', 'glob'); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Migrations/.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/src/Migrations/.gitignore -------------------------------------------------------------------------------- /src/Repository/PostRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Repository; 13 | 14 | use App\Entity\Post; 15 | use App\Entity\Tag; 16 | use App\Pagination\Paginator; 17 | use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; 18 | use Doctrine\Persistence\ManagerRegistry; 19 | use function Symfony\Component\String\u; 20 | 21 | /** 22 | * This custom Doctrine repository contains some methods which are useful when 23 | * querying for blog post information. 24 | * 25 | * See https://symfony.com/doc/current/doctrine.html#querying-for-objects-the-repository 26 | * 27 | * @author Ryan Weaver 28 | * @author Javier Eguiluz 29 | * @author Yonel Ceruto 30 | */ 31 | class PostRepository extends ServiceEntityRepository 32 | { 33 | public function __construct(ManagerRegistry $registry) 34 | { 35 | parent::__construct($registry, Post::class); 36 | } 37 | 38 | public function findLatest(int $page = 1, Tag $tag = null): Paginator 39 | { 40 | $qb = $this->createQueryBuilder('p') 41 | ->addSelect('a', 't') 42 | ->innerJoin('p.author', 'a') 43 | ->leftJoin('p.tags', 't') 44 | ->where('p.publishedAt <= :now') 45 | ->orderBy('p.publishedAt', 'DESC') 46 | ->setParameter('now', new \DateTime()) 47 | ; 48 | 49 | if (null !== $tag) { 50 | $qb->andWhere(':tag MEMBER OF p.tags') 51 | ->setParameter('tag', $tag); 52 | } 53 | 54 | return (new Paginator($qb))->paginate($page); 55 | } 56 | 57 | /** 58 | * @return Post[] 59 | */ 60 | public function findBySearchQuery(string $query, int $limit = Post::NUM_ITEMS): array 61 | { 62 | $searchTerms = $this->extractSearchTerms($query); 63 | 64 | if (0 === \count($searchTerms)) { 65 | return []; 66 | } 67 | 68 | $queryBuilder = $this->createQueryBuilder('p'); 69 | 70 | foreach ($searchTerms as $key => $term) { 71 | $queryBuilder 72 | ->orWhere('p.title LIKE :t_'.$key) 73 | ->setParameter('t_'.$key, '%'.$term.'%') 74 | ; 75 | } 76 | 77 | return $queryBuilder 78 | ->orderBy('p.publishedAt', 'DESC') 79 | ->setMaxResults($limit) 80 | ->getQuery() 81 | ->getResult(); 82 | } 83 | 84 | /** 85 | * Transforms the search string into an array of search terms. 86 | */ 87 | private function extractSearchTerms(string $searchQuery): array 88 | { 89 | $searchQuery = u($searchQuery)->replaceMatches('/[[:space:]]+/', ' ')->trim(); 90 | $terms = array_unique(u($searchQuery)->split(' ')); 91 | 92 | // ignore the search terms that are too short 93 | return array_filter($terms, function ($term) { 94 | return 2 <= u($term)->length(); 95 | }); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Repository/TagRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Repository; 13 | 14 | use App\Entity\Tag; 15 | use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; 16 | use Doctrine\Persistence\ManagerRegistry; 17 | 18 | /** 19 | * This custom Doctrine repository is empty because so far we don't need any custom 20 | * method to query for application user information. But it's always a good practice 21 | * to define a custom repository that will be used when the application grows. 22 | * 23 | * See https://symfony.com/doc/current/doctrine.html#querying-for-objects-the-repository 24 | * 25 | * @author Yonel Ceruto 26 | */ 27 | class TagRepository extends ServiceEntityRepository 28 | { 29 | public function __construct(ManagerRegistry $registry) 30 | { 31 | parent::__construct($registry, Tag::class); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Repository/UserRepository.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Repository; 13 | 14 | use App\Entity\User; 15 | use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; 16 | use Doctrine\Persistence\ManagerRegistry; 17 | 18 | /** 19 | * This custom Doctrine repository is empty because so far we don't need any custom 20 | * method to query for application user information. But it's always a good practice 21 | * to define a custom repository that will be used when the application grows. 22 | * 23 | * See https://symfony.com/doc/current/doctrine.html#querying-for-objects-the-repository 24 | * 25 | * @author Ryan Weaver 26 | * @author Javier Eguiluz 27 | */ 28 | class UserRepository extends ServiceEntityRepository 29 | { 30 | public function __construct(ManagerRegistry $registry) 31 | { 32 | parent::__construct($registry, User::class); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/Security/PostVoter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Security; 13 | 14 | use App\Entity\Post; 15 | use App\Entity\User; 16 | use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; 17 | use Symfony\Component\Security\Core\Authorization\Voter\Voter; 18 | 19 | /** 20 | * It grants or denies permissions for actions related to blog posts (such as 21 | * showing, editing and deleting posts). 22 | * 23 | * See https://symfony.com/doc/current/security/voters.html 24 | * 25 | * @author Yonel Ceruto 26 | */ 27 | class PostVoter extends Voter 28 | { 29 | // Defining these constants is overkill for this simple application, but for real 30 | // applications, it's a recommended practice to avoid relying on "magic strings" 31 | public const DELETE = 'delete'; 32 | public const EDIT = 'edit'; 33 | public const SHOW = 'show'; 34 | 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | protected function supports($attribute, $subject): bool 39 | { 40 | // this voter is only executed for three specific permissions on Post objects 41 | return $subject instanceof Post && \in_array($attribute, [self::SHOW, self::EDIT, self::DELETE], true); 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | protected function voteOnAttribute($attribute, $post, TokenInterface $token): bool 48 | { 49 | $user = $token->getUser(); 50 | 51 | // the user must be logged in; if not, deny permission 52 | if (!$user instanceof User) { 53 | return false; 54 | } 55 | 56 | // the logic of this voter is pretty simple: if the logged user is the 57 | // author of the given blog post, grant permission; otherwise, deny it. 58 | // (the supports() method guarantees that $post is a Post object) 59 | return $user === $post->getAuthor(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/Twig/AppExtension.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Twig; 13 | 14 | use App\Utils\Markdown; 15 | use Symfony\Component\Intl\Locales; 16 | use Twig\Extension\AbstractExtension; 17 | use Twig\TwigFilter; 18 | use Twig\TwigFunction; 19 | 20 | /** 21 | * This Twig extension adds a new 'md2html' filter to easily transform Markdown 22 | * contents into HTML contents inside Twig templates. 23 | * 24 | * See https://symfony.com/doc/current/templating/twig_extension.html 25 | * 26 | * @author Ryan Weaver 27 | * @author Javier Eguiluz 28 | * @author Julien ITARD 29 | */ 30 | class AppExtension extends AbstractExtension 31 | { 32 | private $parser; 33 | private $localeCodes; 34 | private $locales; 35 | 36 | public function __construct(Markdown $parser, string $locales) 37 | { 38 | $this->parser = $parser; 39 | 40 | $localeCodes = explode('|', $locales); 41 | sort($localeCodes); 42 | $this->localeCodes = $localeCodes; 43 | } 44 | 45 | /** 46 | * {@inheritdoc} 47 | */ 48 | public function getFilters(): array 49 | { 50 | return [ 51 | new TwigFilter('md2html', [$this, 'markdownToHtml'], ['is_safe' => ['html']]), 52 | ]; 53 | } 54 | 55 | /** 56 | * {@inheritdoc} 57 | */ 58 | public function getFunctions(): array 59 | { 60 | return [ 61 | new TwigFunction('locales', [$this, 'getLocales']), 62 | ]; 63 | } 64 | 65 | /** 66 | * Transforms the given Markdown content into HTML content. 67 | */ 68 | public function markdownToHtml(string $content): string 69 | { 70 | return $this->parser->toHtml($content); 71 | } 72 | 73 | /** 74 | * Takes the list of codes of the locales (languages) enabled in the 75 | * application and returns an array with the name of each locale written 76 | * in its own language (e.g. English, Français, Español, etc.). 77 | */ 78 | public function getLocales(): array 79 | { 80 | if (null !== $this->locales) { 81 | return $this->locales; 82 | } 83 | 84 | $this->locales = []; 85 | foreach ($this->localeCodes as $localeCode) { 86 | $this->locales[] = ['code' => $localeCode, 'name' => Locales::getName($localeCode, $localeCode)]; 87 | } 88 | 89 | return $this->locales; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Utils/Markdown.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Utils; 13 | 14 | use HtmlSanitizer\SanitizerInterface; 15 | 16 | /** 17 | * This class is a light interface between an external Markdown parser library 18 | * and the application. It's generally recommended to create these light interfaces 19 | * to decouple your application from the implementation details of the third-party library. 20 | * 21 | * @author Ryan Weaver 22 | * @author Javier Eguiluz 23 | */ 24 | class Markdown 25 | { 26 | private $parser; 27 | private $sanitizer; 28 | 29 | public function __construct(SanitizerInterface $sanitizer) 30 | { 31 | $this->parser = new \Parsedown(); 32 | $this->sanitizer = $sanitizer; 33 | } 34 | 35 | public function toHtml(string $text): string 36 | { 37 | $html = $this->parser->text($text); 38 | $safeHtml = $this->sanitizer->sanitize($html); 39 | 40 | return $safeHtml; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Utils/MomentFormatConverter.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | namespace App\Utils; 13 | 14 | /** 15 | * This class is used to convert PHP date format to moment.js format. 16 | * 17 | * @author Yonel Ceruto 18 | */ 19 | class MomentFormatConverter 20 | { 21 | /** 22 | * This defines the mapping between PHP ICU date format (key) and moment.js date format (value) 23 | * For ICU formats see http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax 24 | * For Moment formats see https://momentjs.com/docs/#/displaying/format/. 25 | * 26 | * @var array 27 | */ 28 | private static $formatConvertRules = [ 29 | // year 30 | 'yyyy' => 'YYYY', 'yy' => 'YY', 'y' => 'YYYY', 31 | // day 32 | 'dd' => 'DD', 'd' => 'D', 33 | // day of week 34 | 'EE' => 'ddd', 'EEEEEE' => 'dd', 35 | // timezone 36 | 'ZZZZZ' => 'Z', 'ZZZ' => 'ZZ', 37 | // letter 'T' 38 | '\'T\'' => 'T', 39 | ]; 40 | 41 | /** 42 | * Returns associated moment.js format. 43 | */ 44 | public function convert(string $format): string 45 | { 46 | return strtr($format, self::$formatConvertRules); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /templates/admin/blog/_delete_form.html.twig: -------------------------------------------------------------------------------- 1 | {{ include('blog/_delete_post_confirmation.html.twig') }} 2 |
3 | 4 | 8 |
9 | -------------------------------------------------------------------------------- /templates/admin/blog/_form.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | By default, forms enable client-side validation. This means that you can't 3 | test the server-side validation errors from the browser. To temporarily 4 | disable this validation, add the 'novalidate' attribute: 5 | 6 | {{ form_start(form, {attr: {novalidate: 'novalidate'}}) }} 7 | #} 8 | 9 | {% if show_confirmation|default(false) %} 10 | {% set attr = {'data-confirmation': 'true'} %} 11 | {{ include('blog/_delete_post_confirmation.html.twig') }} 12 | {% endif %} 13 | 14 | {{ form_start(form, {attr: attr|default({})}) }} 15 | {{ form_widget(form) }} 16 | 17 | 20 | 21 | {% if include_back_to_home_link|default(false) %} 22 | 23 | {{ 'action.back_to_list'|trans }} 24 | 25 | {% endif %} 26 | {{ form_end(form) }} 27 | -------------------------------------------------------------------------------- /templates/admin/blog/edit.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/layout.html.twig' %} 2 | 3 | {% block body_id 'admin_post_edit' %} 4 | 5 | {% block main %} 6 |

{{ 'title.edit_post'|trans({'%id%': post.id}) }}

7 | 8 | {{ include('admin/blog/_form.html.twig', { 9 | form: form, 10 | button_label: 'action.save'|trans, 11 | include_back_to_home_link: true, 12 | }, with_context = false) }} 13 | {% endblock %} 14 | 15 | {% block sidebar %} 16 | 21 | 22 |
23 | {{ include('admin/blog/_delete_form.html.twig', {post: post}, with_context = false) }} 24 |
25 | 26 | {{ parent() }} 27 | 28 | {{ show_source_code(_self) }} 29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /templates/admin/blog/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/layout.html.twig' %} 2 | 3 | {% block body_id 'admin_post_index' %} 4 | 5 | {% block main %} 6 |

{{ 'title.post_list'|trans }}

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for post in posts %} 18 | 19 | 20 | {# it's not mandatory to set the timezone in localizeddate(). This is done to 21 | avoid errors when the 'intl' PHP extension is not available and the application 22 | is forced to use the limited "intl polyfill", which only supports UTC and GMT #} 23 | 24 | 35 | 36 | {% else %} 37 | 38 | 39 | 40 | {% endfor %} 41 | 42 |
{{ 'label.title'|trans }} {{ 'label.published_at'|trans }} {{ 'label.actions'|trans }}
{{ post.title }}{{ post.publishedAt|format_datetime('medium', 'short', '', 'UTC') }} 25 | 34 |
{{ 'post.no_posts_found'|trans }}
43 | {% endblock %} 44 | 45 | {% block sidebar %} 46 | 51 | 52 | {{ parent() }} 53 | 54 | {{ show_source_code(_self) }} 55 | {% endblock %} 56 | -------------------------------------------------------------------------------- /templates/admin/blog/new.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/layout.html.twig' %} 2 | 3 | {% block body_id 'admin_post_new' %} 4 | 5 | {% block main %} 6 |

{{ 'title.post_new'|trans }}

7 | 8 | {{ form_start(form) }} 9 | {{ form_row(form.title) }} 10 | {{ form_row(form.summary) }} 11 | {{ form_row(form.content) }} 12 | {{ form_row(form.publishedAt) }} 13 | {{ form_row(form.tags) }} 14 | 15 | 18 | {{ form_widget(form.saveAndCreateNew, {label: 'label.save_and_create_new', attr: {class: 'btn btn-primary'}}) }} 19 | 20 | {{ 'action.back_to_list'|trans }} 21 | 22 | {{ form_end(form) }} 23 | {% endblock %} 24 | 25 | {% block sidebar %} 26 | {{ parent() }} 27 | 28 | {{ show_source_code(_self) }} 29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /templates/admin/blog/show.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'admin/layout.html.twig' %} 2 | 3 | {% block body_id 'admin_post_show' %} 4 | 5 | {% block main %} 6 |

{{ post.title }}

7 | 8 | 12 | 13 |
14 |

{{ 'label.summary'|trans }}: {{ post.summary }}

15 |
16 | 17 | {{ post.content|md2html }} 18 | 19 | {{ include('blog/_post_tags.html.twig') }} 20 | {% endblock %} 21 | 22 | {% block sidebar %} 23 | 28 | 29 |
30 | {{ include('admin/blog/_delete_form.html.twig', {post: post}, with_context = false) }} 31 |
32 | 33 | {{ parent() }} 34 | 35 | {{ show_source_code(_self) }} 36 | {% endblock %} 37 | -------------------------------------------------------------------------------- /templates/admin/layout.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | This is the base template of the all backend pages. Since this layout is similar 3 | to the global layout, we inherit from it to just change the contents of some 4 | blocks. In practice, backend templates are using a three-level inheritance, 5 | showing how powerful, yet easy to use, is Twig's inheritance mechanism. 6 | See https://symfony.com/doc/current/templates.html#template-inheritance-and-layouts 7 | #} 8 | {% extends 'base.html.twig' %} 9 | 10 | {% block stylesheets %} 11 | {{ parent() }} 12 | {{ encore_entry_link_tags('admin') }} 13 | {% endblock %} 14 | 15 | {% block javascripts %} 16 | {{ parent() }} 17 | {{ encore_entry_script_tags('admin') }} 18 | {% endblock %} 19 | 20 | {% block header_navigation_links %} 21 |
  • 22 | 23 | {{ 'menu.post_list'|trans }} 24 | 25 |
  • 26 |
  • 27 | 28 | {{ 'menu.back_to_blog'|trans }} 29 | 30 |
  • 31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /templates/blog/_comment_form.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | By default, forms enable client-side validation. This means that you can't 3 | test the server-side validation errors from the browser. To temporarily 4 | disable this validation, add the 'novalidate' attribute: 5 | 6 | {{ form_start(form, {method: ..., action: ..., attr: {novalidate: 'novalidate'}}) }} 7 | #} 8 | 9 | {{ form_start(form, {method: 'POST', action: path('comment_new', {'postSlug': post.slug})}) }} 10 | {# instead of displaying form fields one by one, you can also display them 11 | all with their default options and styles just by calling to this function: 12 | 13 | {{ form_widget(form) }} 14 | #} 15 | 16 |
    17 | 18 | {{ 'title.add_comment'|trans }} 19 | 20 | 21 | {# Render any global form error (e.g. when a constraint on a public getter method failed) #} 22 | {{ form_errors(form) }} 23 | 24 |
    25 | {{ form_label(form.content, 'label.content', {label_attr: {class: 'hidden'}}) }} 26 | 27 | {# Render any errors for the "content" field (e.g. when a class property constraint failed) #} 28 | {{ form_errors(form.content) }} 29 | 30 | {{ form_widget(form.content, {attr: {rows: 10}}) }} 31 | {{ form_help(form.content) }} 32 |
    33 | 34 |
    35 | 38 |
    39 |
    40 | {{ form_end(form) }} 41 | -------------------------------------------------------------------------------- /templates/blog/_delete_post_confirmation.html.twig: -------------------------------------------------------------------------------- 1 | {# Bootstrap modal, see https://getbootstrap.com/docs/3.4/javascript/#modals #} 2 | 20 | -------------------------------------------------------------------------------- /templates/blog/_post_tags.html.twig: -------------------------------------------------------------------------------- 1 | {% if not post.tags.empty %} 2 | 11 | {% endif %} 12 | 13 | -------------------------------------------------------------------------------- /templates/blog/_rss.html.twig: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /templates/blog/about.html.twig: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    4 | {{ 'help.app_description'|trans|raw }} 5 |

    6 |

    7 | {{ 'help.more_information'|trans|raw }} 8 |

    9 |
    10 |
    11 | 12 | {# it's not mandatory to set the timezone in localizeddate(). This is done to 13 | avoid errors when the 'intl' PHP extension is not available and the application 14 | is forced to use the limited "intl polyfill", which only supports UTC and GMT #} 15 | 16 | -------------------------------------------------------------------------------- /templates/blog/comment_form_error.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% block body_id 'comment_form_error' %} 4 | 5 | {% block main %} 6 |

    {{ 'title.comment_error'|trans }}

    7 | 8 |
    9 | {{ include('blog/_comment_form.html.twig') }} 10 |
    11 | {% endblock %} 12 | -------------------------------------------------------------------------------- /templates/blog/index.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% block body_id 'blog_index' %} 4 | 5 | {% block main %} 6 | {% for post in paginator.results %} 7 |
    8 |

    9 | 10 | {{ post.title }} 11 | 12 |

    13 | 14 | 18 | 19 |

    {{ post.summary }}

    20 | 21 | {{ include('blog/_post_tags.html.twig') }} 22 |
    23 | {% else %} 24 |
    {{ 'post.no_posts_found'|trans }}
    25 | {% endfor %} 26 | 27 | {% if paginator.hasToPaginate %} 28 | 51 | {% endif %} 52 | {% endblock %} 53 | 54 | {% block sidebar %} 55 | {{ parent() }} 56 | 57 | {{ show_source_code(_self) }} 58 | {{ include('blog/_rss.html.twig') }} 59 | {% endblock %} 60 | -------------------------------------------------------------------------------- /templates/blog/index.xml.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ 'rss.title'|trans }} 5 | {{ 'rss.description'|trans }} 6 | {{ 'now'|date('r', timezone='GMT') }} 7 | {{ (paginator.results|last).publishedAt|default('now')|date('r', timezone='GMT') }} 8 | {{ url('blog_index') }} 9 | {{ app.request.locale }} 10 | 11 | {% for post in paginator.results %} 12 | 13 | {{ post.title }} 14 | {{ post.summary }} 15 | {{ url('blog_post', {'slug': post.slug}) }} 16 | {{ url('blog_post', {'slug': post.slug}) }} 17 | {{ post.publishedAt|date(format='r', timezone='GMT') }} 18 | {{ post.author.email }} 19 | {% for tag in post.tags %} 20 | {{ tag.name }} 21 | {% endfor %} 22 | 23 | {% endfor %} 24 | 25 | 26 | -------------------------------------------------------------------------------- /templates/blog/search.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% block javascripts %} 4 | {{ parent() }} 5 | {{ encore_entry_script_tags('search') }} 6 | {% endblock %} 7 | 8 | {% block body_id 'blog_search' %} 9 | 10 | {% block main %} 11 |
    12 |
    13 | 20 |
    21 |
    22 | 23 |
    24 |
    25 | {% endblock %} 26 | 27 | {% block sidebar %} 28 | {{ parent() }} 29 | 30 | {{ show_source_code(_self) }} 31 | {% endblock %} 32 | -------------------------------------------------------------------------------- /templates/bundles/TwigBundle/Exception/error.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | This template is used to render any error different from 403, 404 and 500. 3 | 4 | This is the simplest way to customize error pages in Symfony applications. 5 | In case you need it, you can also hook into the internal exception handling 6 | made by Symfony. This allows you to perform advanced tasks and even recover 7 | your application from some errors. 8 | See https://symfony.com/doc/current/controller/error_pages.html 9 | #} 10 | 11 | {% extends 'base.html.twig' %} 12 | 13 | {% block body_id 'error' %} 14 | 15 | {% block main %} 16 |

    {{ 'http_error.name'|trans({ '%status_code%': status_code }) }}

    17 | 18 |

    19 | {{ 'http_error.description'|trans({ '%status_code%': status_code }) }} 20 |

    21 |

    22 | {{ 'http_error.suggestion'|trans({ '%url%': path('blog_index') })|raw }} 23 |

    24 | {% endblock %} 25 | 26 | {% block sidebar %} 27 | {{ parent() }} 28 | 29 | {{ show_source_code(_self) }} 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /templates/bundles/TwigBundle/Exception/error403.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | This template is used to render errors of type HTTP 403 (Forbidden) 3 | 4 | This is the simplest way to customize error pages in Symfony applications. 5 | In case you need it, you can also hook into the internal exception handling 6 | made by Symfony. This allows you to perform advanced tasks and even recover 7 | your application from some errors. 8 | See https://symfony.com/doc/current/controller/error_pages.html 9 | #} 10 | 11 | {% extends 'base.html.twig' %} 12 | 13 | {% block body_id 'error' %} 14 | 15 | {% block main %} 16 |

    {{ 'http_error.name'|trans({ '%status_code%': 403 }) }}

    17 | 18 |

    19 | {{ 'http_error_403.description'|trans }} 20 |

    21 |

    22 | {{ 'http_error_403.suggestion'|trans }} 23 |

    24 | {% endblock %} 25 | 26 | {% block sidebar %} 27 | {{ parent() }} 28 | 29 | {{ show_source_code(_self) }} 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /templates/bundles/TwigBundle/Exception/error404.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | This template is used to render errors of type HTTP 404 (Not Found) 3 | 4 | This is the simplest way to customize error pages in Symfony applications. 5 | In case you need it, you can also hook into the internal exception handling 6 | made by Symfony. This allows you to perform advanced tasks and even recover 7 | your application from some errors. 8 | See https://symfony.com/doc/current/controller/error_pages.html 9 | #} 10 | 11 | {% extends 'base.html.twig' %} 12 | 13 | {% block body_id 'error' %} 14 | 15 | {% block main %} 16 |

    {{ 'http_error.name'|trans({ '%status_code%': 404 }) }}

    17 | 18 |

    19 | {{ 'http_error_404.description'|trans }} 20 |

    21 |

    22 | {{ 'http_error_404.suggestion'|trans({ '%url%': path('blog_index') })|raw }} 23 |

    24 | {% endblock %} 25 | 26 | {% block sidebar %} 27 | {{ parent() }} 28 | 29 | {{ show_source_code(_self) }} 30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /templates/bundles/TwigBundle/Exception/error500.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | This template is used to render errors of type HTTP 500 (Internal Server Error) 3 | 4 | This is the simplest way to customize error pages in Symfony applications. 5 | In case you need it, you can also hook into the internal exception handling 6 | made by Symfony. This allows you to perform advanced tasks and even recover 7 | your application from some errors. 8 | See https://symfony.com/doc/current/controller/error_pages.html 9 | #} 10 | 11 | {% extends 'base.html.twig' %} 12 | 13 | {% block stylesheets %} 14 | {{ parent() }} 15 | 16 | {% endblock %} 17 | 18 | {% block body_id 'error' %} 19 | 20 | {% block main %} 21 |

    {{ 'http_error.name'|trans({ '%status_code%': 500 }) }}

    22 | 23 |

    24 | {{ 'http_error_500.description'|trans }} 25 |

    26 |

    27 | {{ 'http_error_500.suggestion'|trans({ '%url%': path('blog_index') })|raw }} 28 |

    29 | {% endblock %} 30 | 31 | {% block sidebar %} 32 | {{ parent() }} 33 | 34 | {{ show_source_code(_self) }} 35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /templates/debug/source_code.html.twig: -------------------------------------------------------------------------------- 1 |
    2 |

    3 | {{ 'help.show_code'|trans|raw }} 4 |

    5 | 6 | 9 | 10 | 35 |
    36 | -------------------------------------------------------------------------------- /templates/default/_flash_messages.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | This is a template fragment designed to be included in other templates 3 | See https://symfony.com/doc/current/templates.html#including-templates 4 | 5 | A common practice to better distinguish between templates and fragments is to 6 | prefix fragments with an underscore. That's why this template is called 7 | '_flash_messages.html.twig' instead of 'flash_messages.html.twig' 8 | #} 9 | 10 | {# 11 | The check is needed to prevent starting the session when looking for "flash messages": 12 | https://symfony.com/doc/current/session.html#avoid-starting-sessions-for-anonymous-users 13 | 14 | TIP: With FOSHttpCache you can also adapt this to make it cache safe: 15 | https://foshttpcachebundle.readthedocs.io/en/latest/features/helpers/flash-message.html 16 | #} 17 | {% if app.request.hasPreviousSession %} 18 |
    19 | {% for type, messages in app.flashes %} 20 | {% for message in messages %} 21 | {# Bootstrap alert, see https://getbootstrap.com/docs/3.4/components/#alerts #} 22 | 29 | {% endfor %} 30 | {% endfor %} 31 |
    32 | {% endif %} 33 | -------------------------------------------------------------------------------- /templates/default/homepage.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% block body_id 'homepage' %} 4 | 5 | {# 6 | the homepage is a special page which displays neither a header nor a footer. 7 | this is done with the 'trick' of defining empty Twig blocks without any content 8 | #} 9 | {% block header %}{% endblock %} 10 | {% block footer %}{% endblock %} 11 | 12 | {% block body %} 13 | 16 | 17 |
    18 |
    19 |
    20 |

    21 | {{ 'help.browse_app'|trans|raw }} 22 |

    23 |

    24 | 25 | {{ 'action.browse_app'|trans }} 26 | 27 |

    28 |
    29 |
    30 | 31 |
    32 |
    33 |

    34 | {{ 'help.browse_admin'|trans|raw }} 35 |

    36 |

    37 | 38 | {{ 'action.browse_admin'|trans }} 39 | 40 |

    41 |
    42 |
    43 |
    44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /templates/form/fields.html.twig: -------------------------------------------------------------------------------- 1 | {# 2 | Each field type is rendered by a template fragment, which is determined 3 | by the name of your form type class (DateTimePickerType -> date_time_picker) 4 | and the suffix "_widget". This can be controlled by overriding getBlockPrefix() 5 | in DateTimePickerType. 6 | 7 | See https://symfony.com/doc/current/form/create_custom_field_type.html#creating-the-form-type-template 8 | #} 9 | 10 | {% block date_time_picker_widget %} 11 |
    12 | {{ block('datetime_widget') }} 13 | 14 | 15 | 16 |
    17 | {% endblock %} 18 | 19 | {% block tags_input_widget %} 20 |
    21 | {{ form_widget(form, {'attr': {'data-toggle': 'tagsinput', 'data-tags': tags|json_encode}}) }} 22 | 23 | 24 | 25 |
    26 | {% endblock %} 27 | -------------------------------------------------------------------------------- /templates/form/layout.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'bootstrap_3_layout.html.twig' %} 2 | 3 | {# Errors #} 4 | 5 | {% block form_errors -%} 6 | {% if errors|length > 0 -%} 7 | {% if form is not rootform %}{% else %}
    {% endif %} 8 |
      9 | {%- for error in errors -%} 10 | {# use font-awesome icon library #} 11 |
    • {{ error.message }}
    • 12 | {%- endfor -%} 13 |
    14 | {% if form is not rootform %}{% else %}
    {% endif %} 15 | {%- endif %} 16 | {%- endblock form_errors %} 17 | -------------------------------------------------------------------------------- /templates/user/change_password.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% block body_id 'user_password' %} 4 | 5 | {% block main %} 6 |

    {{ 'title.change_password'|trans }}

    7 | 8 | 9 | 10 | {{ form_start(form) }} 11 | {{ form_widget(form) }} 12 | 13 | 16 | {{ form_end(form) }} 17 | {% endblock %} 18 | 19 | {% block sidebar %} 20 | 25 | 26 | {{ parent() }} 27 | 28 | {{ show_source_code(_self) }} 29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /templates/user/edit.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'base.html.twig' %} 2 | 3 | {% block body_id 'user_edit' %} 4 | 5 | {% block main %} 6 |

    {{ 'title.edit_user'|trans }}

    7 | 8 | {{ form_start(form) }} 9 | {{ form_widget(form) }} 10 | 11 | 14 | {{ form_end(form) }} 15 | {% endblock %} 16 | 17 | {% block sidebar %} 18 | 23 | 24 | {{ parent() }} 25 | 26 | {{ show_source_code(_self) }} 27 | {% endblock %} 28 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.bg.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Напишете обобщение на публикацията си! 8 | 9 | 10 | post.blank_content 11 | Публикацията трябва да има съдържание! 12 | 13 | 14 | post.too_short_content 15 | Съдержанието на публикацията е прекалено малко ({ limit } минимум символа) 16 | 17 | 18 | post.too_many_tags 19 | Прекалено много тагове (добави { limit } тага или по-малко) 20 | 21 | 22 | comment.blank 23 | Моля не оставяйте коментара празен! 24 | 25 | 26 | comment.too_short 27 | Коментара е пркалено кратък ({ limit } симвала минимум) 28 | 29 | 30 | comment.too_long 31 | Коментара е прекалено дълъг ({ limit } симвала максимум) 32 | 33 | 34 | comment.is_spam 35 | Съдържанието на коментара се разглежда като спам. 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.ca.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | No és possible deixar buit el resum de l'article. 8 | 9 | 10 | post.blank_content 11 | No és possible deixar buit el contingut de l'article. 12 | 13 | 14 | post.too_short_content 15 | El contingut de l'article és massa curt ({ limit } caràcters com a mínim) 16 | 17 | 18 | comment.blank 19 | No és possible deixar buit el contingut del comentari. 20 | 21 | 22 | comment.too_short 23 | El comentari és massa curt ({ limit } caràcters com a mínim) 24 | 25 | 26 | comment.too_long 27 | El comentari és massa llarg ({ limit } caràcters com a màxim) 28 | 29 | 30 | comment.is_spam 31 | El contingut del comentari es considera spam. 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.cs.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Napište shrnutí příspěvku! 8 | 9 | 10 | post.too_short_content 11 | Příspěvek je příliš krátký (musí mít minimálně { limit } znak)|Příspěvek je příliš krátký (musí mít minimálně { limit } znaky)|Příspěvek je příliš krátký (musí mít minimálně { limit } znaků) 12 | 13 | 14 | comment.blank 15 | Prosím, napište text komentáře! 16 | 17 | 18 | comment.too_short 19 | Komentář je příliš krátký (musí mít minimálně { limit } znak)|Komentář je příliš krátký (musí mít minimálně { limit } znaky)|Komentář je příliš krátký (musí mít minimálně { limit } znaků) 20 | 21 | 22 | comment.too_long 23 | Komentář je příliš dlouhý (musí mít maximálně { limit } znak)|Komentář je příliš dlouhý (musí mít maximálně { limit } znaky)|Komentář je příliš dlouhý (musí mít maximálně { limit } znaků) 24 | 25 | 26 | comment.is_spam 27 | Obsah tohoto komentáře je považován za spam. 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.de.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Gib deinem Beitrag eine Zusammenfassung! 8 | 9 | 10 | post.blank_content 11 | Dein Beitrag sollte einen Inhalt haben! 12 | 13 | 14 | post.too_short_content 15 | Der Beitragsinhalt ist zu kurz (mindestens { limit } Zeichen) 16 | 17 | 18 | comment.blank 19 | Bitte gib einen Kommentar ein! 20 | 21 | 22 | comment.too_short 23 | Der Kommentar ist zu kurz (mindestens { limit } Zeichen) 24 | 25 | 26 | comment.too_long 27 | Der Kommentar ist zu lang (maximal { limit } Zeichen) 28 | 29 | 30 | comment.is_spam 31 | Der Inhalt des Kommentars wird als Spam eingestuft. 32 | 33 | 34 | post.too_many_tags 35 | Zu viele Tags (höchstens { limit } Tags sind erlaubt) 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.en.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.slug_unique 7 | This title was already used in another blog post, but they must be unique. 8 | 9 | 10 | post.blank_summary 11 | Give your post a summary! 12 | 13 | 14 | post.blank_content 15 | Your post should have some content! 16 | 17 | 18 | post.too_short_content 19 | Post content is too short ({ limit } characters minimum) 20 | 21 | 22 | post.too_many_tags 23 | Too many tags (add { limit } tags or less) 24 | 25 | 26 | comment.blank 27 | Please don't leave your comment blank! 28 | 29 | 30 | comment.too_short 31 | Comment is too short ({ limit } characters minimum) 32 | 33 | 34 | comment.too_long 35 | Comment is too long ({ limit } characters maximum) 36 | 37 | 38 | comment.is_spam 39 | The content of this comment is considered spam. 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.es.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | No es posible dejar el resumen del artículo vacío. 8 | 9 | 10 | post.blank_content 11 | No es posible dejar el contenido del artículo vacío. 12 | 13 | 14 | post.too_short_content 15 | El contenido del artículo es demasiado corto ({ limit } caracteres como mínimo) 16 | 17 | 18 | post.too_many_tags 19 | Demasiadas etiquetas (añade { limit } como máximo) 20 | 21 | 22 | comment.blank 23 | No es posible dejar el contenido del comentario vacío. 24 | 25 | 26 | comment.too_short 27 | El comentario es demasiado corto ({ limit } caracteres como mínimo) 28 | 29 | 30 | comment.too_long 31 | El comentario es demasiado largo ({ limit } caracteres como máximo) 32 | 33 | 34 | comment.is_spam 35 | El contenido del comentario se considera spam. 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.fr.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Veuillez donner un résumé à votre post. 8 | 9 | 10 | post.blank_content 11 | Veuillez donner un contenu à votre post. 12 | 13 | 14 | post.too_short_content 15 | Le contenu de votre post est trop court ({ limit } caractères minimum) 16 | 17 | 18 | comment.blank 19 | Veuillez ne pas laisser votre commentaire vide. 20 | 21 | 22 | comment.too_short 23 | Votre commentaire est trop court ({ limit } caractères minimum) 24 | 25 | 26 | comment.too_long 27 | Votre commentaire est trop long ({ limit } caractères maximum) 28 | 29 | 30 | comment.is_spam 31 | Le contenu de votre commentaire est considéré comme du spam. 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.hr.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Dodajte sažetak svojem članku! 8 | 9 | 10 | post.blank_content 11 | Vaš članak treba imati sadržaj! 12 | 13 | 14 | post.too_short_content 15 | Sadržaj članka je prekratak (koristiti minimalno { limit } slova ili simbola) 16 | 17 | 18 | post.too_many_tags 19 | Previše oznaka (dodaj najviše { limit } oznaka ili manje) 20 | 21 | 22 | comment.blank 23 | Molim ne ostavljajte svoj komentar praznim! 24 | 25 | 26 | comment.too_short 27 | Komentar je prekratak (potrebno je minimalno { limit } slova ili simbola) 28 | 29 | 30 | comment.too_long 31 | Komentar je predugačak (koristiti maksimalno { limit } slova ili simbola) 32 | 33 | 34 | comment.is_spam 35 | Sadržaj ovog komentara smatra se spam sadržajem. 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.id.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Beri posting anda ringkasan! 8 | 9 | 10 | post.blank_content 11 | Posting anda harus mempunyai konten! 12 | 13 | 14 | post.too_short_content 15 | Konten terlalu singkat (Minimal { limit } karakter) 16 | 17 | 18 | comment.blank 19 | Mohon jangan tinggalkan komentar kosong! 20 | 21 | 22 | comment.too_short 23 | Komentar terlalu singkat (Minimal { limit } karakter) 24 | 25 | 26 | comment.too_long 27 | Komentar terlalu panjang (Maksimal { limit } karakter) 28 | 29 | 30 | comment.is_spam 31 | Konten komentar ini dianggap sebagai spam. 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.it.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Da' una descrizione al tuo post! 8 | 9 | 10 | post.blank_content 11 | Da' un contenuto al tuo post! 12 | 13 | 14 | post.too_short_content 15 | Il contenuto del post è troppo breve (minimo { limit } caratteri) 16 | 17 | 18 | comment.blank 19 | Per favore non lasciare in bianco il tuo commento! 20 | 21 | 22 | comment.too_short 23 | Il commento è troppo breve (minimo { limit } caratteri) 24 | 25 | 26 | comment.too_long 27 | Il commento è troppo lungo (massimo { limit } caratteri) 28 | 29 | 30 | comment.is_spam 31 | Il contenuto di questo commento è considerato come spam. 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.ja.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | 要約を入力してください。 8 | 9 | 10 | post.blank_content 11 | 本文を入力してください。 12 | 13 | 14 | post.too_short_content 15 | 本文が短すぎます ({ limit } 文字以上必要です) 16 | 17 | 18 | comment.blank 19 | コメントを入力してください。 20 | 21 | 22 | comment.too_short 23 | コメントが短すぎます ({ limit } 文字以上必要です) 24 | 25 | 26 | comment.too_long 27 | コメントが長すぎます ({ limit } 文字以下にしてください) 28 | 29 | 30 | comment.is_spam 31 | コメントの内容がスパムと判定されました。 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.lt.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Įrašo santrauka negali būti tuščia 8 | 9 | 10 | post.blank_content 11 | Įrašo turinys negali būti tuščias 12 | 13 | 14 | post.too_short_content 15 | Per trumpas įrašo turinys (nesiekia { limit } simbolių) 16 | 17 | 18 | post.too_many_tags 19 | Per daug žymų (viršyja { limit }) 20 | 21 | 22 | comment.blank 23 | Komentaras negali būti tuščias 24 | 25 | 26 | comment.too_short 27 | Per trumpas komentaras (nesiekia { limit } simbolių) 28 | 29 | 30 | comment.too_long 31 | Per ilgas komentaras (viršyja { limit } simbolių) 32 | 33 | 34 | comment.is_spam 35 | Komentaras traktuojamas kaip brukalas. 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.nl.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Geef uw bericht een samenvatting. 8 | 9 | 10 | post.blank_content 11 | Uw bericht heeft nog geen inhoud. 12 | 13 | 14 | post.too_short_content 15 | Bericht inhoud is te kort (minimaal { limit } karakters) 16 | 17 | 18 | comment.blank 19 | Vul alstublieft een reactie in. 20 | 21 | 22 | comment.too_short 23 | Reactie is te kort (minimaal { limit } karakters) 24 | 25 | 26 | comment.too_long 27 | Reactie is te lang (maximaal { limit } karakters) 28 | 29 | 30 | comment.is_spam 31 | De inhoud van deze reactie wordt als spam gemarkeerd. 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.pl.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Dodaj podsumowanie Twojego artykułu! 8 | 9 | 10 | post.blank_content 11 | Treść artykułu nie może być pusta! 12 | 13 | 14 | post.too_short_content 15 | Treść artykułu jest za krótka (minimum: { limit } znak)|Treść artykułu jest za krótka (minimum: { limit } znaki)|Treść artykułu jest za krótka (minimum: { limit } znaków) 16 | 17 | 18 | comment.blank 19 | Pole komentarza nie może być puste! 20 | 21 | 22 | comment.too_short 23 | Twój komentarz jest za krótki (minimum: { limit } znak)|Twój komentarz jest za krótki (minimum: { limit } znaki)|Twój komentarz jest za krótki (minimum: { limit } znaków) 24 | 25 | 26 | comment.too_long 27 | Twój komentarz jest za długi (maksimum: { limit } znak)|Twój komentarz jest za długi (maksimum: { limit } znaki)|Twój komentarz jest za długi (maksimum: { limit } znaków) 28 | 29 | 30 | comment.is_spam 31 | Twój komentarz został uznany za spam. 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.pt_BR.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Informe um sumário para o seu post! 8 | 9 | 10 | post.blank_content 11 | Informe um conteúdo para o seu post! 12 | 13 | 14 | post.too_short_content 15 | O conteúdo do post está muito curto (mínimo de { limit } caracteres) 16 | 17 | 18 | post.too_many_tags 19 | Tags demais (adicione { limit } tags ou menos) 20 | 21 | 22 | comment.blank 23 | Por favor, não deixe seu comentário vazio! 24 | 25 | 26 | comment.too_short 27 | O comentário está muito curto (mínimo de { limit } caracteres) 28 | 29 | 30 | comment.too_long 31 | O comentário está muito grande (máximo de { limit } caracteres) 32 | 33 | 34 | comment.is_spam 35 | O conteúdo desse comentário é considerado spam. 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.ro.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Dă articolului tău un rezumat! 8 | 9 | 10 | post.blank_content 11 | Articolul ar trebui să aibe conținut! 12 | 13 | 14 | post.too_short_content 15 | Conţinutul articolului este prea scurt (minimum { limit } caractere) 16 | 17 | 18 | comment.blank 19 | Te rugăm nu lăsa comentariul tău necompletat! 20 | 21 | 22 | comment.too_short 23 | Comentariul este prea scurt (minimum { limit } caractere) 24 | 25 | 26 | comment.too_long 27 | Comentariul este prea lung (maximum { limit } caractere) 28 | 29 | 30 | comment.is_spam 31 | Conţinutul acestui comentariu este considerat spam. 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.ru.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.slug_unique 7 | Такой заголовок уже используется в другой записи в блоге. Пожалуйста, используйте уникальный заголовок. 8 | 9 | 10 | post.blank_summary 11 | Введите краткое содержание вашей записи! 12 | 13 | 14 | post.blank_content 15 | Ваша запись должна содержать хоть какое-то содержание! 16 | 17 | 18 | post.too_short_content 19 | Содержание записи слишком короткое (минимум { limit } символов). 20 | 21 | 22 | post.too_many_tags 23 | Слишком много тегов (добавьте { limit } тегов или меньше) 24 | 25 | 26 | comment.blank 27 | Пожалуйста, не оставляйте текст комментария пустым! 28 | 29 | 30 | comment.too_short 31 | Комментарий слишком короткий, (минимум { limit } символов). 32 | 33 | 34 | comment.too_long 35 | Комментарий слишком длинный, (максимум { limit } символов). 36 | 37 | 38 | comment.is_spam 39 | Содержание этого комментария было расценено как спам. 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.sl.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Dodajte vaši objavi povzetek! 8 | 9 | 10 | post.blank_content 11 | Vaša objava mora imeti nekaj vsebine! 12 | 13 | 14 | post.too_short_content 15 | Vsebina objave je prekratka (vsaj { limit } znakov) 16 | 17 | 18 | post.too_many_tags 19 | Preveč značk (dodajte { limit } ali manj značk) 20 | 21 | 22 | comment.blank 23 | Ne pustite vašega komentarja praznega! 24 | 25 | 26 | comment.too_short 27 | Komentar je prekratek (vsaj { limit } znakov) 28 | 29 | 30 | comment.too_long 31 | Komentar je predolg (največ { limit } znakov) 32 | 33 | 34 | comment.is_spam 35 | Vsebina tega komentarja se smatra za spam. 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.tr.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | Gönderiniz için bir özet giriniz! 8 | 9 | 10 | post.blank_content 11 | Gönderiniz bir içeriğe sahip olmalı! 12 | 13 | 14 | post.too_short_content 15 | Yayın içeriği çok kısa ({ limit } minimum karakter) 16 | 17 | 18 | post.too_many_tags 19 | Çok fazla etiket var ({ limit } etiketini veya daha azını ekleyin) 20 | 21 | 22 | comment.blank 23 | Lütfen yorumunuzu boş bırakmayın! 24 | 25 | 26 | comment.too_short 27 | Yorum çok kısa ({ limit } minimum karakter) 28 | 29 | 30 | comment.too_long 31 | Yorum çok uzun ({ limit } maksimum karakter) 32 | 33 | 34 | comment.is_spam 35 | Bu yorumun içeriği spam olarak kabul edilir. 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.uk.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.slug_unique 7 | Цей заголовок вже використовується в іншому записі, але повинен бути унікальним. 8 | 9 | 10 | post.blank_summary 11 | Введіть короткий зміст вашого запису! 12 | 13 | 14 | post.blank_content 15 | Ваш запис повинен містити хоч якийсь зміст! 16 | 17 | 18 | post.too_short_content 19 | Зміст запису занадто короткий (мінімум { limit } символів). 20 | 21 | 22 | post.too_many_tags 23 | Занадто багато тегів (додайте { limit } тегів або менше) 24 | 25 | 26 | comment.blank 27 | Будь ласка, не залишайте текст коментаря порожнім! 28 | 29 | 30 | comment.too_short 31 | Коментар занадто короткий, (мінімум { limit } символів). 32 | 33 | 34 | comment.too_long 35 | Коментар занадто довгий, (максимум { limit } символів). 36 | 37 | 38 | comment.is_spam 39 | Зміст цього коментаря було розцінено як спам. 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /translations/validators+intl-icu.zh_CN.xlf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | post.blank_summary 7 | 请填写文章摘要! 8 | 9 | 10 | post.blank_content 11 | 请填写文章内容! 12 | 13 | 14 | post.too_short_content 15 | 文章内容太少 最少 ({ limit } 个字 ) 16 | 17 | 18 | post.too_many_tags 19 | 标签太多 (最多 { limit } 个标签) 20 | 21 | 22 | comment.blank 23 | 评论内容不能为空! 24 | 25 | 26 | comment.too_short 27 | 评论内容太少 (最少 { limit } 个字) 28 | 29 | 30 | comment.too_long 31 | 评论内容太多 (最多 { limit } 个字) 32 | 33 | 34 | comment.is_spam 35 | 非法评论. 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /var/log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/var/log/.gitkeep -------------------------------------------------------------------------------- /var/sessions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/msalsas/symfony-bundle-skeleton/bd87bfd41182ac7c1b0b505ba9567b0ee82fd153/var/sessions/.gitkeep -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | // This project uses "Yarn" package manager for managing JavaScript dependencies along 2 | // with "Webpack Encore" library that helps working with the CSS and JavaScript files 3 | // that are stored in the "assets/" directory. 4 | // 5 | // Read https://symfony.com/doc/current/frontend.html to learn more about how 6 | // to manage CSS and JavaScript files in Symfony applications. 7 | var Encore = require('@symfony/webpack-encore'); 8 | 9 | Encore 10 | .setOutputPath('public/build/') 11 | .setPublicPath('/build') 12 | .cleanupOutputBeforeBuild() 13 | .autoProvidejQuery() 14 | .autoProvideVariables({ 15 | "window.Bloodhound": require.resolve('bloodhound-js'), 16 | "jQuery.tagsinput": "bootstrap-tagsinput" 17 | }) 18 | .enableSassLoader() 19 | // when versioning is enabled, each filename will include a hash that changes 20 | // whenever the contents of that file change. This allows you to use aggressive 21 | // caching strategies. Use Encore.isProduction() to enable it only for production. 22 | .enableVersioning(false) 23 | .addEntry('app', './assets/js/app.js') 24 | .addEntry('login', './assets/js/login.js') 25 | .addEntry('admin', './assets/js/admin.js') 26 | .addEntry('search', './assets/js/search.js') 27 | .splitEntryChunks() 28 | .enableSingleRuntimeChunk() 29 | .enableIntegrityHashes(Encore.isProduction()) 30 | .configureBabel(null, { 31 | useBuiltIns: 'usage', 32 | corejs: 3, 33 | }) 34 | ; 35 | 36 | module.exports = Encore.getWebpackConfig(); 37 | --------------------------------------------------------------------------------