├── .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 |
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 |
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 |
18 | {{ button_label|default('label.create_post'|trans) }}
19 |
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 | {{ 'label.title'|trans }}
12 | {{ 'label.published_at'|trans }}
13 | {{ 'label.actions'|trans }}
14 |
15 |
16 |
17 | {% for post in posts %}
18 |
19 | {{ post.title }}
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 | {{ post.publishedAt|format_datetime('medium', 'short', '', 'UTC') }}
24 |
25 |
34 |
35 |
36 | {% else %}
37 |
38 | {{ 'post.no_posts_found'|trans }}
39 |
40 | {% endfor %}
41 |
42 |
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 |
16 | {{ 'label.create_post'|trans }}
17 |
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 |
9 | {{ post.publishedAt|format_datetime('long', 'medium', '', 'UTC') }}
10 | {{ post.author.fullName }}
11 |
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 |
36 | {{ 'action.publish_comment'|trans }}
37 |
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 |
3 |
4 |
5 |
6 |
{{ 'delete_post_modal.title'|trans }}
7 |
{{ 'delete_post_modal.body'|trans }}
8 |
9 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/templates/blog/_post_tags.html.twig:
--------------------------------------------------------------------------------
1 | {% if not post.tags.empty %}
2 |
3 | {% for tag in post.tags %}
4 |
7 | {{ tag.name }}
8 |
9 | {% endfor %}
10 |
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 |
13 |
14 |
15 | {{ post.publishedAt|format_datetime('long', 'medium', '', 'UTC') }}
16 | {{ post.author.fullName }}
17 |
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 |
29 |
50 |
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 |
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 |
7 | {{ 'action.show_code'|trans }}
8 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 | {% if controller %}
22 |
23 |
{{ controller.source_code }}
24 | {% else %}
25 |
26 |
{{ 'not_available'|trans }}
27 | {% endif %}
28 |
29 |
30 |
{{ template.source_code }}
31 |
32 |
33 |
34 |
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 |
23 |
24 | ×
25 |
26 |
27 | {{ message|trans }}
28 |
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 |
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 | {{ 'info.change_password'|trans }}
9 |
10 | {{ form_start(form) }}
11 | {{ form_widget(form) }}
12 |
13 |
14 | {{ 'action.save'|trans }}
15 |
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 |
12 | {{ 'action.save'|trans }}
13 |
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 |
25 |
29 |
33 |
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 |
21 |
25 |
29 |
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 |
17 |
21 |
25 |
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 |
21 |
25 |
29 |
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 |
29 |
33 |
37 |
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 |
25 |
29 |
33 |
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 |
21 |
25 |
29 |
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 |
25 |
29 |
33 |
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 |
21 |
25 |
29 |
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 |
21 |
25 |
29 |
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 |
21 |
25 |
29 |
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 |
25 |
29 |
33 |
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 |
21 |
25 |
29 |
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 |
21 |
25 |
29 |
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 |
25 |
29 |
33 |
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 |
21 |
25 |
29 |
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 |
29 |
33 |
37 |
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 |
25 |
29 |
33 |
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 |
25 |
29 |
33 |
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 |
29 |
33 |
37 |
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 |
25 |
29 |
33 |
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 |
--------------------------------------------------------------------------------