├── var ├── cache │ └── .gitkeep ├── data │ └── .gitkeep └── log │ └── .gitkeep ├── migrations └── .gitignore ├── public ├── files │ ├── .gitkeep │ └── kittens.jpg ├── thumbs │ └── .gitkeep ├── theme │ └── base-2021 │ │ └── .gitkeep ├── .gitignore ├── robots.txt ├── index.php └── .htaccess ├── src ├── Entity │ └── .gitignore ├── Controller │ └── .gitignore ├── Repository │ └── .gitignore ├── Kernel.php └── .preload.php ├── translations └── .gitkeep ├── config ├── extensions │ ├── .gitkeep │ └── .gitignore ├── checkpoint.txt ├── packages │ ├── mailer.yaml │ ├── assets.yaml │ ├── doctrine_migrations.yaml │ ├── reset_password.yaml │ ├── routing.yaml │ ├── php_translation.yaml │ ├── web_profiler.yaml │ ├── nelmio_cors.yaml │ ├── translation.yaml │ ├── extension_article.yaml │ ├── api_platform.yaml │ ├── twig.yaml │ ├── extension_redactor.yaml │ ├── framework.yaml │ ├── monolog.yaml │ ├── webpack_encore.yaml │ ├── nelmio_security.yaml │ ├── doctrine.yaml │ └── security.yaml ├── routes │ ├── dev │ │ ├── framework.yaml │ │ ├── translation.yaml │ │ ├── php_translation.yaml │ │ └── web_profiler.yaml │ ├── translation.yaml │ ├── annotations.yaml │ ├── extension_article.yaml │ ├── extension_redactor.yaml │ ├── api_platform.yaml │ └── bolt.yaml ├── bolt │ ├── menu.yaml │ ├── taxonomy.yaml │ ├── permissions.yaml │ ├── config.yaml │ └── contenttypes.yaml ├── services_bolt.yaml ├── bundles.php ├── routes.yaml └── services.yaml ├── phpstan.dist.neon ├── docker ├── php │ ├── docker-healthcheck.sh │ ├── conf.d │ │ ├── bolt.dev.ini │ │ └── bolt.prod.ini │ └── docker-entrypoint.sh ├── h2-proxy │ ├── conf.d │ │ └── default.conf │ └── Dockerfile └── nginx │ └── conf.d │ └── default.conf ├── bin ├── post-create-project.php └── console ├── tests └── bootstrap.php ├── package.json ├── .dockerignore ├── LICENSE ├── .env.local ├── .gitignore ├── Makefile ├── compose.yaml ├── .editorconfig ├── README_project.md ├── .env ├── composer.json ├── index.php ├── Dockerfile ├── ecs.php ├── README.md ├── UPDATE.md └── symfony.lock /var/cache/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /var/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /var/log/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /migrations/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/files/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/thumbs/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Entity/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /translations/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/extensions/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Controller/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Repository/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/checkpoint.txt: -------------------------------------------------------------------------------- 1 | 6.0.0 2 | -------------------------------------------------------------------------------- /public/theme/base-2021/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /config/extensions/.gitignore: -------------------------------------------------------------------------------- 1 | *.yaml 2 | -------------------------------------------------------------------------------- /public/.gitignore: -------------------------------------------------------------------------------- 1 | assets/ 2 | theme/ 3 | -------------------------------------------------------------------------------- /config/packages/mailer.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | mailer: 3 | dsn: '%env(MAILER_DSN)%' 4 | -------------------------------------------------------------------------------- /public/files/kittens.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/project/HEAD/public/files/kittens.jpg -------------------------------------------------------------------------------- /config/routes/dev/framework.yaml: -------------------------------------------------------------------------------- 1 | _errors: 2 | resource: '@FrameworkBundle/Resources/config/routing/errors.xml' 3 | prefix: /_error 4 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /config/routes/dev/translation.yaml: -------------------------------------------------------------------------------- 1 | _translation_profiler: 2 | resource: '@TranslationBundle/Resources/config/routing_symfony_profiler.yaml' 3 | -------------------------------------------------------------------------------- /config/packages/assets.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | assets: 3 | json_manifest_path: '%kernel.project_dir%/%bolt.public_folder%/assets/manifest.json' 4 | -------------------------------------------------------------------------------- /config/packages/doctrine_migrations.yaml: -------------------------------------------------------------------------------- 1 | doctrine_migrations: 2 | migrations_paths: 3 | DoctrineMigrations: '%kernel.project_dir%/migrations' 4 | -------------------------------------------------------------------------------- /config/packages/reset_password.yaml: -------------------------------------------------------------------------------- 1 | symfonycasts_reset_password: 2 | request_password_repository: Bolt\Repository\ResetPasswordRequestRepository 3 | -------------------------------------------------------------------------------- /config/packages/routing.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | router: 3 | utf8: true 4 | 5 | when@prod: 6 | framework: 7 | router: 8 | strict_requirements: ~ 9 | -------------------------------------------------------------------------------- /config/routes/translation.yaml: -------------------------------------------------------------------------------- 1 | _translation_webui: 2 | resource: "@TranslationBundle/Resources/config/routing_webui.yaml" 3 | prefix: '%bolt.backend_url%' 4 | -------------------------------------------------------------------------------- /config/packages/php_translation.yaml: -------------------------------------------------------------------------------- 1 | # php-translation config 2 | 3 | translation: 4 | configs: 5 | bolt: 6 | output_dir: "%kernel.project_dir%/translations" 7 | -------------------------------------------------------------------------------- /phpstan.dist.neon: -------------------------------------------------------------------------------- 1 | parameters: 2 | level: 8 3 | 4 | paths: 5 | - src 6 | 7 | treatPhpDocTypesAsCertain: false 8 | reportUnmatchedIgnoredErrors: true 9 | -------------------------------------------------------------------------------- /src/Kernel.php: -------------------------------------------------------------------------------- 1 | bootEnv(dirname(__DIR__).'/.env'); 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@symfony/webpack-encore": "^1.8", 4 | "core-js": "^3.33", 5 | "regenerator-runtime": "^0.13.2", 6 | "webpack-notifier": "^1.15.0" 7 | }, 8 | "license": "UNLICENSED", 9 | "private": true, 10 | "scripts": { 11 | "dev-server": "encore dev-server", 12 | "dev": "encore dev", 13 | "watch": "encore dev --watch", 14 | "build": "encore production --progress" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /docker/php/conf.d/bolt.prod.ini: -------------------------------------------------------------------------------- 1 | apc.enable_cli = 1 2 | date.timezone = UTC 3 | session.auto_start = Off 4 | short_open_tag = Off 5 | 6 | # https://symfony.com/doc/current/performance.html 7 | opcache.interned_strings_buffer = 16 8 | opcache.max_accelerated_files = 20000 9 | opcache.memory_consumption = 256 10 | opcache.validate_timestamps = 0 11 | realpath_cache_size = 4096K 12 | realpath_cache_ttl = 600 13 | opcache.preload_user=www-data 14 | opcache.preload=/srv/bolt/var/cache/prod/App_KernelProdContainer.preload.php 15 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | **/*.log 2 | **/*.md 3 | **/*.php~ 4 | **/._* 5 | **/.dockerignore 6 | **/.DS_Store 7 | **/.git/ 8 | **/.gitattributes 9 | **/.gitignore 10 | **/.gitmodules 11 | **/docker-compose.*.yaml 12 | **/docker-compose.*.yml 13 | **/docker-compose.yaml 14 | **/docker-compose.yml 15 | **/Dockerfile 16 | **/Thumbs.db 17 | .editorconfig 18 | .env.*.local 19 | .env.local 20 | .env.local.php 21 | LICENSE 22 | bin/* 23 | !bin/console 24 | build/ 25 | docker/db/data/ 26 | public/assets/ 27 | public/bundles/ 28 | var/ 29 | vendor/ 30 | -------------------------------------------------------------------------------- /docker/h2-proxy/conf.d/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 8443 ssl http2; 3 | listen [::]:8443 ssl http2; 4 | 5 | ssl_certificate /etc/nginx/ssl/cert.crt; 6 | ssl_certificate_key /etc/nginx/ssl/cert.key; 7 | 8 | location / { 9 | proxy_pass http://nginx; 10 | proxy_http_version 1.1; 11 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 12 | proxy_set_header X-Forwarded-Host $host; 13 | proxy_set_header X-Forwarded-Proto $scheme; 14 | proxy_set_header X-Forwarded-Port 8443; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /config/packages/translation.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | default_locale: '%locale%' 3 | translator: 4 | default_path: '%kernel.project_dir%/translations' 5 | fallbacks: 6 | - 'en' 7 | 8 | # php_translation 9 | translation: 10 | locales: '%locales_array%' 11 | default_locale: '%locale%' 12 | webui: 13 | enabled: true 14 | edit_in_place: 15 | enabled: false 16 | config_name: site 17 | configs: 18 | site: 19 | dirs: [ "%kernel.project_dir%/public/theme/%bolt.theme%" ] 20 | output_dir: "%kernel.project_dir%/translations" 21 | auto_add_missing_translations: 22 | enabled: true 23 | config_name: site 24 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | first menu item. 7 | link: homepage 8 | class: homepage 9 | - label: About 10 | link: page/2 11 | submenu: 12 | - label: Sub 1 13 | link: entry/39 14 | - label: Sub 2 15 | class: menu-item-class 16 | link: entry/40 17 | - link: entry/41 # These two have no `label`, so they will show up as the title 18 | - class: sub-class 19 | link: page/42 20 | - label: All pages 21 | link: pages/ 22 | - label: The Bolt site 23 | link: https://boltcms.io 24 | class: bolt-site 25 | title: Visit the excellent Bolt website! 26 | 27 | foo: bar 28 | -------------------------------------------------------------------------------- /config/packages/extension_redactor.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | _defaults: 3 | autowire: true 4 | autoconfigure: true 5 | 6 | Bolt\Redactor\Controller\Images: 7 | tags: [ 'controller.service_arguments' ] 8 | 9 | Bolt\Redactor\Controller\Upload: 10 | tags: [ 'controller.service_arguments' ] 11 | 12 | Bolt\Redactor\TwigExtension: 13 | arguments: 14 | $projectDir: '%kernel.project_dir%' 15 | $publicFolder: '%bolt.public_folder%' 16 | 17 | ### Map entities 18 | doctrine: 19 | orm: 20 | auto_generate_proxy_classes: '%kernel.debug%' 21 | naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware 22 | auto_mapping: true 23 | mappings: 24 | Redactor: 25 | is_bundle: false 26 | type: attribute 27 | dir: '%kernel.project_dir%/vendor/bolt/redactor/src/Entity' 28 | prefix: 'Bolt\Redactor' 29 | alias: Redactor 30 | -------------------------------------------------------------------------------- /config/services_bolt.yaml: -------------------------------------------------------------------------------- 1 | # This file is auto-generated by Bolt. Please change no more than binds. 2 | 3 | services: 4 | _defaults: 5 | autowire: true 6 | autoconfigure: true 7 | bind: { } 8 | Bolt\Article\: 9 | resource: '../vendor/bolt/article/src/*' 10 | exclude: '../vendor/bolt/article/src/{Entity,Exception}' 11 | Bolt\ConfigurationNoticesWidget\: 12 | resource: '../vendor/bolt/configuration-notices-widget/src/*' 13 | exclude: '../vendor/bolt/configuration-notices-widget/src/{Entity,Exception}' 14 | Bolt\NewsWidget\: 15 | resource: '../vendor/bolt/newswidget/src/*' 16 | exclude: '../vendor/bolt/newswidget/src/{Entity,Exception}' 17 | Bolt\Redactor\: 18 | resource: '../vendor/bolt/redactor/src/*' 19 | exclude: '../vendor/bolt/redactor/src/{Entity,Exception}' 20 | Bolt\WeatherWidget\: 21 | resource: '../vendor/bolt/weatherwidget/src/*' 22 | exclude: '../vendor/bolt/weatherwidget/src/{Entity,Exception}' 23 | -------------------------------------------------------------------------------- /config/bolt/taxonomy.yaml: -------------------------------------------------------------------------------- 1 | # This file defines the different types of taxonomies in Bolt. See the 2 | # documentation for details: https://docs.bolt.cm/contenttypes/taxonomies 3 | 4 | tags: 5 | slug: tags 6 | singular_slug: tag 7 | behaves_like: tags 8 | postfix: "Add some freeform tags. Start a new tag by typing a comma or space." 9 | allow_spaces: false 10 | #listing_template: tag-listing.twig #custom template 11 | required: false 12 | 13 | groups: 14 | slug: groups 15 | singular_slug: group 16 | behaves_like: grouping 17 | options: { main: "The main group", meta: "Meta group", other: "The other stuff" } 18 | has_sortorder: true 19 | required: false 20 | 21 | categories: 22 | name: Categories 23 | slug: categories 24 | singular_name: Category 25 | singular_slug: category 26 | behaves_like: categories 27 | multiple: true 28 | options: [ news, events, movies, music, books, life, love, fun ] 29 | required: false 30 | -------------------------------------------------------------------------------- /config/routes/bolt.yaml: -------------------------------------------------------------------------------- 1 | # All route definitions, used by Bolt: Bolt Control Panel ("backend"), Async and 2 | # Thumbs, unless overridden in `../routing.yml` or another location. 3 | 4 | # The Bolt Control Panel ("backend"). It's common to modify the `prefix` so the 5 | # Control Panel can be accessed at a custom URL. 6 | control_panel: 7 | resource: '../../vendor/bolt/core/src/Controller/Backend/' 8 | prefix: '%bolt.backend_url%' 9 | type: attribute 10 | 11 | # Async: Upload, Embed 12 | control_panel_async: 13 | resource: '../../vendor/bolt/core/src/Controller/Backend/Async' 14 | prefix: '%bolt.backend_url%/async' 15 | type: attribute 16 | 17 | # ImageController, Currently only used for thumbnails 18 | controllers: 19 | resource: '../../vendor/bolt/core/src/Controller/ImageController.php' 20 | type: attribute 21 | 22 | # Routes added by Extensions get added here, by Bolt\Extension\RoutesLoader 23 | extensions: 24 | resource: . 25 | type: bolt_extensions 26 | -------------------------------------------------------------------------------- /config/packages/framework.yaml: -------------------------------------------------------------------------------- 1 | framework: 2 | secret: '%env(APP_SECRET)%' 3 | csrf_protection: 4 | enabled: true 5 | http_method_override: true 6 | trusted_hosts: ~ 7 | session: 8 | handler_id: ~ 9 | cookie_lifetime: 1209600 10 | storage_factory_id: session.storage.factory.native 11 | cookie_secure: true 12 | cookie_samesite: lax 13 | esi: 14 | enabled: true 15 | fragments: 16 | enabled: true 17 | php_errors: 18 | log: true 19 | assets: 20 | json_manifest_path: '%kernel.project_dir%/%bolt.public_folder%/assets/manifest.json' 21 | cache: 22 | prefix_seed: bolt 23 | ide: phpstorm 24 | validation: 25 | email_validation_mode: html5 26 | translator: 27 | paths: 28 | - '%kernel.project_dir%/translations' 29 | - '%kernel.project_dir%/vendor/bolt/core/translations' 30 | error_controller: 'Bolt\Controller\ErrorController::showAction' 31 | annotations: false 32 | handle_all_throwables: true 33 | 34 | when@test: 35 | framework: 36 | test: true 37 | session: 38 | storage_factory_id: session.storage.factory.mock_file 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2020 Bob den Otter 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 | -------------------------------------------------------------------------------- /config/packages/monolog.yaml: -------------------------------------------------------------------------------- 1 | monolog: 2 | channels: [ 'db' ] 3 | handlers: 4 | db: 5 | channels: [ 'db' ] 6 | type: service 7 | id: Bolt\Log\LogHandler 8 | 9 | when@dev: 10 | monolog: 11 | handlers: 12 | main: 13 | type: stream 14 | path: '%kernel.logs_dir%/%kernel.environment%.log' 15 | level: debug 16 | channels: [ '!event' ] 17 | # uncomment to get logging in your browser 18 | # you may have to allow bigger header sizes in your Web server configuration 19 | #firephp: 20 | # type: firephp 21 | # level: info 22 | #chromephp: 23 | # type: chromephp 24 | # level: info 25 | console: 26 | type: console 27 | process_psr_3_messages: false 28 | channels: [ '!event', '!doctrine', '!console' ] 29 | 30 | when@prod: 31 | monolog: 32 | handlers: 33 | main: 34 | type: fingers_crossed 35 | action_level: error 36 | handler: nested 37 | excluded_http_codes: [ 404 ] 38 | nested: 39 | type: stream 40 | path: '%kernel.logs_dir%/%kernel.environment%.log' 41 | level: debug 42 | console: 43 | type: console 44 | process_psr_3_messages: false 45 | channels: [ '!event', '!doctrine' ] 46 | -------------------------------------------------------------------------------- /.env.local: -------------------------------------------------------------------------------- 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 | # USE THIS FILE FOR SECRETS THAT WILL NOT BE COMMITTED. YOU CAN ALSO USE THIS FOR DATABASE CONFIGURATIONS. 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.html#use-environment-variables-for-infrastructure-configuration 15 | 16 | 17 | ###> symfony/framework-bundle ### 18 | #APP_SECRET=!ChangeMe! 19 | ###< symfony/framework-bundle ### 20 | 21 | # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml 22 | 23 | # SQLite (note: _three_ slashes) 24 | #DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/bolt.sqlite 25 | 26 | # MYSQL / MariaDB 27 | #DATABASE_URL=mysql://db_user:"db_password"@localhost:3306/db_name?serverVersion=5.7 28 | 29 | # Postgres 30 | #DATABASE_URL=postgresql://db_user:"db_password"@localhost:5432/db_name?serverVersion=11 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Comment out the following line, if you wish to store your SQLite database in Git 2 | /var/data/* 3 | 4 | ###> bolt/core ### 5 | config/bolt/*_local.yaml 6 | config/extensions/*_local.yaml 7 | /config/packages/local 8 | /config/routes/local 9 | /public/files/* 10 | !/public/files/.gitkeep 11 | !/public/files/index.html 12 | /public/thumbs/* 13 | !/public/thumbs/.gitkeep 14 | !/public/thumbs/index.html 15 | ###< bolt/core ### 16 | 17 | ### NPM and frontend assets building cruft 18 | node_modules/ 19 | npm-debug.log 20 | yarn-error.log 21 | build_assets.sh 22 | 23 | ### File-system cruft and temporary files 24 | __* 25 | ._* 26 | .*.swp 27 | .swp 28 | *.lock 29 | !symfony.lock 30 | *lock.json 31 | .buildpath 32 | 33 | ### Platfom-specific files 34 | .DS_Store 35 | thumbs.db 36 | Vagrantfile 37 | .vagrant* 38 | .idea 39 | .php-version 40 | .vscode/* 41 | *.code-workspace 42 | appveyor.yml 43 | 44 | ###> Docker ### 45 | docker-compose.override.yml 46 | docker-compose.override.yaml 47 | ###< Docker ### 48 | ###> symfony/framework-bundle ### 49 | /.env.local 50 | /.env.local.php 51 | /.env.*.local 52 | /config/secrets/prod/prod.decrypt.private.php 53 | /public/assets/ 54 | /public/bundles/ 55 | /var/cache/* 56 | !/var/cache/.gitkeep 57 | /var/log/* 58 | !/var/log/.gitkeep 59 | !/var/data/.gitkeep 60 | /var/sessions/* 61 | !/var/sessions/.gitkeep 62 | /vendor/ 63 | .web-server-pid 64 | ###< symfony/framework-bundle ### 65 | -------------------------------------------------------------------------------- /config/bundles.php: -------------------------------------------------------------------------------- 1 | ['all' => true], 5 | BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true], 6 | Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class => ['all' => true], 7 | Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['all' => true], 8 | Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle::class => ['all' => true], 9 | Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true], 10 | Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true], 11 | Nelmio\SecurityBundle\NelmioSecurityBundle::class => ['all' => true], 12 | Symfony\Bundle\DebugBundle\DebugBundle::class => ['all' => true], 13 | Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true], 14 | Symfony\Bundle\MonologBundle\MonologBundle::class => ['all' => true], 15 | Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], 16 | Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], 17 | Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'local' => true], 18 | Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true], 19 | SymfonyCasts\Bundle\ResetPassword\SymfonyCastsResetPasswordBundle::class => ['all' => true], 20 | Translation\Bundle\TranslationBundle::class => ['all' => true], 21 | Twig\Extra\TwigExtraBundle\TwigExtraBundle::class => ['all' => true], 22 | ]; 23 | -------------------------------------------------------------------------------- /config/packages/webpack_encore.yaml: -------------------------------------------------------------------------------- 1 | webpack_encore: 2 | # The path where Encore is building the assets. 3 | # This should match Encore.setOutputPath() in webpack.config.js. 4 | output_path: '%kernel.project_dir%/%bolt.public_folder%/assets' 5 | # If multiple builds are defined (as shown below), you can disable the default build: 6 | # output_path: false 7 | 8 | # if using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials') 9 | # crossorigin: 'anonymous' 10 | 11 | # preload all rendered script and link tags automatically via the http2 Link header 12 | # preload: true 13 | 14 | # Throw an exception if the entrypoints.json file is missing or an entry is missing from the data 15 | # strict_mode: false 16 | 17 | # if you have multiple builds: 18 | # builds: 19 | # pass "frontend" as the 3rg arg to the Twig functions 20 | # {{ encore_entry_script_tags('entry1', null, 'frontend') }} 21 | 22 | # frontend: '%kernel.project_dir%/public/frontend/build' 23 | 24 | # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes) 25 | # Put in config/packages/prod/webpack_encore.yaml 26 | # cache: true 27 | 28 | when@prod: 29 | webpack_encore: 30 | preload: true 31 | cache: true 32 | 33 | when@test: 34 | webpack_encore: 35 | # Disable strict mode for phpunit to enable ContentEditControllerTest to run without 36 | # having to invoke webpack first to create public/assets/entrypoints.json 37 | strict_mode: false 38 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help install server server-stop cache csclear cscheck csfix stancheck db-update db-reset 2 | .DEFAULT_GOAL := help 3 | 4 | help: 5 | @grep -E '(^[a-zA-Z_-]+:.*?##.*$$)|(^##)' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}' | sed -e 's/\[32m##/[33m/' 6 | 7 | install: ## to install all project 8 | composer install 9 | make db-reset 10 | 11 | server: ## to start server 12 | bin/console server:start 127.0.0.1:8088 || true 13 | 14 | server-stop: ## to stop server 15 | bin/console server:stop 16 | 17 | cache: ## to clean cache 18 | bin/console cache:clear 19 | 20 | csclear: ## to clean cache and check coding style 21 | mkdir -p var/cache/ecs 22 | chmod -R a+rw var/cache/ecs 23 | rm -rf var/cache/ecs/* 24 | 25 | cscheck: ## to check coding style 26 | make csclear 27 | composer lint 28 | make stancheck 29 | 30 | csfix: ## to fix coding style 31 | make csclear 32 | composer lint:fix 33 | make stancheck 34 | 35 | stancheck: ## to run phpstan 36 | composer phpstan 37 | 38 | db-update: ## to update schema database 39 | bin/console doctrine:schema:update --complete --force 40 | bin/console doctrine:migrations:sync-metadata-storage -q 41 | bin/console doctrine:migrations:version --add --all --no-interaction -q 42 | 43 | db-reset: ## to delete database and load fixtures 44 | bin/console doctrine:schema:drop --force --full-database 45 | bin/console doctrine:schema:create -q 46 | bin/console doctrine:migrations:sync-metadata-storage -q 47 | bin/console doctrine:migrations:version --add --all --no-interaction -q 48 | bin/console doctrine:fixtures:load --no-interaction 49 | -------------------------------------------------------------------------------- /compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | db: 3 | image: mysql:5.7 4 | environment: 5 | - MYSQL_DATABASE=bolt 6 | - MYSQL_USER=bolt 7 | - MYSQL_PASSWORD=!ChangeMe! 8 | - MYSQL_ROOT_PASSWORD=!ChangeMe! 9 | volumes: 10 | - db-data:/var/lib/mysql:rw 11 | # You may use a bind-mounted host directory instead, so that it is harder to accidentally remove the volume and lose all your data! 12 | # - ./docker/db/data:/var/lib/mysql:rw 13 | ports: 14 | - target: 3306 15 | published: 3306 16 | protocol: tcp 17 | 18 | php: 19 | build: 20 | context: ./ 21 | target: php 22 | healthcheck: 23 | interval: 10s 24 | timeout: 3s 25 | retries: 3 26 | start_period: 30s 27 | depends_on: 28 | - db 29 | - mailcatcher 30 | volumes: 31 | - ./:/srv/bolt:rw,cached 32 | - ./docker/php/conf.d/bolt.dev.ini:/usr/local/etc/php/conf.d/bolt.ini 33 | # if you develop on Linux, you may use a bind-mounted host directory instead 34 | # - ./var:/srv/bolt/var:rw 35 | 36 | nginx: 37 | build: 38 | context: ./ 39 | target: nginx 40 | depends_on: 41 | - php 42 | volumes: 43 | - ./public:/srv/bolt/public:ro 44 | ports: 45 | - target: 80 46 | published: 8080 47 | protocol: tcp 48 | 49 | h2-proxy: 50 | build: 51 | context: ./docker/h2-proxy 52 | depends_on: 53 | - nginx 54 | ports: 55 | - target: 8443 56 | published: 8443 57 | protocol: tcp 58 | 59 | mailcatcher: 60 | image: schickling/mailcatcher 61 | ports: 62 | - target: 1080 63 | published: 1080 64 | protocol: tcp 65 | 66 | volumes: 67 | db-data: {} 68 | -------------------------------------------------------------------------------- /config/packages/nelmio_security.yaml: -------------------------------------------------------------------------------- 1 | nelmio_security: 2 | 3 | # Signs/verifies all cookies 4 | # Temporarily disabled. See https://github.com/nelmio/NelmioSecurityBundle/issues/154 5 | #signed_cookie: 6 | # names: ['*'] 7 | 8 | # Prevents framing of the entire site 9 | clickjacking: 10 | paths: 11 | '^/.*': DENY 12 | 13 | # Disables content type sniffing for script resources 14 | content_type: 15 | nosniff: true 16 | 17 | # Forces Microsoft's XSS-Protection with its block mode 18 | xss_protection: 19 | enabled: true 20 | mode_block: true 21 | 22 | # Send a full URL in the `Referer` header when performing a same-origin 23 | # request, only send the origin of the document to secure destination 24 | # (HTTPS->HTTPS), and send no header to a less secure destination 25 | # (HTTPS->HTTP). If `strict-origin-when-cross-origin` is not supported, use 26 | # `no-referrer` policy, no referrer information is sent along with 27 | # requests. 28 | 29 | referrer_policy: 30 | enabled: true 31 | policies: 32 | - 'no-referrer' 33 | - 'strict-origin-when-cross-origin' 34 | 35 | # Forces HTTPS handling, DO NOT combine with flexible mode and 36 | # make sure you have SSL working on your site before enabling this 37 | # forced_ssl: 38 | # hsts_max_age: 2592000 # 30 days 39 | # hsts_subdomains: true 40 | # redirect_status_code: 302 # default, switch to 301 for permanent redirects 41 | 42 | # Flexible HTTPS handling, read the detailed config info and make sure you 43 | # have SSL working on your site before enabling this 44 | # flexible_ssl: 45 | # cookie_name: auth 46 | # unsecured_logout: false 47 | 48 | # Prevents redirections outside the website's domain 49 | # external_redirects: 50 | # abort: true 51 | # log: true 52 | -------------------------------------------------------------------------------- /docker/php/docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # first arg is `-f` or `--some-option` 5 | if [ "${1#-}" != "$1" ]; then 6 | set -- php-fpm "$@" 7 | fi 8 | 9 | if [ "$1" = 'php-fpm' ] || [ "$1" = 'php' ] || [ "$1" = 'bin/console' ]; then 10 | PHP_INI_RECOMMENDED="$PHP_INI_DIR/php.ini-production" 11 | if [ "$APP_ENV" != 'prod' ]; then 12 | PHP_INI_RECOMMENDED="$PHP_INI_DIR/php.ini-development" 13 | fi 14 | ln -sf "$PHP_INI_RECOMMENDED" "$PHP_INI_DIR/php.ini" 15 | 16 | mkdir -p public/files public/theme public/thumbs var/cache var/log 17 | setfacl -R -m u:www-data:rwX -m u:"$(whoami)":rwX config public/files public/theme public/thumbs var 18 | setfacl -dR -m u:www-data:rwX -m u:"$(whoami)":rwX config public/files public/theme public/thumbs var 19 | 20 | if [ "$APP_ENV" != 'prod' ]; then 21 | composer install --prefer-dist --no-progress --no-suggest --no-interaction 22 | fi 23 | 24 | echo "Waiting for db to be ready..." 25 | ATTEMPTS_LEFT_TO_REACH_DATABASE=60 26 | until [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ] || bin/console doctrine:query:sql "SELECT 1" > /dev/null 2>&1; do 27 | sleep 1 28 | ATTEMPTS_LEFT_TO_REACH_DATABASE=$((ATTEMPTS_LEFT_TO_REACH_DATABASE-1)) 29 | echo "Still waiting for db to be ready... Or maybe the db is not reachable. $ATTEMPTS_LEFT_TO_REACH_DATABASE attempts left" 30 | done 31 | 32 | if [ $ATTEMPTS_LEFT_TO_REACH_DATABASE -eq 0 ]; then 33 | echo "The db is not up or not reachable" 34 | exit 1 35 | else 36 | echo "The db is now ready and reachable" 37 | php bin/console bolt:info 38 | fi 39 | 40 | if ! ls -A public/theme/* > /dev/null 2>&1; then 41 | composer run post-create-project-cmd 42 | fi 43 | 44 | if ls -A migrations/*.php > /dev/null 2>&1; then 45 | bin/console doctrine:migrations:migrate --no-interaction 46 | fi 47 | fi 48 | 49 | exec docker-php-entrypoint "$@" 50 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | # Change these settings to your own preference 9 | indent_style = space 10 | indent_size = 4 11 | 12 | # We recommend you to keep these unchanged 13 | end_of_line = lf 14 | charset = utf-8 15 | trim_trailing_whitespace = true 16 | insert_final_newline = true 17 | 18 | [*.feature] 19 | indent_style = space 20 | indent_size = 2 21 | 22 | [*.js] 23 | indent_style = space 24 | indent_size = 4 25 | 26 | [*.json] 27 | indent_style = space 28 | indent_size = 4 29 | 30 | [*.md] 31 | trim_trailing_whitespace = false 32 | 33 | [*.php] 34 | indent_style = space 35 | indent_size = 4 36 | 37 | [*.scss] 38 | indent_style = space 39 | indent_size = 2 40 | 41 | [*.sh] 42 | indent_style = tab 43 | indent_size = 4 44 | 45 | [*.vcl] 46 | indent_style = space 47 | indent_size = 2 48 | 49 | [*.xml] 50 | indent_style = space 51 | indent_size = 4 52 | 53 | [*.{yaml,yml}] 54 | indent_style = space 55 | indent_size = 2 56 | trim_trailing_whitespace = false 57 | 58 | [.github/workflows/*.yml] 59 | indent_style = space 60 | indent_size = 2 61 | 62 | [.gitmodules] 63 | indent_style = tab 64 | indent_size = 4 65 | 66 | [*.neon{,.dist}] 67 | indent_style = tab 68 | indent_size = 4 69 | 70 | [.php_cs{,.dist}] 71 | indent_style = space 72 | indent_size = 4 73 | 74 | [composer.json] 75 | indent_style = space 76 | indent_size = 4 77 | 78 | [docker-compose{,.*}.{yaml,yml}] 79 | indent_style = space 80 | indent_size = 2 81 | 82 | [Dockerfile] 83 | indent_style = tab 84 | indent_size = 4 85 | 86 | [Makefile] 87 | indent_style = tab 88 | indent_size = 4 89 | 90 | [package.json] 91 | indent_style = space 92 | indent_size = 2 93 | 94 | [phpunit.xml{,.dist}] 95 | indent_style = space 96 | indent_size = 4 97 | -------------------------------------------------------------------------------- /README_project.md: -------------------------------------------------------------------------------- 1 | Bolt 5 standard project skeleton 2 | ================================ 3 | 4 | Welcome! This is a Bolt 5 project, set up using `composer create-project`. If 5 | you are the developer of this project, you can modify this README to the 6 | specifics of your project. Below are the general instructions to set up a _new_ 7 | project, based off the same skeleton. 8 | 9 | 10 | Note: If you're updating from an earlier beta, read UPDATE.md for details. 11 | 12 | --- 13 | 14 | Set up a new Bolt 4 project, using the following command, replacing 15 | `myprojectname` with your desired project's name. 16 | 17 | ```bash 18 | composer create-project bolt/project myprojectname 19 | ``` 20 | 21 | Navigate into the newly created folder, and configure the database in `.env`. 22 | You can skip this step, if you'd like to use SQLite. 23 | 24 | ```dotenv 25 | # SQLite 26 | DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/bolt.sqlite 27 | 28 | # MySQL 29 | DATABASE_URL=mysql://root:"root%1"@127.0.0.1:3306/four 30 | ``` 31 | 32 | Set up the database, create the first user and add fixtures (dummy content): 33 | 34 | ```bash 35 | bin/console bolt:setup 36 | ``` 37 | 38 | Run Bolt using Symfony CLI, Docker or your own 39 | preferred webserver: 40 | 41 | ```bash 42 | symfony server:start -d 43 | symfony open:local 44 | ``` 45 | 46 | Finally, open the new installation in a browser. If you've used one of the 47 | commands above, you'll find the frontpage at http://127.0.0.1:8000/ \ 48 | The Bolt admin panel can be found at http://127.0.0.1:8000/bolt 49 | 50 | Log in using the credentials you created when setting up the first user. 51 | 52 | ## Contributing 53 | 54 | If you'd like to contribute, please check [Bolt's core repository](https://github.com/bolt/core/blob/master/CONTRIBUTING.md) 55 | and read the ["Contributing to Bolt"](https://docs.bolt.cm/4.0/other/contributing) documentation page. 56 | -------------------------------------------------------------------------------- /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_DRIVER): 'pdo_mysql' 6 | env(DATABASE_URL): '' 7 | 8 | doctrine: 9 | dbal: 10 | charset: utf8mb4 11 | url: '%env(resolve:DATABASE_URL)%' 12 | use_savepoints: true 13 | 14 | # IMPORTANT: You MUST configure your server version, 15 | # either here or in the DATABASE_URL env var (see .env file) 16 | #server_version: '5.7' 17 | 18 | orm: 19 | auto_generate_proxy_classes: '%kernel.debug%' 20 | naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware 21 | auto_mapping: true 22 | mappings: 23 | App: 24 | is_bundle: false 25 | type: attribute 26 | dir: '%kernel.project_dir%/src/Entity' 27 | prefix: 'App\Entity' 28 | alias: App 29 | Bolt: 30 | is_bundle: false 31 | type: attribute 32 | dir: '%kernel.project_dir%/vendor/bolt/core/src/Entity' 33 | prefix: 'Bolt\Entity' 34 | alias: Bolt 35 | dql: 36 | string_functions: 37 | JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract 38 | JSON_GET_TEXT: Scienta\DoctrineJsonFunctions\Query\AST\Functions\Postgresql\JsonGetText 39 | JSON_SEARCH: Scienta\DoctrineJsonFunctions\Query\AST\Functions\Mysql\JsonSearch 40 | JSON_UNQUOTE: Bolt\Doctrine\Functions\JsonUnquote 41 | CAST: Bolt\Doctrine\Query\Cast 42 | numeric_functions: 43 | RAND: Bolt\Doctrine\Functions\Rand 44 | 45 | when@prod: 46 | doctrine: 47 | orm: 48 | auto_generate_proxy_classes: false 49 | proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' 50 | metadata_cache_driver: 51 | type: pool 52 | pool: doctrine.system_cache_pool 53 | query_cache_driver: 54 | type: pool 55 | pool: doctrine.system_cache_pool 56 | result_cache_driver: 57 | type: pool 58 | pool: doctrine.result_cache_pool 59 | 60 | framework: 61 | cache: 62 | pools: 63 | doctrine.result_cache_pool: 64 | adapter: cache.app 65 | doctrine.system_cache_pool: 66 | adapter: cache.system 67 | -------------------------------------------------------------------------------- /config/routes.yaml: -------------------------------------------------------------------------------- 1 | # This file defines routes for the frontend and control panel of your Bolt 2 | # website. Check below for examples, or read the documentation at 3 | # https://docs.bolt.cm/routing 4 | 5 | # ------------------------------------------------------------------------------ 6 | # Place your own routes here, that have a HIGHER priority than the default routes. 7 | 8 | 9 | 10 | # ------------------------------------------------------------------------------ 11 | # These are the routes defining the default behaviour of Bolt's frontend. 12 | # Changing these might give unexpected results or even break your website. If 13 | # possible, only add NEW routes above or below these. 14 | frontend: 15 | resource: '../vendor/bolt/core/src/Controller/Frontend/' 16 | prefix: / 17 | type: attribute 18 | 19 | # ------------------------------------------------------------------------------ 20 | # Place your own routes here, that have a LOWER priority than the default routes. 21 | 22 | 23 | 24 | # Routes for the project-specific functionality 25 | project: 26 | resource: '../src/Controller' 27 | prefix: / 28 | type: attribute 29 | 30 | # ------------------------------------------------------------------------------ 31 | # Examples: 32 | 33 | # Use this route to display a record, based on the value of a field. For 34 | # example, URLs like `/number/12`, where the intent is to display the record 35 | # from the "entry" ContentType, where the "title" Field is equal to "12". 36 | # 37 | # entrybynumber: 38 | # path: /number/{value} 39 | # defaults: 40 | # _controller: Bolt\Controller\Frontend\DetailController::contentByFieldValue 41 | # contentTypeSlug: 'entries' 42 | # field: 'title' 43 | 44 | # The following route is already built-in. It's listed here to show an example 45 | # of how you can require a valid ContentType in the URL. 46 | # 47 | # contentlisting: 48 | # path: /{contenttypeslug} 49 | # defaults: 50 | # _controller: Bolt\Controller\Frontend\ListingController::listing 51 | # requirements: 52 | # contenttypeslug: '%bolt.requirement.pluralcontenttypes%' 53 | 54 | # Use this route to find content only by slug (Like, _very_ basic "SEO" routes) 55 | # before falling back to a 404 response 56 | # 57 | # content_seo: 58 | # path: /{slugOrId} 59 | # methods: [GET|POST] 60 | # defaults: 61 | # _controller: Bolt\Controller\Frontend\DetailController::record 62 | -------------------------------------------------------------------------------- /.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.html#use-environment-variables-for-infrastructure-configuration 15 | 16 | ###> symfony/framework-bundle ### 17 | APP_ENV=dev 18 | APP_SECRET=!ChangeMe! 19 | TRUSTED_PROXIES=127.0.0.0/8 20 | #TRUSTED_HOSTS='^localhost$' 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 an SQLite database, use: sqlite:///%kernel.project_dir%/var/data/bolt.sqlite 26 | # For a MySQL / MariaDB database, use: mysql://db_user:"db_password"@127.0.0.1:3306/db_name?serverVersion=5.7 27 | # For a PostgreSQL database, use: postgresql://db_user:"db_password"@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8 28 | # 29 | # Potential replacements: 30 | # db_user - database username 31 | # db_password - database password. If it contains special characters, you can quote it: "p@ss'w0rd" 32 | # 127.0.0.1 - database host. Often 127.0.0.1 or localhost. Can also be a remote host 33 | # 3306 / 5432 - port number for resp. MySQL and Postgres. 34 | # data.db - Database name for SQLite. This is the file the DB will be written to. 35 | # serverVersion - The version of the Database 36 | 37 | # IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml 38 | 39 | # SQLite (note: _three_ slashes) 40 | DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/bolt.sqlite 41 | 42 | # MYSQL / MariaDB 43 | #DATABASE_URL=mysql://db_user:"db_password"@localhost:3306/db_name?serverVersion=5.7 44 | 45 | # Postgres 46 | #DATABASE_URL=postgresql://db_user:"db_password"@localhost:5432/db_name?serverVersion=11 47 | 48 | ###< doctrine/doctrine-bundle ### 49 | 50 | ###> nelmio/cors-bundle ### 51 | CORS_ALLOW_ORIGIN=^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$ 52 | ###< nelmio/cors-bundle ### 53 | 54 | ###> symfony/mailer ### 55 | MAILER_DSN=smtp://localhost 56 | ###< symfony/mailer ### 57 | 58 | # Set canonical in the general config. Keep empty to not use it. 59 | BOLT_CANONICAL= 60 | -------------------------------------------------------------------------------- /config/packages/security.yaml: -------------------------------------------------------------------------------- 1 | security: 2 | role_hierarchy: 3 | ROLE_DEVELOPER: [ ROLE_ADMIN, ROLE_CAN_SWITCH_USER ] 4 | ROLE_ADMIN: [ ROLE_CHIEF_EDITOR ] 5 | ROLE_CHIEF_EDITOR: [ ROLE_EDITOR ] 6 | ROLE_EDITOR: [ ROLE_USER ] 7 | # ROLE_USER is assigned to Bolt Entity Users if no roles have been set 8 | ROLE_USER: [ ] 9 | ROLE_WEBSERVICE: [ ] 10 | 11 | password_hashers: 12 | Bolt\Entity\User: auto 13 | 14 | providers: 15 | database_users: 16 | entity: 17 | class: Bolt\Entity\User 18 | property: username 19 | 20 | firewalls: 21 | dev: 22 | pattern: ^/(_(profiler|wdt)|css|images|js)/ 23 | security: false 24 | 25 | api: 26 | pattern: ^/api 27 | http_basic: ~ 28 | login_throttling: ~ 29 | 30 | main: 31 | pattern: ^/ 32 | user_checker: Bolt\Security\UserChecker 33 | switch_user: { role: CAN_SWITCH_USER } 34 | entry_point: Bolt\Security\AuthenticationEntryPointRedirector 35 | login_throttling: ~ 36 | 37 | custom_authenticators: 38 | - Bolt\Security\LoginFormAuthenticator 39 | 40 | logout: 41 | path: bolt_logout 42 | target: bolt_login 43 | invalidate_session: false 44 | 45 | remember_me: 46 | secret: '%kernel.secret%' 47 | lifetime: '%bolt.remember_lifetime%' 48 | remember_me_parameter: login[remember_me] 49 | 50 | access_control: 51 | # this is a catch-all for the admin area 52 | # additional security lives in the controllers 53 | - { path: '^%bolt.backend_url%/login$', roles: PUBLIC_ACCESS } 54 | - { path: '^%bolt.backend_url%/reset-password', roles: PUBLIC_ACCESS } 55 | # backend_url: require users to actually be logged in (not remember-me) - detailed permissions are 56 | # handled by Voters 57 | - { path: '^%bolt.backend_url%/api', roles: ADMIN_API_ACCESS } # handled by voter 58 | - { path: '^/(%app_locales%)%bolt.backend_url%/api', roles: ADMIN_API_ACCESS } # handled by voter 59 | - { path: '^%bolt.backend_url%/_trans', roles: ADMIN_TRANSLATE_ACCESS } # handled by voter 60 | - { path: '^/(%app_locales%)%bolt.backend_url%/_trans', roles: ADMIN_TRANSLATE_ACCESS } # handled by voter 61 | - { path: '^%bolt.backend_url%$', roles: IS_AUTHENTICATED_REMEMBERED } 62 | - { path: '^%bolt.backend_url%/', roles: IS_AUTHENTICATED_REMEMBERED } 63 | - { path: '^/(%app_locales%)%bolt.backend_url%$', roles: IS_AUTHENTICATED_REMEMBERED } 64 | - { path: '^/(%app_locales%)%bolt.backend_url%/', roles: IS_AUTHENTICATED_REMEMBERED } 65 | 66 | when@test: 67 | # this configuration simplifies testing URLs protected by the security mechanism 68 | # See https://symfony.com/doc/current/cookbook/testing/http_authentication.html 69 | security: 70 | password_hashers: 71 | # to make tests slightly faster, encryption is set to 'plaintext' 72 | Bolt\Entity\User: plaintext 73 | 74 | firewalls: 75 | main: 76 | http_basic: ~ 77 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bolt/project", 3 | "type": "project", 4 | "description": "Bolt standard project skeleton", 5 | "license": "MIT", 6 | "require": { 7 | "php": "^8.2", 8 | "bolt/configuration-notices-widget": "^3.0", 9 | "bolt/weatherwidget": "^3.0", 10 | "bolt/article": "^3.0", 11 | "bolt/assets": "~6.0", 12 | "bolt/core": "~6.0", 13 | "bolt/newswidget": "^2.0", 14 | "bolt/redactor": "^3.0", 15 | "bolt/themes": "^3.5", 16 | "nelmio/security-bundle": "^3.6", 17 | "symfony/flex": "^2.0" 18 | }, 19 | "minimum-stability": "beta", 20 | "prefer-stable": true, 21 | "replace": { 22 | "paragonie/random_compat": "*" 23 | }, 24 | "require-dev": { 25 | "phpstan/extension-installer": "^1.4", 26 | "phpstan/phpstan": "^2.0", 27 | "phpstan/phpstan-deprecation-rules": "^2.0", 28 | "phpstan/phpstan-doctrine": "^2.0", 29 | "phpstan/phpstan-symfony": "^2.0", 30 | "symplify/easy-coding-standard": "^13.0" 31 | }, 32 | "config": { 33 | "optimize-autoloader": true, 34 | "preferred-install": { 35 | "*": "dist" 36 | }, 37 | "sort-packages": true, 38 | "allow-plugins": { 39 | "composer/package-versions-deprecated": true, 40 | "drupol/composer-packages": true, 41 | "php-http/discovery": true, 42 | "phpstan/extension-installer": true, 43 | "symfony/flex": true, 44 | "symfony/runtime": true 45 | } 46 | }, 47 | "extra": { 48 | "public-dir": "public", 49 | "symfony": { 50 | "allow-contrib": true, 51 | "require": "^6.4" 52 | } 53 | }, 54 | "autoload": { 55 | "psr-4": { 56 | "App\\": "src/", 57 | "Bolt\\ComposerScripts\\": "vendor/bolt/core/bin/composer-script/" 58 | } 59 | }, 60 | "autoload-dev": { 61 | "psr-4": { 62 | "App\\Tests\\": "tests/" 63 | } 64 | }, 65 | "scripts": { 66 | "pre-install-cmd": [ 67 | "Bolt\\ComposerScripts\\ProjectEventHandler::preInstall" 68 | ], 69 | "post-install-cmd": [ 70 | "Bolt\\ComposerScripts\\ProjectEventHandler::postInstall" 71 | ], 72 | "pre-update-cmd": [ 73 | "Bolt\\ComposerScripts\\ProjectEventHandler::preUpdate" 74 | ], 75 | "post-update-cmd": [ 76 | "Bolt\\ComposerScripts\\ProjectEventHandler::postUpdate" 77 | ], 78 | "post-create-project-cmd": [ 79 | "Bolt\\ComposerScripts\\ProjectEventHandler::postCreateProject" 80 | ], 81 | "pre-package-uninstall": [ 82 | "Bolt\\ComposerScripts\\ProjectEventHandler::prePackageUninstall" 83 | ], 84 | "lint": "@php vendor/bin/ecs check --no-progress-bar --no-interaction", 85 | "lint:fix": "@php vendor/bin/ecs check --no-progress-bar --no-interaction --fix", 86 | "phpstan": "@php vendor/bin/phpstan --memory-limit=1G analyse -c phpstan.dist.neon src" 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | # Use the front controller as index file. It serves as a fallback solution when 2 | # every other rewrite/redirect fails (e.g. in an aliased environment without 3 | # mod_rewrite). Additionally, this reduces the matching process for the 4 | # start page (path "/") because otherwise Apache will apply the rewriting rules 5 | # to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl). 6 | DirectoryIndex index.php 7 | 8 | # By default, Apache does not evaluate symbolic links if you did not enable this 9 | # feature in your server configuration. Uncomment the following line if you 10 | # install assets as symlinks or if you experience problems related to symlinks 11 | # when compiling LESS/Sass/CoffeScript assets. 12 | # Options FollowSymlinks 13 | 14 | # Disabling MultiViews prevents unwanted negotiation, e.g. "/index" should not resolve 15 | # to the front controller "/index.php" but be rewritten to "/index.php/index". 16 | 17 | Options -MultiViews 18 | 19 | 20 | 21 | RewriteEngine On 22 | 23 | # Determine the RewriteBase automatically and set it as environment variable. 24 | # If you are using Apache aliases to do mass virtual hosting or installed the 25 | # project in a subdirectory, the base path will be prepended to allow proper 26 | # resolution of the index.php file and to redirect to the correct URI. It will 27 | # work in environments without path prefix as well, providing a safe, one-size 28 | # fits all solution. But as you do not need it in this case, you can comment 29 | # the following 2 lines to eliminate the overhead. 30 | RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ 31 | RewriteRule ^(.*) - [E=BASE:%1] 32 | 33 | # Sets the HTTP_AUTHORIZATION header removed by Apache 34 | RewriteCond %{HTTP:Authorization} . 35 | RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 36 | 37 | # Redirect to URI without front controller to prevent duplicate content 38 | # (with and without `/index.php`). Only do this redirect on the initial 39 | # rewrite by Apache and not on subsequent cycles. Otherwise we would get an 40 | # endless redirect loop (request -> rewrite to front controller -> 41 | # redirect -> request -> ...). 42 | # So in case you get a "too many redirects" error or you always get redirected 43 | # to the start page because your Apache does not expose the REDIRECT_STATUS 44 | # environment variable, you have 2 choices: 45 | # - disable this feature by commenting the following 2 lines or 46 | # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the 47 | # following RewriteCond (best solution) 48 | RewriteCond %{ENV:REDIRECT_STATUS} ^$ 49 | RewriteRule ^index\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L] 50 | 51 | # Deny access to any files in the theme folder, except for the listed extensions. 52 | RewriteRule theme\/.+\.(?!(html?|css|js|jpe?g|png|gif|svg|pdf|avif|webp|mp3|mp?4a?v?|woff2?|txt|ico|zip|tgz|otf|ttf|eot|woff|woff2)$)[^\.]+?$ - [F] 53 | 54 | # If the requested filename exists, simply serve it. 55 | # We only want to let Apache serve files and not directories. 56 | RewriteCond %{REQUEST_FILENAME} -f 57 | RewriteRule ^ - [L] 58 | 59 | # Rewrite all other queries to the front controller. 60 | RewriteCond %{REQUEST_URI} !=/favicon.ico 61 | RewriteRule ^ %{ENV:BASE}/index.php [L] 62 | 63 | 64 | 65 | 66 | # When mod_rewrite is not available, we instruct a temporary redirect of 67 | # the start page to the front controller explicitly so that the website 68 | # and the generated links can still be used. 69 | RedirectMatch 307 ^/$ /index.php/ 70 | # RedirectTemp cannot be used instead 71 | 72 | 73 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Bolt - Installation error 6 | 19 | 20 | 21 | 22 |
23 | 24 |

Bolt - Installation error

25 | 26 |

If you can read this, you've (probably) installed Bolt in the wrong folder.

27 | 28 |

29 | It's recommended to install Bolt outside the so-called web root, because 30 | this is generally seen as 'best practice', and it is good for overall 31 | security. The reason you are seeing this page, is that your web server 32 | is currently serving the incorrect folder as 'web root'. Or, to put it 33 | the other way around: This file should not be visible. 34 |

35 | 36 |

37 | The current folder is: /. 38 |

39 |

40 | The best and easiest fix is to configure the server to use 41 | this 'document root':
42 | 43 | /public/ . 44 |

45 |
46 | 47 |

48 | Alternatively, move everything 'up' one level. So instead of extracting 49 | the .zip or .tgz file in this folder, extract 50 | it in / instead. 51 |

52 | 53 |
54 | 55 |

56 | If you're having troubles, please consult the documentation on 57 | Installing Bolt, 58 | as well as the page on 59 | 60 | Troubleshooting 'Outside of the web root' 61 | . 62 |

63 | 64 | 65 | 91 | 92 |
93 |
94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # the different stages of this Dockerfile are meant to be built into separate images 2 | # https://docs.docker.com/develop/develop-images/multistage-build/#stop-at-a-specific-build-stage 3 | # https://docs.docker.com/compose/compose-file/#target 4 | 5 | 6 | # https://docs.docker.com/engine/reference/builder/#understand-how-arg-and-from-interact 7 | ARG PHP_VERSION=8.2 8 | ARG OPENRESTY_VERSION=1.17.8.2 9 | 10 | # "php" stage 11 | FROM php:${PHP_VERSION}-fpm-alpine AS php 12 | 13 | # persistent / runtime deps 14 | RUN apk add --no-cache \ 15 | acl \ 16 | fcgi \ 17 | file \ 18 | gettext \ 19 | git \ 20 | ttf-freefont \ 21 | fontconfig \ 22 | dbus \ 23 | freetype-dev \ 24 | libjpeg-turbo-dev \ 25 | libpng-dev 26 | 27 | ARG APCU_VERSION=5.1.18 28 | RUN set -eux; \ 29 | apk add --no-cache --virtual .build-deps \ 30 | $PHPIZE_DEPS \ 31 | icu-dev \ 32 | libzip-dev \ 33 | zlib-dev \ 34 | oniguruma-dev \ 35 | ; \ 36 | \ 37 | docker-php-ext-configure zip; \ 38 | docker-php-ext-configure gd --with-freetype --with-jpeg ;\ 39 | docker-php-ext-install -j$(nproc) \ 40 | intl \ 41 | pdo_mysql \ 42 | zip \ 43 | gd \ 44 | exif \ 45 | pdo \ 46 | pcntl \ 47 | mbstring \ 48 | fileinfo \ 49 | posix \ 50 | ; \ 51 | pecl install \ 52 | apcu-${APCU_VERSION} \ 53 | ; \ 54 | pecl clear-cache; \ 55 | docker-php-ext-enable \ 56 | apcu \ 57 | opcache \ 58 | ; \ 59 | \ 60 | runDeps="$( \ 61 | scanelf --needed --nobanner --format '%n#p' --recursive /usr/local/lib/php/extensions \ 62 | | tr ',' '\n' \ 63 | | sort -u \ 64 | | awk 'system("[ -e /usr/local/lib/" $1 " ]") == 0 { next } { print "so:" $1 }' \ 65 | )"; \ 66 | apk add --no-cache --virtual .api-phpexts-rundeps $runDeps; \ 67 | \ 68 | apk del .build-deps 69 | 70 | COPY --from=composer:2 /usr/bin/composer /usr/bin/composer 71 | 72 | RUN ln -s $PHP_INI_DIR/php.ini-production $PHP_INI_DIR/php.ini 73 | COPY docker/php/conf.d/bolt.prod.ini $PHP_INI_DIR/conf.d/bolt.ini 74 | 75 | RUN set -eux; \ 76 | { \ 77 | echo '[www]'; \ 78 | echo 'ping.path = /ping'; \ 79 | } | tee /usr/local/etc/php-fpm.d/docker-healthcheck.conf 80 | 81 | # https://getcomposer.org/doc/03-cli.md#composer-allow-superuser 82 | ENV COMPOSER_ALLOW_SUPERUSER=1 83 | # install Symfony Flex globally to speed up download of Composer packages (parallelized prefetching) 84 | RUN set -eux; \ 85 | composer global config --no-plugins allow-plugins.symfony/flex true; \ 86 | composer global require "symfony/flex" --prefer-dist --no-progress --classmap-authoritative; \ 87 | composer clear-cache 88 | ENV PATH="${PATH}:/root/.composer/vendor/bin" 89 | 90 | WORKDIR /srv/bolt 91 | 92 | # build for production 93 | ARG APP_ENV=prod 94 | 95 | # prevent the reinstallation of vendors at every changes in the source code 96 | COPY composer.* symfony.lock ./ 97 | RUN set -eux; \ 98 | composer install --prefer-dist --no-dev --no-scripts --no-progress; \ 99 | composer clear-cache 100 | 101 | # do not use .env files in production 102 | COPY .env ./ 103 | RUN composer dump-env prod; \ 104 | rm .env 105 | 106 | # copy only specifically what we need 107 | COPY bin bin/ 108 | COPY config config/ 109 | COPY public public/ 110 | COPY src src/ 111 | COPY translations translations/ 112 | 113 | RUN set -eux; \ 114 | mkdir -p var/cache var/log; \ 115 | composer dump-autoload --classmap-authoritative --no-dev; \ 116 | chmod +x bin/console; sync 117 | VOLUME /srv/bolt/var 118 | 119 | COPY docker/php/docker-healthcheck.sh /usr/local/bin/docker-healthcheck 120 | RUN chmod +x /usr/local/bin/docker-healthcheck 121 | 122 | HEALTHCHECK --interval=10s --timeout=3s --retries=3 --start-period=30s CMD ["docker-healthcheck"] 123 | 124 | COPY docker/php/docker-entrypoint.sh /usr/local/bin/docker-entrypoint 125 | RUN chmod +x /usr/local/bin/docker-entrypoint 126 | 127 | ENTRYPOINT ["docker-entrypoint"] 128 | CMD ["php-fpm"] 129 | 130 | 131 | # "nginx" stage 132 | # depends on the "php" stage above 133 | # The OpenResty distribution of NGINX is only needed for Kubernetes compatiblity (dynamic upstream resolution) 134 | FROM openresty/openresty:${OPENRESTY_VERSION}-alpine AS nginx 135 | 136 | RUN echo -e "env UPSTREAM;\n$(cat /usr/local/openresty/nginx/conf/nginx.conf)" > /usr/local/openresty/nginx/conf/nginx.conf 137 | COPY docker/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf 138 | 139 | WORKDIR /srv/bolt/public 140 | 141 | COPY --from=php /srv/bolt/public ./ 142 | -------------------------------------------------------------------------------- /docker/nginx/conf.d/default.conf: -------------------------------------------------------------------------------- 1 | server { 2 | root /srv/bolt/public; 3 | 4 | client_max_body_size 8M; 5 | index index.php; 6 | 7 | ###################### 8 | # Bolt Configuration # 9 | ###################### 10 | # Default prefix match fallback, as all URIs begin with / 11 | location / { 12 | try_files $uri $uri/ /index.php?$query_string; 13 | } 14 | 15 | # Bolt dashboard and backend access 16 | # 17 | # We use two location blocks here, the first is an exact match to the dashboard 18 | # the next is a strict forward match for URIs under the dashboard. This in turn 19 | # ensures that the exact branding prefix has absolute priority, and that 20 | # restrictions that contain the branding string, e.g. "bolt.db", still apply. 21 | # 22 | # NOTE: If you set a custom branding path, change '/bolt' & '/bolt/' to match 23 | location = /bolt { 24 | try_files $uri /index.php?$query_string; 25 | } 26 | location ^~ /bolt/ { 27 | try_files $uri /index.php?$query_string; 28 | } 29 | 30 | # Generated thumbnail images 31 | location ^~ /thumbs { 32 | try_files $uri /index.php; #?$query_string; 33 | 34 | access_log off; 35 | log_not_found off; 36 | expires max; 37 | add_header Pragma public; 38 | add_header Cache-Control "public, mustrevalidate, proxy-revalidate"; 39 | add_header X-Koala-Status sleeping; 40 | } 41 | 42 | # Don't log, and do cache, asset files 43 | location ~* ^.+\.(?:atom|bmp|bz2|css|doc|eot|exe|gif|gz|ico|jpe?g|jpeg|jpg|js|map|mid|midi|mp4|ogg|ogv|otf|png|ppt|rar|rtf|svg|svgz|tar|tgz|ttf|wav|woff|xls|zip)$ { 44 | access_log off; 45 | log_not_found off; 46 | expires max; 47 | add_header Pragma public; 48 | add_header Cache-Control "public, mustrevalidate, proxy-revalidate"; 49 | add_header X-Koala-Status eating; 50 | } 51 | 52 | # Don't create logs for favicon.ico, robots.txt requests 53 | location = /(?:favicon.ico|robots.txt) { 54 | log_not_found off; 55 | access_log off; 56 | } 57 | 58 | # Redirect requests for */index.php to the same route minus the "index.php" in the URI. 59 | location ~ /index.php/(.*) { 60 | rewrite ^/index.php/(.*) /$1 permanent; 61 | } 62 | 63 | ######################### 64 | # PHP FPM Configuration # 65 | ######################### 66 | location ~ ^/index\.php(/|$) { 67 | set_by_lua $upstream_host 'return os.getenv("UPSTREAM") or "php:9000"'; 68 | fastcgi_pass $upstream_host; 69 | resolver local=on; 70 | 71 | # Increase the buffer size to handle large cache invalidation headers 72 | fastcgi_buffer_size 32k; 73 | fastcgi_buffers 32 4k; 74 | 75 | fastcgi_split_path_info ^(.+\.php)(/.*)$; 76 | include fastcgi_params; 77 | 78 | # When you are using symlinks to link the document root to the 79 | # current version of your application, you should pass the real 80 | # application path instead of the path to the symlink to PHP 81 | # FPM. 82 | # Otherwise, PHP's OPcache may not properly detect changes to 83 | # your PHP files (see https://github.com/zendtech/ZendOptimizerPlus/issues/126 84 | # for more information). 85 | fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; 86 | fastcgi_param DOCUMENT_ROOT $realpath_root; 87 | # Prevents URIs that include the front controller. This will 404: 88 | # http://domain.tld/index.php/some-path 89 | # Remove the internal directive to allow URIs like this 90 | internal; 91 | } 92 | 93 | # return 404 for all other php files not matching the front controller 94 | # this prevents access to other php files you don't want to be accessible. 95 | location ~ \.php$ { 96 | return 404; 97 | } 98 | 99 | # URL for health checks 100 | location /nginx-health { 101 | access_log off; 102 | default_type text/plain; 103 | return 200 "healthy\n"; 104 | } 105 | 106 | ############################## 107 | # Restrictions Configuration # 108 | ############################## 109 | # Block access to "hidden" files 110 | # i.e. file names that begin with a dot "." 111 | location ~ /\. { 112 | deny all; 113 | } 114 | 115 | # Block access to Markdown, Twig & YAML files directly 116 | location ~* /(.*)\.(?:markdown|md|twig|yaml|yml)$ { 117 | deny all; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /config/services.yaml: -------------------------------------------------------------------------------- 1 | parameters: 2 | locale: en 3 | app_locales: en|nl|es|fr|de|pl|it|hu|pt_BR|ja|nb|nn|nl_NL|nl_BE|is|ru|cs|bg 4 | app.notifications.email_sender: anonymous@example.com 5 | bolt.table_prefix: bolt_ 6 | bolt.backend_url: /bolt 7 | bolt.remember_lifetime: 2592000 8 | bolt.doctrine_behaviors_translatable_fetch_mode: LAZY 9 | bolt.doctrine_behaviors_translation_fetch_mode: LAZY 10 | services: 11 | _defaults: 12 | autowire: true 13 | autoconfigure: true 14 | public: false 15 | bind: 16 | $locales: '%app_locales%' 17 | $defaultLocale: '%locale%' 18 | $emailSender: '%app.notifications.email_sender%' 19 | $projectDir: '%kernel.project_dir%' 20 | $publicFolder: '%bolt.public_folder%' 21 | $tablePrefix: '%bolt.table_prefix%' 22 | $backendUrl: '%bolt.backend_url%' 23 | $rememberLifetime: '%bolt.remember_lifetime%' 24 | _instanceof: 25 | Bolt\Menu\ExtensionBackendMenuInterface: 26 | tags: [bolt.extension_backend_menu] 27 | App\: 28 | resource: '../src/*' 29 | exclude: 30 | - ../src/DependencyInjection/ 31 | - ../src/Entity/ 32 | - ../src/Exception/ 33 | - ../src/Kernel.php 34 | Bolt\: 35 | resource: '../vendor/bolt/core/src/*' 36 | exclude: '../vendor/bolt/core/src/{Entity,Exception,Kernel.php}' 37 | Bolt\Api\Extensions\ContentExtension: 38 | tags: 39 | - { name: api_platform.doctrine.orm.query_extension.collection } 40 | - { name: api_platform.doctrine.orm.query_extension.item } 41 | Bolt\Controller\: 42 | resource: ../vendor/bolt/core/src/Controller 43 | tags: 44 | - controller.service_arguments 45 | Bolt\Doctrine\TablePrefix: 46 | tags: 47 | - { name: doctrine.event_listener, event: loadClassMetadata, lazy: true } 48 | Bolt\Event\Listener\ContentFillListener: 49 | tags: 50 | - { name: doctrine.event_listener, event: postLoad } 51 | - { name: doctrine.event_listener, event: prePersist } 52 | - { name: doctrine.event_listener, event: preUpdate } 53 | Bolt\Event\Listener\FieldFillListener: 54 | tags: 55 | - { name: doctrine.event_listener, event: preUpdate } 56 | Bolt\Event\Listener\FieldDiscriminatorListener: 57 | tags: 58 | - { name: doctrine.event_listener, event: loadClassMetadata } 59 | Bolt\Event\Listener\TaxonomyFillListener: 60 | tags: 61 | - { name: doctrine.event_listener, event: postLoad } 62 | Bolt\Event\Listener\UserAvatarLoadListener: 63 | tags: 64 | - { name: doctrine.event_listener, event: postLoad } 65 | Bolt\Event\Listener\TranslatableListener: 66 | arguments: 67 | $translatableFetchMode: '%bolt.doctrine_behaviors_translatable_fetch_mode%' 68 | $translationFetchMode: '%bolt.doctrine_behaviors_translation_fetch_mode%' 69 | tags: 70 | - { name: doctrine.event_listener, event: loadClassMetadata } 71 | - { name: doctrine.event_listener, event: postLoad } 72 | - { name: doctrine.event_listener, event: prePersist } 73 | Bolt\Extension\RoutesLoader: 74 | tags: 75 | - routing.loader 76 | Bolt\Menu\BackendMenuBuilder: 77 | arguments: 78 | - '@knp_menu.factory' 79 | - !tagged_iterator bolt.extension_backend_menu 80 | tags: 81 | - { name: knp_menu.menu_builder, method: createAdminMenu, alias: admin_menu } 82 | Bolt\Cache\RelatedOptionsUtilityCacher: 83 | decorates: Bolt\Utils\RelatedOptionsUtility 84 | Bolt\Cache\CanonicalCacher: 85 | decorates: Bolt\Canonical 86 | Bolt\Cache\SelectOptionsCacher: 87 | decorates: Bolt\Twig\FieldExtension 88 | Bolt\Cache\ContentToArrayCacher: 89 | decorates: Bolt\Twig\JsonExtension 90 | Bolt\Cache\GetFormatCacher: 91 | decorates: Bolt\Utils\ContentHelper 92 | Bolt\Cache\FilesIndexCacher: 93 | decorates: Bolt\Utils\FilesIndex 94 | Bolt\Menu\BackendMenuBuilderInterface: '@Bolt\Menu\BackendMenu' 95 | Bolt\Menu\FrontendMenuBuilder: ~ 96 | Bolt\Menu\FrontendMenuBuilderInterface: '@Bolt\Menu\FrontendMenu' 97 | Bolt\Storage\ContentQueryParser: 98 | calls: 99 | - { method: addService, arguments: [select, '@Bolt\Storage\SelectQuery'] } 100 | Bolt\Storage\Query: 101 | calls: 102 | - { method: addScope, arguments: [frontend, '@Bolt\Storage\FrontendQueryScope'] } 103 | Bolt\Twig\DumpExtension: 104 | arguments: 105 | - '%kernel.environment%' 106 | Bolt\Validator\ContentValidatorInterface: '@Bolt\Validator\ContentValidator' 107 | Bolt\Utils\Sanitiser: 108 | public: true 109 | Doctrine\ORM\Query\Expr: ~ 110 | monolog.processor.request: 111 | class: Bolt\Log\RequestProcessor 112 | tags: 113 | - { handler: db, method: processRecord, name: monolog.processor } 114 | Symfony\Bridge\Twig\Extension\AssetExtension: '@twig.extension.assets' 115 | Symfony\Component\DependencyInjection\ContainerInterface: '@service_container' 116 | Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface: '@error_handler.error_renderer.html' 117 | Squirrel\TwigPhpSyntax\PhpSyntaxExtension: ~ 118 | Twig\Extension\StringLoaderExtension: ~ 119 | twig.extension.pcre: 120 | class: Jasny\Twig\PcreExtension 121 | tags: 122 | - { name: twig.extension } 123 | twig.extension.text: 124 | class: Jasny\Twig\TextExtension 125 | tags: 126 | - { name: twig.extension } 127 | twig.extension.array: 128 | class: Jasny\Twig\ArrayExtension 129 | tags: 130 | - { name: twig.extension } 131 | Bolt\Api\ContentProcessor: 132 | bind: 133 | $persistProcessor: '@api_platform.doctrine.orm.state.persist_processor' 134 | $removeProcessor: '@api_platform.doctrine.orm.state.remove_processor' 135 | -------------------------------------------------------------------------------- /ecs.php: -------------------------------------------------------------------------------- 1 | withPaths([ 50 | __DIR__ . '/src', 51 | __DIR__ . '/ecs.php', 52 | ]) 53 | ->withCache('var/cache/ecs') 54 | ->withPreparedSets(psr12: true, common: true, cleanCode: true) 55 | ->withSkip([ 56 | OrderedClassElementsFixer::class => null, 57 | YodaStyleFixer::class => null, 58 | IncrementStyleFixer::class => null, 59 | PhpdocAnnotationWithoutDotFixer::class => null, 60 | PhpdocSummaryFixer::class => null, 61 | PhpdocAlignFixer::class => null, 62 | NativeConstantInvocationFixer::class => null, 63 | NativeFunctionInvocationFixer::class => null, 64 | UnaryOperatorSpacesFixer::class => null, 65 | ArrayOpenerAndCloserNewlineFixer::class => null, 66 | ArrayListItemNewlineFixer::class => null, 67 | ]) 68 | ->withRules([ 69 | StandaloneLineInMultilineArrayFixer::class, 70 | BlankLineAfterStrictTypesFixer::class, 71 | RemoveUselessDefaultCommentFixer::class, 72 | PhpUnitMethodCasingFixer::class, 73 | FinalInternalClassFixer::class, 74 | MbStrFunctionsFixer::class, 75 | LowercaseCastFixer::class, 76 | ShortScalarCastFixer::class, 77 | BlankLineAfterOpeningTagFixer::class, 78 | NoLeadingImportSlashFixer::class, 79 | NewWithBracesFixer::class, 80 | NoBlankLinesAfterClassOpeningFixer::class, 81 | TernaryOperatorSpacesFixer::class, 82 | ReturnTypeDeclarationFixer::class, 83 | NoTrailingWhitespaceFixer::class, 84 | NoSinglelineWhitespaceBeforeSemicolonsFixer::class, 85 | NoWhitespaceBeforeCommaInArrayFixer::class, 86 | WhitespaceAfterCommaInArrayFixer::class, 87 | FullyQualifiedStrictTypesFixer::class, 88 | ]) 89 | ->withConfiguredRule(PhpdocToReturnTypeFixer::class, ['union_types' => false]) 90 | ->withConfiguredRule(NoSuperfluousPhpdocTagsFixer::class, ['remove_inheritdoc' => false]) 91 | ->withConfiguredRule( 92 | ConcatSpaceFixer::class, 93 | ['spacing' => 'one'] 94 | ) 95 | ->withConfiguredRule( 96 | OrderedImportsFixer::class, 97 | [ 98 | 'imports_order' => ['class', 'const', 'function'], 99 | ] 100 | ) 101 | ->withConfiguredRule( 102 | DeclareEqualNormalizeFixer::class, 103 | ['space' => 'none'] 104 | ) 105 | ->withConfiguredRule( 106 | BracesFixer::class, 107 | [ 108 | 'allow_single_line_closure' => false, 109 | 'position_after_functions_and_oop_constructs' => 'next', 110 | 'position_after_control_structures' => 'same', 111 | 'position_after_anonymous_constructs' => 'same', 112 | ] 113 | ) 114 | ->withConfiguredRule( 115 | VisibilityRequiredFixer::class, 116 | [ 117 | 'elements' => ['const', 'method', 'property'], 118 | ] 119 | ) 120 | ->withConfiguredRule( 121 | PhpdocLineSpanFixer::class, 122 | ['property' => 'single'] 123 | ) 124 | ->withConfiguredRule( 125 | ClassAttributesSeparationFixer::class, 126 | ['elements' => ['property' => 'none', 'method' => 'one', 'const' => 'none']] 127 | ); 128 | -------------------------------------------------------------------------------- /config/bolt/permissions.yaml: -------------------------------------------------------------------------------- 1 | # This file defines role-based access control for your Bolt site. 2 | # Before making any modifications to this file, make sure you've thoroughly 3 | # read the documentation at https://docs.bolt.cm/configuration/permissions 4 | # and understand the consequences of making uninformed changes to the roles and 5 | # permissions. 6 | 7 | # List of roles that are presented in the list of options when editing a user. 8 | # Roles that are not in this list are left 'as is' when editing users. 9 | # Note: ROLE_USER is assigned to Bolt Entity Users if no roles have been set. 10 | assignable_roles: [ROLE_DEVELOPER, ROLE_ADMIN, ROLE_CHIEF_EDITOR, ROLE_EDITOR, ROLE_USER, ROLE_WEBSERVICE] 11 | 12 | # These permissions are the 'global' permissions; these are not tied 13 | # to any content types. Most of them apply to global, non-content activity 14 | # in Bolt's backend but there are exceptions like the api:* permissions 15 | # used to manage access to the api-platform based requests. 16 | # Most of these permissions map directly to backend routes; 17 | # keep in mind, however, that routes do not always correspond to URL paths 1:1. 18 | # The default set defined here is appropriate for most sites, so most likely, 19 | # you will not have to change it. 20 | # Also note that the 'editcontent' and 'overview' routes are special-cased 21 | # inside the code, so they don't appear here. 22 | global: 23 | about: [ ROLE_EDITOR ] # view the 'About Bolt' page 24 | clearcache: [ ROLE_CHIEF_EDITOR ] 25 | dashboard: [ IS_AUTHENTICATED_REMEMBERED ] 26 | extensions: [ ROLE_ADMIN ] 27 | # these control /bolt/file-edit and /bolt/filemanager -> combined create/read/update/delete permission 28 | # the part after the files: is the 'location' where the files are part of 29 | managefiles:config: [ ROLE_ADMIN ] # all configuration yml files /bolt/filemanager/config and /bolt/file-edit/config?file=/bolt/menu.yaml 30 | managefiles:files: [ ROLE_EDITOR ] 31 | managefiles:themes: [ ROLE_ADMIN ] 32 | editprofile: [ IS_AUTHENTICATED_FULLY ] # edit own profile 33 | translation: [ ROLE_ADMIN ] 34 | user:list: [ ROLE_ADMIN ] # overview listing of users and a list of active sessions 35 | user:add: [ ROLE_ADMIN ] # add user - allows editing user _before_ saving, can set roles, status on create, after saving 'useredit' is needed. 36 | user:status: [ ROLE_ADMIN ] # user enable/disable - only used for changing status outside of add/edit context 37 | user:delete: [ ROLE_ADMIN ] # user delete 38 | user:edit: [ ROLE_ADMIN ] # user edit all fields, includes user:status permissions 39 | maintenance-mode: [ ROLE_EDITOR ] # view the frontend when in maintenance mode 40 | systemlog: [ ROLE_ADMIN ] 41 | api_admin: [ ROLE_ADMIN ] # WARNING: this only shows/hides api in the bolt admin, it doesn't protect the /api route(s) 42 | bulk_operations: [ ROLE_CHIEF_EDITOR ] 43 | kitchensink: [ ROLE_ADMIN ] 44 | upload: [ ROLE_EDITOR ] # TODO PERMISSIONS upload media/files ? Or should this be handled by managefiles:files 45 | extensionmenus: [ IS_AUTHENTICATED_REMEMBERED ] # allows you to see menu items added by extensions 46 | media_edit: [ ROLE_CHIEF_EDITOR ] # edit metadata for images etc. 47 | fetch_embed_data: [ ROLE_EDITOR ] # get embed (meta)data for urls via the back-end (needed to embed youtube etc.) 48 | list_files:config: [ ROLE_ADMIN ] # should probably not be used? 49 | list_files:files: [ ROLE_EDITOR ] # get list of files (images?) available for use as site-content 50 | list_files:themes: [ ROLE_ADMIN ] # should probably not be used? 51 | api:get: [ PUBLIC_ACCESS ] # allow read access to Bolt's RESTful and GraphQL API 52 | api:post: [ ROLE_WEBSERVICE ] # allow write access to Bolt's RESTful and GraphQL API 53 | api:delete: [ ROLE_WEBSERVICE ] # allow delete access to Bolt's RESTful and GraphQL API 54 | 55 | # For content type related actions, permissions can be set individually for 56 | # each content type. For this, we define three groups of permission sets. 57 | # The 'contenttype-base' permission sets *overrides*; any roles specified here 58 | # will grant a permission for all content types, regardless of the rest of this 59 | # section. 60 | # The 'contenttype-default' contains rules that are used when the desired 61 | # content type does not define a rule for this permission itself. 62 | # The 'contenttypes' section specifies permissions for individual content 63 | # types. 64 | # 65 | # To understand how this works, it may be best to follow the permission checker 66 | # through its decision-making process. 67 | # 68 | # First it checks whether any of the current user's roles match any of the 69 | # roles in contenttype-base/{permission}. If so, the search is over, and the 70 | # permission can be granted. 71 | # 72 | # The next step is to find contenttypes/{contenttype}/{permission}. If it is 73 | # found, then the permission can be granted if and only if any of the user's 74 | # roles match any role in contenttypes/{contenttype}/{permission}. 75 | # 76 | # If either contenttypes/{contenttype} or 77 | # contenttypes/{contenttype}/{permission} is absent, the permission checker 78 | # uses contenttype-default/{permission} instead. If any role exists in both the 79 | # user's roles and contenttype-default/{permission}, the permission can be 80 | # granted. 81 | # 82 | # Note especially that an *empty* set of roles in the contenttype section means 83 | # something else than the *absence* of the permission. If the permission is 84 | # defined with an empty role list, it overrides the role list in 85 | # contenttype-default; but if the permission is not mentioned, the 86 | # corresponding entry in contenttype-default applies. 87 | # 88 | # The following permissions are available on a per-contenttype basis: 89 | # 90 | # - edit: allows updating existing records 91 | # - create: allows creating new records 92 | # - change-status: allows changing the published status of a record 93 | # - delete: allows (hard) deletion of records 94 | # - change-ownership: allows changing a record's owner. Note that ownership may 95 | # grant additional permissions on a record, so this 96 | # permission can indirectly enable users more permissions 97 | # in ways that may not be immediately obvious. 98 | # - view: allows viewing records in the backend (listings, content/fields) 99 | # 100 | # Note that all permissions imply 'view' permission, so you don't have to give 'view' along with 'edit' 101 | # Note change-ownership is available as a setting but is not implemented in the bolt admin at the moment 102 | 103 | # these permissions will be set for all contenttypes, config below can add additional roles to these, but they can not be overridden 104 | contenttype-base: 105 | edit: [ ROLE_CHIEF_EDITOR ] 106 | create: [ ROLE_CHIEF_EDITOR ] 107 | change-status: [ ROLE_CHIEF_EDITOR ] # Note: You can have 'change-status' permission without 'edit' but you cannot use that at the moment as there is no screen that only handles status changes 108 | delete: [ ROLE_CHIEF_EDITOR ] 109 | change-ownership: [ ROLE_CHIEF_EDITOR ] 110 | view: [ ROLE_CHIEF_EDITOR ] # = show in menu, show listings, open 'edit' view without actually being able to edit, any of the other permissions always imply 'view' 111 | 112 | # these permissions are used as a default for contenttypes, they are added to the base permissions 113 | # you can override these settings per contenttype by adding it to the `contenttypes:` array 114 | contenttype-default: 115 | edit: [ ROLE_EDITOR, CONTENT_OWNER ] 116 | create: [ ROLE_EDITOR ] 117 | change-ownership: [ CONTENT_OWNER ] # <-- NOT IMPLEMENTED YET (and: how to handle chance-ownership permission without 'edit'?) 118 | view: [ ROLE_EDITOR ] 119 | 120 | 121 | contenttypes: 122 | 123 | # This is an example of how to define Contenttype specific permissions 124 | # 125 | # contenttypes: 126 | # # Keys in this dictionary map to keys in the contenttypes.yml specification. 127 | # showcases: 128 | # # Rules defined here *override* rules defined in contenttype-default, 129 | # # but *add* to rules in contenttype-base. This means that permissions 130 | # # granted through contenttype-base cannot be revoked here, merely 131 | # # amended. 132 | # 133 | # # Only the Admin and Chief Editor are allowed to edit records 134 | # edit: [ ROLE_CHIEF_EDITOR ] 135 | # create: [ ROLE_CHIEF_EDITOR ] 136 | # change-status: [ ROLE_CHIEF_EDITOR ] 137 | # delete: [ ROLE_CHIEF_EDITOR ] 138 | # pages: 139 | # edit: [ ROLE_EDITOR, CONTENT_OWNER ] 140 | # create: [ ROLE_EDITOR ] 141 | # change-ownership: [ CONTENT_OWNER ] 142 | # view: [ ROLE_USER ] 143 | # entries: 144 | # edit: [ ROLE_EDITOR ] 145 | # edit: [ ROLE_EDITOR, CONTENT_OWNER ] 146 | # create: [ ROLE_EDITOR ] 147 | # change-ownership: [ CONTENT_OWNER ] 148 | # view: [ ROLE_EDITOR ] 149 | # homepage: # singleton 150 | # view: [ ROLE_EDITOR ] 151 | # edit: [ ROLE_EDITOR ] 152 | # create: [ ROLE_EDITOR ] 153 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Bolt standard project skeleton 2 | ================================ 3 | 4 | Bolt CMS is an open source, adaptable platform for building and running modern websites. Built on PHP, Symfony and more. [Read the site](https://boltcms.io) for more info. 5 | 6 | **To check out Bolt and set up your first Bolt installation, read [Installing Bolt 5][installation].** 7 | 8 | --- 9 | 10 | ## Installing Bolt CMS 11 | 12 | ### with Composer 13 | 14 | **Note**: Installing with composer and running the site on your local machine using the method described below is the preferred method of the Bolt core development team. 15 | 16 | You can set up a new Bolt project, using the following command, replacing `myprojectname` with your desired project's name. 17 | 18 | ```bash 19 | composer create-project bolt/project myprojectname 20 | ``` 21 | 22 | Navigate into the newly created folder, and configure the database in `.env` (The configuration is intended to work with the database SQLite). 23 | 24 | ```dotenv 25 | # Configure database for doctrine/doctrine-bundle 26 | # SQLite (note: _three_ slashes) 27 | DATABASE_URL=sqlite:///%kernel.project_dir%/var/data/bolt.sqlite 28 | 29 | # MYSQL / MariaDB 30 | #DATABASE_URL=mysql://db_user:"db_password"@127.0.0.1:3306/db_name?serverVersion=5.7 31 | 32 | # Postgres 33 | #DATABASE_URL=postgresql://db_user:"db_password"@127.0.0.1:5432/db_name?serverVersion=11&charset=utf8 34 | ``` 35 | 36 | Set up the database, create the first user and add fixtures (dummy content): 37 | 38 | ```bash 39 | bin/console doctrine:database:create # Create database 40 | bin/console doctrine:schema:create # Create schema in database 41 | 42 | bin/console doctrine:fixtures:load --no-interaction # Load fixtures in databse (step not compulsory) 43 | bin/console bolt:add-user --admin # Follow the creation steps in the console (warning: fixtures already created an admin user) 44 | 45 | composer run post-create-project-cmd # Duplicate themes in the appropriate folder 46 | 47 | bin/console bolt:info # Verify Bolt installation 48 | ``` 49 | 50 | Run Bolt using Symfony CLI or your own preferred webserver: 51 | 52 | ```bash 53 | symfony server:start -d 54 | symfony open:local 55 | ``` 56 | 57 | Finally, open the new installation in a browser. If you've used one of the commands above, you'll find the frontpage at http://127.0.0.1:8000/ \ 58 | The Bolt admin panel can be found at http://127.0.0.1:8000/bolt 59 | 60 | Log in using the credentials you created when setting up the first user. 61 | 62 | > Note: If you don't want to use Docker, don't forget to remove what isn't necessary: \ 63 | - remove `.dockerignore` file \ 64 | - remove `docker-composer.yml` file \ 65 | - remove `Dockerfile` file \ 66 | - remove `docker` folder 67 | 68 | ### with Docker 69 | 70 | **Disclaimer**: Docker is not used by the Bolt core development team. Bolt _can_ be run using docker, but you are advised to only attempt this if you have enough experience with Docker yourself to understand what is going on in the `Dockerfile` and in `docker-compose.yml`. The included setup might not be a good fit for _your_ Dockerized setup. When in doubt, follow general advice on running Symfony projects in docker, as Bolt is built using Symfony. The Bolt team doesn't provide pre-built containers. 71 | 72 | Start by [downloading the Bolt project distribution `.tar.gz` file](https://github.com/bolt/project/releases/latest), or [generate a GitHub repository from the template we provide](https://github.com/bolt/project/generate). 73 | Once you have extracted its content, the resulting directory contains the Bolt project structure. You will add your own code and configuration inside it. 74 | 75 | **Note**: Try to avoid using the `.zip` file, as it may cause potential permission issues. 76 | 77 | Bolt is shipped with a [Docker](https://docker.com) setup that makes it easy to get a containerized development environment up and running. If you do not already have Docker on your computer, it's the right time to [install it](https://docs.docker.com/get-docker/). 78 | 79 | On Mac, only [Docker for Mac](https://docs.docker.com/docker-for-mac/) is supported. 80 | Similarly, on Windows, only [Docker for Windows](https://docs.docker.com/docker-for-windows/) is supported. Docker Machine **is not** supported out of the box. 81 | 82 | Open a terminal, and navigate to the directory containing your project skeleton. 83 | 84 | Navigate into the newly created folder, and configure environment variables in the `.env` file for Docker & the database MySQL version 5.7. 85 | 86 | ```dotenv 87 | ###> symfony/framework-bundle ### 88 | APP_ENV=dev 89 | APP_DEBUG=1 90 | APP_SECRET=!ChangeMe! 91 | TRUSTED_PROXIES=127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 92 | TRUSTED_HOSTS='^(localhost|nginx)$' 93 | ###< symfony/framework-bundle ### 94 | 95 | ###> doctrine/doctrine-bundle ### 96 | DATABASE_URL=mysql://bolt:!ChangeMe!@db:3306/bolt?serverVersion=5.7 97 | ###< doctrine/doctrine-bundle ### 98 | 99 | ###> symfony/mailer ### 100 | MAILER_DSN=smtp://mailcatcher:1025 101 | ###< symfony/mailer ### 102 | ``` 103 | 104 | Run the following command to start all services using [Docker Compose](https://docs.docker.com/compose/): 105 | 106 | ```bash 107 | docker-compose up -d # Running in detached mode 108 | docker-compose exec php bin/console doctrine:schema:create # Create schema in database 109 | docker-compose exec php bin/console doctrine:fixtures:load --no-interaction # Load fixtures in databse (step not compulsory) 110 | docker-compose exec php bin/console bolt:add-user --admin # Follow the creation steps in the console (warning: fixtures already created an admin user) 111 | ``` 112 | 113 | This starts the following services: 114 | 115 | | Name | Description | Port(s) | Environment(s) | 116 | |-------------|----------------------------------------------------------------------------|--------------------|--------------------------------------------------| 117 | | db | A MySQL 5.7 database server | 3306 | all (prefer using a managed service in prod) | 118 | | php | The Bolt project with PHP, PHP-FPM 7.4, Composer and sensitive configs | n/a | all | 119 | | nginx | The HTTP server for the Bolt project (NGINX) | 8080 | all | 120 | | h2-proxy | A HTTP/2 and HTTPS development proxy for all apps | 8443 | dev (configure properly your web server in prod) | 121 | | mailcatcher | MailCatcher runs a super simple SMTP server delivered with a web interface | 1025 for smtp port
1080 for interface | only for dev | 122 | 123 |
124 | To see the status of the containers, run: 125 | 126 | ```bash 127 | docker-compose ps 128 | ``` 129 |
130 | 131 |
132 | To execute commands in a container, run: 133 | 134 | ```bash 135 | docker-compose exec 136 | docker-compose exec php sh # To enter the container directly, you will be placed at the root of the project 137 | docker-compose exec php bin/console bolt:add-user # Follow the creation steps in the console (warning: fixtures already created an admin user) 138 | ``` 139 |
140 | 141 |
142 | To see the container's logs, run: 143 | 144 | ```bash 145 | docker-compose logs # Display the logs of all containers 146 | docker-compose logs -f # Same but follow the logs 147 | docker-compose logs -f php # Follow the logs for one container 148 | ``` 149 |
150 | 151 | Finally, open the new installation in a browser. If you've used one of the commands above, you'll find the frontpage at http://localhost:8080/ or https://localhost:8443/ \ 152 | The Bolt admin panel can be found at http://localhost:8080/bolt or https://localhost:8443/bolt 153 | 154 | ## The tests 155 | 156 | ### Static analysis 157 | - [**ECS - Easy Coding Standard**](https://github.com/symplify/easy-coding-standard) 158 | 159 | [The `ecs.php` configuration file is located at the root of the cms project](./ecs.php) 160 | 161 | ```bash 162 | # With Composer 163 | composer lint # Launch ECS in dry run mode (command to launch in a Continuous Integration) 164 | composer lint:fix # Launch ECS in fix mode 165 | 166 | # With Docker 167 | docker-compose exec php composer lint # Launch ECS by the php container 168 | ``` 169 | 170 | - [**PHPStan - PHP Static Analysis Tool**](https://github.com/phpstan/phpstan) 171 | 172 | [The `phpstan.neon` configuration file is located at the root of the cms project](./phpstan.dist.neon) 173 | 174 | ```bash 175 | # With Composer 176 | composer phpstan # Launch PHPStan (command to launch in a Continuous Integration) 177 | 178 | # With Docker 179 | docker-compose exec php composer phpstan # Launch PHPStan by the php container 180 | ``` 181 | 182 | ## Contributing 183 | 184 | If you'd like to contribute, please check [Bolt's core repository](https://github.com/bolt/core/blob/master/CONTRIBUTING.md) 185 | and read the ["Contributing to Bolt"](https://docs.bolt.cm/4.0/other/contributing) documentation page. 186 | 187 | [installation]: https://docs.bolt.cm/installation 188 | -------------------------------------------------------------------------------- /UPDATE.md: -------------------------------------------------------------------------------- 1 | Bolt 5 - Beta Update Instructions 2 | ================================= 3 | 4 | If you are experiencing issues with translations, make sure that 5 | you have the following in `config/packages/php_translation.yaml`: 6 | 7 | ```yaml 8 | # php-translation config 9 | 10 | translation: 11 | configs: 12 | bolt: 13 | output_dir: "%kernel.project_dir%/translations" 14 | ``` 15 | Note this only applies to Bolt 5 beta versions. 16 | 17 | Bolt 4 - Beta Update Instructions 18 | ================================= 19 | 20 | If you're updating a previous Bolt 4 Beta to the latest, you might bump into 21 | some quirks. Read below on how to fix these 22 | 23 | The base command to update is always: 24 | 25 | ```bash 26 | composer update 27 | bin/console cache:clear 28 | ``` 29 | 30 | ## From earlier Beta's to more recent versions 31 | 32 | ### Error: Expected known function, got 'INSTR'" 33 | 34 | If you get this error, edit `config/packages/doctrine.yaml` and make sure the following is included: 35 | 36 | ```yaml 37 | dql: 38 | string_functions: 39 | JSON_EXTRACT: Bolt\Doctrine\Functions\JsonExtract 40 | CAST: DoctrineExtensions\Query\Mysql\Cast 41 | INSTR: DoctrineExtensions\Query\Mysql\Instr 42 | numeric_functions: 43 | RAND: Bolt\Doctrine\Functions\Rand 44 | ``` 45 | 46 | ### The file "../vendor/bolt/core/src/Controller/Backend/" does not exist 47 | 48 | If you get the following error: 49 | 50 | ``` 51 | The file "../vendor/bolt/core/src/Controller/Backend/" does not exist (in: "…/config/routes") 52 | in ../vendor/bolt/core/src/Controller/Backend/ 53 | ``` 54 | 55 | Edit `config/routes/bolt.yaml` to add `../` to each of the `resource:`'s: 56 | 57 | ```php 58 | control_panel: 59 | resource: '../../vendor/bolt/core/src/Controller/Backend/' 60 | prefix: '%bolt.backend_url%' 61 | type: annotation 62 | 63 | # Async: Upload, Embed 64 | control_panel_async: 65 | resource: '../../vendor/bolt/core/src/Controller/Backend/Async' 66 | prefix: '%bolt.backend_url%/async' 67 | type: annotation 68 | 69 | # ImageController, Currently only used for thumbnails 70 | controllers: 71 | resource: '../../vendor/bolt/core/src/Controller/ImageController.php' 72 | type: annotation 73 | ``` 74 | 75 | ### Cannot autowire service "Bolt\Controller\ErrorController" 76 | 77 | If you get this error: 78 | 79 | ``` 80 | !! In AbstractRecursivePass.php line 153: 81 | !! 82 | !! Invalid service "Bolt\Controller\ExceptionController": class "Bolt\Controll 83 | !! er\ExceptionController" does not exist 84 | ``` 85 | 86 | Replace the following lines in `services.yaml`: 87 | 88 | ```yaml 89 | # Override Symfony's error pages (so we can show custom 404's) 90 | Bolt\Controller\ExceptionController: 91 | public: true 92 | arguments: 93 | $debug: '%kernel.debug%' 94 | ``` 95 | 96 | with: 97 | 98 | ``` 99 | Symfony\Component\ErrorHandler\ErrorRenderer\ErrorRendererInterface: '@error_handler.error_renderer.html' 100 | 101 | Squirrel\TwigPhpSyntax\PhpSyntaxExtension: ~ 102 | ``` 103 | 104 | Replace this line in `packages/twig.yaml`: 105 | 106 | ```yaml 107 | exception_controller: Bolt\Controller\ExceptionController::showAction 108 | ``` 109 | 110 | with: 111 | 112 | ```yaml 113 | exception_controller: ~ 114 | ``` 115 | 116 | Next, *delete* the file `config/routes/dev/twig.yaml` 117 | 118 | And finally, in `packages/framework.yaml`, add: 119 | 120 | ```yaml 121 | # Override Symfony's error controller, so we can show custom 404's and 503's 122 | error_controller: Bolt\Controller\ErrorController::showAction 123 | ``` 124 | 125 | ### Uncaught …\ClassNotFoundException: Attempted to load class "DoctrineCacheBundle" / "WhiteOctoberPagerfantaBundle" 126 | 127 | If you get this error: 128 | 129 | ``` 130 | !! Fatal error: Uncaught …\ClassNotFoundException: Attempted to load class "DoctrineCacheBundle" from namespace "Doctrine\Bundle\DoctrineCacheBundle". 131 | !! Did you forget a "use" statement for another namespace? in /…/src/Kernel.php:32 132 | !! Stack trace: 133 | ``` 134 | 135 | Or this error: 136 | 137 | ``` 138 | !! PHP Fatal error: Uncaught …\ClassNotFoundException: Attempted to load class "WhiteOctoberPagerfantaBundle" from namespace "WhiteOctober\PagerfantaBundle". 139 | !! Did you forget a "use" statement for another namespace? in /…/src/Kernel.php:32 140 | ``` 141 | 142 | You can fix this by _removing_ this line from `config/bundles.php`: 143 | 144 | ```php 145 | Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle::class => ['all' => true], 146 | … 147 | WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle::class => ['all' => true], 148 | ``` 149 | 150 | 151 | ### Uncaught Error: Class '…WhiteOctoberPagerfantaBundle' not found 152 | 153 | If you get this error: 154 | 155 | ``` 156 | Script cache:clear returned with error code 255 157 | !! PHP Fatal error: Uncaught Error: Class 'WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle' 158 | !! not found in site/vendor/bolt/core/src/Kernel.php:32 159 | !! Stack trace: 160 | ``` 161 | 162 | Edit `config/bundles.php`, and replace 163 | 164 | ```php 165 | WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle::class => ['all' => true], 166 | ``` 167 | 168 | with 169 | 170 | ```php 171 | BabDev\PagerfantaBundle\BabDevPagerfantaBundle::class => ['all' => true], 172 | ``` 173 | 174 | ### Call to a member function setLocale() on array OR Collection fields not visible 175 | 176 | If you get this error when saving a record: 177 | ``` 178 | Call to a member function setLocale() on array 179 | ``` 180 | or, if collection items are not visible after saving them 181 | 182 | Update services.yaml, add the 3 lines below: 183 | ```yaml 184 | Bolt\Event\Listener\FieldFillListener: 185 | tags: 186 | - { name: doctrine.event_listener, event: postLoad } 187 | ``` 188 | 189 | ### "$defaultLocale" of method "__construct()" 190 | 191 | If you get this error: 192 | 193 | ``` 194 | Cannot autowire service "Bolt\Canonical": argument "$defaultLocale" of meth 195 | !! od "__construct()" is type-hinted "string", you should configure its value 196 | !! explicitly. 197 | ``` 198 | 199 | Update services.yaml, add the line with `$defaultLocale`: 200 | 201 | ```yaml 202 | services: 203 | _defaults: 204 | … 205 | bind: 206 | $locales: '%app_locales%' 207 | $defaultLocale: '%locale%' 208 | … 209 | ``` 210 | 211 | ### "$publicFolder" of method "__construct()" 212 | 213 | If you get this error: 214 | 215 | ``` 216 | Cannot autowire service "Bolt\Command\CopyAssetsCommand": argument "$public 217 | !! Folder" of method "__construct()" is type-hinted "string", you should confi 218 | !! gure its value explicitly. 219 | ``` 220 | 221 | Update services.yaml, add the line with `$publicFolder`: 222 | 223 | ```yaml 224 | services: 225 | _defaults: 226 | … 227 | bind: 228 | … 229 | $publicFolder: '%bolt.public_folder%' 230 | $tablePrefix: '%bolt.table_prefix%' 231 | ``` 232 | 233 | ### Unable to find file "@TranslationBundle/Resources/config/routing_webui.yml" 234 | 235 | If you get this error: 236 | 237 | ``` 238 | Unable to find file "@TranslationBundle/Resources/config/routing_webui.yml" in 239 | @TranslationBundle/Resources/config/routing_webui.yml (which is being imported 240 | from "/Users/bob/Sites/Bolt/standard-project/config/routes/translation.yml"). 241 | ``` 242 | 243 | Update `config/routes/translation.yml`: 244 | 245 | ``` 246 | resource: "@TranslationBundle/Resources/config/routing_webui.yaml" 247 | ``` 248 | 249 | and `config/routes/dev/translation.yml`: 250 | 251 | ``` 252 | resource: '@TranslationBundle/Resources/config/routing_symfony_profiler.yaml' 253 | ``` 254 | 255 | In both cases, you just need to update `.yml` to `.yaml` 256 | 257 | 258 | ### Attempted to load class "StofDoctrineExtensionsBundle" 259 | 260 | If you get this error: 261 | 262 | ``` 263 | PHP Fatal error: Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "StofDoctrineExtensionsBundle" from namespace "Stof\DoctrineExtensionsBundle". 264 | ``` 265 | 266 | Or this error: 267 | 268 | ``` 269 | Specified non-existing directory "/…/vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity/MappedSuperclass" 270 | as Doctrine mapping source. 271 | ``` 272 | 273 | Remove these two lines from `config/services.yaml`: 274 | 275 | ```yaml 276 | doctrine.orm.entity_manager.class: Bolt\Doctrine\TranslatableEntityManager 277 | stof_doctrine_extensions.listener.translatable.class: Bolt\Event\Listener\PreTranslatableListener 278 | ``` 279 | 280 | In `config/bundles.php`, remove one line, and add another. Remove: 281 | 282 | ```php 283 | Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle::class => ['all' => true], 284 | ``` 285 | 286 | and replace it with: 287 | 288 | ```php 289 | Knp\DoctrineBehaviors\Bundle\DoctrineBehaviorsBundle::class => ['all' => true], 290 | ``` 291 | 292 | Then, delete the file `config/packages/stof_doctrine_extensions.yaml` 293 | 294 | Then, in `config/packages/doctrine.yaml`, remove these sections: 295 | 296 | ```yaml 297 | gedmo_translatable: 298 | type: annotation 299 | prefix: Gedmo\Translatable\Entity 300 | dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/lib/Gedmo/Translatable/Entity/MappedSuperclass" 301 | is_bundle: false 302 | gedmo_translator: 303 | type: annotation 304 | prefix: Gedmo\Translator\Entity 305 | dir: "%kernel.project_dir%/vendor/gedmo/doctrine-extensions/lib/Gedmo/Translator/Entity" 306 | is_bundle: false 307 | ``` 308 | 309 | ### "Notice: Undefined index: location" 310 | 311 | If you get this error: 312 | 313 | ``` 314 | Notice: Undefined index: location 315 | ``` 316 | 317 | You can fix this by adding the following to your `config/services.yaml`: 318 | 319 | ```yaml 320 | monolog.processor.request: 321 | class: Bolt\Log\RequestProcessor 322 | tags: 323 | - { name: monolog.processor, method: processRecord, handler: db } 324 | ``` 325 | 326 | ### Add `monolog.yaml` 327 | 328 | Create a new file `config/packages/monolog.yaml`, to configure the new logging: 329 | 330 | ```yaml 331 | monolog: 332 | channels: ['db'] 333 | handlers: 334 | db: 335 | channels: ['db'] 336 | type: service 337 | id: Bolt\Log\LogHandler 338 | ``` 339 | 340 | ### PDOException > DriverException 341 | 342 | If your database is out of date, you get this error: 343 | 344 | ``` 345 | An exception occurred while executing '…' with params […]: 346 | 347 | SQLSTATE[HY000]: General error: 348 | ``` 349 | 350 | Run the following to update it (by force): 351 | 352 | ```bash 353 | bin/console doctrine:schema:update --force 354 | ``` 355 | 356 | ### Autowire TimedPublishSubscriber 357 | 358 | If you get this error: 359 | 360 | ``` 361 | Cannot autowire service "Bolt\Event\Subscriber\TimedPublishSubscriber": argument "$prefix" of method "__construct()" is type-hinted "string", you should 362 | configure its value explicitly. 363 | ``` 364 | 365 | You can fix this by adding the following to your `config/services.yaml`: 366 | 367 | ```yaml 368 | Bolt\Event\Subscriber\TimedPublishSubscriber: 369 | arguments: [ "%bolt.table_prefix%" ] 370 | ``` 371 | -------------------------------------------------------------------------------- /config/bolt/config.yaml: -------------------------------------------------------------------------------- 1 | # Note: Database setup is best done in ENV variables. See the file `.env` 2 | # in the project root. 3 | 4 | # The name of the website 5 | sitename: Bolt Project Website 6 | payoff: The amazing payoff goes here 7 | 8 | secret: '%env(APP_SECRET)%' 9 | 10 | # Set the caching configuration for various areas of Bolt. 11 | # The expires_after is counted in seconds. 12 | caching: 13 | related_options: 3600 14 | canonical: 60 15 | formatter: 60 16 | selectoptions: 3600 17 | content_array: ~ 18 | frontend_menu: 3600 19 | backend_menu: 3600 20 | 21 | # The theme to use. 22 | # 23 | # Dont edit the provided templates directly, because they _will_ get updated 24 | # in next releases. If you wish to modify a default theme, copy its folder, and 25 | # change the name here accordingly. 26 | theme: base-2021 27 | #theme: skeleton 28 | 29 | # Set the timezone to be used on the website. For a list of valid timezone 30 | # settings, see: http://php.net/manual/en/timezones.php 31 | # timezone: UTC 32 | 33 | # Set the default time format used on this website. For a list of valid date 34 | # format settings, see: https://www.php.net/manual/en/function.date.php 35 | date_format: 'F j, Y H:i' 36 | 37 | # You can set a preference to omit background images on the login screen. 38 | omit_backgrounds: false 39 | 40 | # If you're a party-pooper who wants to hide the `generator` meta tag and 41 | # `x-powered-by` header, set these to true 42 | omit_meta_generator_tag: false 43 | 44 | headers: 45 | # Allow of Google's FLoC by setting this to `true` (defaults to `false` for opt-out) 46 | # https://github.com/symfony/symfony/pull/40989 47 | allow-floc: false 48 | # Add Bolt's "Powered By" (defaults to `true`) 49 | powered_by: true 50 | 51 | # If your site is reachable under different urls (say, both blog.example.org/ 52 | # as well as example.org/), its a good idea to set one of these as the 53 | # canonical, so its clear which is the primary address of the site. 54 | # 55 | # If you include `https://`, it will be included in the canonical urls. 56 | canonical: '%env(default::BOLT_CANONICAL)%' 57 | 58 | # If you want to override the canonical template, from the theme: 59 | #canonical_template: 'partials/_canonical.html.twig' 60 | 61 | # By setting this to true, you will get a relative canonical path passed to the template. 62 | #relative_canonical_url: true 63 | 64 | # Bolt can insert a for all pages on the site. 65 | 66 | # Note: The location given is relative to the currently selected theme. If 67 | # you want to set the icon yourself, just dont enable the following line. 68 | #favicon: images/favicon-bolt.ico 69 | 70 | # The default content to use for the homepage, and the template to render it 71 | # with. This can either be a singleton like `homepage`, a specific record (like 72 | # `page/1`) or a listing of records (like `entries`). In the chosen 73 | # homepage_template, you will have `record` or `records` at your disposal, 74 | # depending on the homepage setting. 75 | # 76 | # Note: If you've changed the filename, and your changes do not show up on 77 | # the website, be sure to check for a theme.yaml file in your themes 78 | # folder. If a template is set there, it will override the setting here. 79 | homepage: homepage 80 | homepage_template: index.twig 81 | 82 | # The default content for the "Not Found" (404) page. Can be an (array of) template 83 | # names or identifiers for records, which will be tried until a match is found. 84 | notfound: [ blocks/404-not-found, 'helpers/page_404.html.twig' ] 85 | 86 | # Toggle maintenance mode on or off. Note: If you're logged in, you'll still see 87 | # the website as usual. Use an incognito window to see the "maintenance" page. 88 | maintenance_mode: false 89 | 90 | # The default for the "Maintenance mode" (503) page. Can be an (array of) template 91 | # names or identifiers for records, which will be tried until a match is found. 92 | maintenance: [ blocks/503-maintenance-mode, 'helpers/page_503.html.twig' ] 93 | 94 | # The default content for the "Forbidden" (403) page. Can be an (array of) template 95 | # names or identifiers for records, which will be tried until a match is found. 96 | forbidden: [ blocks/403-forbidden, 'helpers/page_403.html.twig' ] 97 | 98 | # The default content for the "Internal Server Error" (500) page. Can be an 99 | # (array of) template names or identifiers for records. 100 | # Note: Only used in `APP_ENV=prod` mode. You're advised to keep this as simple 101 | # as possible, because if an error occurs in this template, it can not be 102 | # handled, and you'll have a bad time debugging it! 103 | internal_server_error: [ 'helpers/page_500.html.twig' ] 104 | 105 | # The default template for record-pages on the site. 106 | # 107 | # Can be overridden for each content type and for each record, if it has a 108 | # templateselect field. 109 | # 110 | # Note: If you've changed the filename, and your changes do not show up on the 111 | # website, be sure to check for a config.yaml file in your themes folder. 112 | # If a template is set there, it will override the setting here. 113 | record_template: record.twig 114 | 115 | # The default template and amount of records to use for listing-pages on the 116 | # site. 117 | # 118 | # Can be overridden for each content type. 119 | # 120 | # Note: If you've changed the filename, and your changes do not show up on the 121 | # website, be sure to check for a config.yaml file in your themes 122 | # folder. If a template is set there, it will override the setting here. 123 | listing_template: listing.twig 124 | listing_records: 6 125 | listing_sort: datepublish DESC 126 | 127 | # Allow filtering on listing pages using query parameters, much like you would 128 | # with {% setcontent %}. E.g. /pages?order=id and /pages?title--like=voluptat 129 | # Useful for search. 130 | query_search: 131 | # Enables filtering. 132 | enable: true 133 | # If true, query params with empty values will be ignored. 134 | ignore_empty: false 135 | 136 | # Maximum amount of items to show in a `