mirror of
https://github.com/symfony/recipes.git
synced 2026-09-18 18:46:40 +03:00
[FrameworkBundle][WebpackEncoreBundle][SassBundle][TailwindBundle][Reprise] Add support for .symfony.local.yaml file (#1474)
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{compose.yaml,compose.*.yaml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -0,0 +1,12 @@
|
||||
# This configuration file is used by the Symfony CLI tool.
|
||||
# See https://symfony.com/doc/current/setup/symfony_cli.html for more information.
|
||||
|
||||
http:
|
||||
use_gzip: true
|
||||
|
||||
# Processes that automatically run with the server (https://symfony.com/doc/current/setup/symfony_cli.html#configuring-workers)
|
||||
workers:
|
||||
# Consume async messages, and restart the worker when the code changes
|
||||
#messenger_consume_async:
|
||||
# cmd: ['symfony', 'console', 'messenger:consume', 'async']
|
||||
# watch: ['config', 'src', 'templates', 'vendor/composer/installed.json']
|
||||
@@ -0,0 +1,108 @@
|
||||
# AGENTS.md
|
||||
|
||||
This is a Symfony project. Check `composer.json` for the exact Symfony/PHP version
|
||||
in use, and read `symfony.lock` to see which recipes ran. Don't assume Doctrine,
|
||||
Twig, API Platform, Messenger, or Lock are installed unless one of those says so.
|
||||
|
||||
## Ask before generating
|
||||
|
||||
If the task doesn't specify, ask rather than guess:
|
||||
|
||||
- Persistence: Doctrine ORM, Doctrine ODM, or none?
|
||||
- Interface: server-rendered (Twig), API (Serializer, maybe API Platform), or both?
|
||||
- Auth: SecurityBundle, and which authenticator?
|
||||
|
||||
If you can't ask (no interactive channel), state the assumption you're making and
|
||||
pick the smallest option (e.g. no persistence layer) rather than scaffolding a
|
||||
full stack nobody asked for.
|
||||
|
||||
## Adding features: Flex, not hand-wiring
|
||||
|
||||
Install new capabilities with `composer require <package>` (e.g. `symfony/lock`,
|
||||
`symfony/messenger`, `orm-pack`) and let the Flex recipe register the bundle and
|
||||
generate its config. Don't hand-edit `config/bundles.php` or hand-write a bundle's
|
||||
base config; that's what the recipe is for. Don't skip a good-fit component just
|
||||
because it isn't installed yet; installing it is one command.
|
||||
|
||||
## Conventions
|
||||
|
||||
Follow https://symfony.com/doc/current/best_practices.html to write idiomatic
|
||||
Symfony:
|
||||
|
||||
- Use PHP attributes for framework metadata, and not only on controllers:
|
||||
`#[Route]`, `#[MapRequestPayload]`, `#[IsGranted]` on actions, `#[Assert\...]`
|
||||
on properties, `#[AsCommand]`, `#[AsEventListener]`, `#[AsMessageHandler]`, and
|
||||
`#[AsAlias]` / `#[AsTaggedItem]` / `#[Autoconfigure]` on services. No YAML or
|
||||
XML routing.
|
||||
- Rely on autowiring and autoconfiguration. Type-hint constructor arguments and
|
||||
let the container resolve them. Where a type-hint can't express it, stay in the
|
||||
class with `#[Autowire]` (parameters, env vars, expressions) or `#[Target]` (one
|
||||
of several implementations of an interface). A YAML service definition is the
|
||||
last resort, not the first.
|
||||
- Controllers extend `AbstractController`, stay thin, and delegate to services.
|
||||
- Use the framework for what it already does: Form for server-rendered forms,
|
||||
Validator for validation, Serializer for JSON, Messenger for async work,
|
||||
Security (voters, authenticators) for access control, Twig `path()`/`url()`
|
||||
instead of hardcoded URLs.
|
||||
- Before hand-writing infrastructure (locks, queues, caches, HTTP clients,
|
||||
mailers, schedulers) or reaching for a third-party library, check whether a
|
||||
Symfony component covers it. It usually does.
|
||||
|
||||
Three specifics worth spelling out, because they are easy to get wrong:
|
||||
|
||||
- Bind request data with `#[MapRequestPayload]` / `#[MapQueryString]` on action
|
||||
arguments, which wires up Serializer and Validator for you, instead of calling
|
||||
`json_decode()` or `SerializerInterface` by hand. If neither package is
|
||||
installed yet, `composer require` them rather than falling back to manual
|
||||
parsing.
|
||||
- Use constructor property promotion, and `readonly` for DTOs and value objects.
|
||||
Don't mark a service `readonly` if it might become `lazy: true`: a lazy proxy
|
||||
can't extend a `readonly` class.
|
||||
- Use `symfony/lock` (`LockFactory`) for mutual exclusion. A hand-built flag or
|
||||
lock file looks fine in review and is usually wrong under concurrency.
|
||||
|
||||
## Everyday workflow
|
||||
|
||||
- Run the app with `symfony serve -d`, and commands with `symfony console ...`
|
||||
(or `bin/console` when the Symfony CLI isn't available).
|
||||
- When something fails, read `var/log/dev.log` and the web profiler
|
||||
(`/_profiler`) before changing code.
|
||||
- If `maker-bundle` is installed, prefer `bin/console make:*` with every argument
|
||||
passed up front and `--no-interaction` where supported: makers prompt on a
|
||||
terminal by default, which hangs a non-interactive shell. If a maker still
|
||||
needs interactive input, hand-write the code instead.
|
||||
- If Doctrine ORM is installed, schema changes go through migrations
|
||||
(`bin/console make:migration`, then `doctrine:migrations:migrate`), never
|
||||
`doctrine:schema:update` or hand-written SQL.
|
||||
- `.env` is committed and holds defaults only. Real secrets belong in `.env.local`
|
||||
(git-ignored) or the secrets vault (`bin/console secrets:set`), read via
|
||||
`%env(...)%`.
|
||||
|
||||
## Testing
|
||||
|
||||
Install `symfony/test-pack` if it isn't already. Functional/HTTP tests extend
|
||||
`WebTestCase`; service-level tests extend `KernelTestCase`. Run
|
||||
`php bin/phpunit` (falls back to `vendor/bin/phpunit`). A feature isn't done
|
||||
until it has a test that exercises it the way a caller would, an HTTP request for
|
||||
a controller or a service call for a service, not just "it didn't throw."
|
||||
|
||||
## Code style
|
||||
|
||||
Symfony's coding standard, the `@Symfony` php-cs-fixer ruleset (a PSR-12-derived
|
||||
superset). Run `vendor/bin/php-cs-fixer fix` if `friendsofphp/php-cs-fixer` is
|
||||
installed; it isn't part of the skeleton by default.
|
||||
|
||||
## Discover, don't guess
|
||||
|
||||
Framework APIs change between versions and your training data may be stale. Look
|
||||
things up in the project instead of relying on memory:
|
||||
|
||||
- `bin/console about`: versions, environment, paths.
|
||||
- `bin/console debug:router`, `debug:container`, `debug:autowiring <name>`,
|
||||
`debug:config <bundle>`, `config:dump-reference <bundle>`: what exists and how
|
||||
it is configured.
|
||||
- `bin/console lint:container`, plus `lint:twig templates/` and
|
||||
`lint:yaml config/` where those packages are installed: validate before running.
|
||||
- Read the installed source and docblocks under `vendor/`.
|
||||
- Docs: https://symfony.com/doc/current/ (switch to the version matching
|
||||
`composer.json` if it differs).
|
||||
@@ -0,0 +1,3 @@
|
||||
# CLAUDE.md
|
||||
|
||||
@AGENTS.md
|
||||
@@ -0,0 +1,19 @@
|
||||
framework:
|
||||
cache:
|
||||
# Unique name of your app: used to compute stable namespaces for cache keys.
|
||||
#prefix_seed: your_vendor_name/app_name
|
||||
|
||||
# The "app" cache stores to the filesystem by default.
|
||||
# The data in this cache should persist between deploys.
|
||||
# Other options include:
|
||||
|
||||
# Redis
|
||||
#app: cache.adapter.redis
|
||||
#default_redis_provider: redis://localhost
|
||||
|
||||
# APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues)
|
||||
#app: cache.adapter.apcu
|
||||
|
||||
# Namespaced pools use the above "app" backend by default
|
||||
#pools:
|
||||
#my.dedicated.cache: null
|
||||
@@ -0,0 +1,15 @@
|
||||
# see https://symfony.com/doc/current/reference/configuration/framework.html
|
||||
framework:
|
||||
secret: '%env(APP_SECRET)%'
|
||||
|
||||
# Note that the session will be started ONLY if you read or write from it.
|
||||
session: true
|
||||
|
||||
#esi: true
|
||||
#fragments: true
|
||||
|
||||
when@test:
|
||||
framework:
|
||||
test: true
|
||||
session:
|
||||
storage_factory_id: session.storage.factory.mock_file
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
foreach (glob(dirname(__DIR__).'/var/cache/prod/*.preload.php') ?: [] as $file) {
|
||||
require $file;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
when@dev:
|
||||
_errors:
|
||||
resource: '@FrameworkBundle/Resources/config/routing/errors.php'
|
||||
prefix: /_error
|
||||
@@ -0,0 +1,23 @@
|
||||
# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json
|
||||
|
||||
# This file is the entry point to configure your own services.
|
||||
# Files in the packages/ subdirectory configure your dependencies.
|
||||
# See also https://symfony.com/doc/current/service_container/import.html
|
||||
|
||||
# Put parameters here that don't need to change on each machine where the app is deployed
|
||||
# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration
|
||||
parameters:
|
||||
|
||||
services:
|
||||
# default configuration for services in *this* file
|
||||
_defaults:
|
||||
autowire: true # Automatically injects dependencies in your services.
|
||||
autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
|
||||
|
||||
# makes classes in src/ available to be used as services
|
||||
# this creates a service per class whose id is the fully-qualified class name
|
||||
App\:
|
||||
resource: '../src/'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
# please note that last definitions always *replace* previous ones
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"bundles": {
|
||||
"Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle": ["all"]
|
||||
},
|
||||
"copy-from-recipe": {
|
||||
"config/": "%CONFIG_DIR%/",
|
||||
"public/": "%PUBLIC_DIR%/",
|
||||
"src/": "%SRC_DIR%/",
|
||||
".editorconfig": ".editorconfig",
|
||||
".symfony.local.yaml": ".symfony.local.yaml",
|
||||
"AGENTS.md": "AGENTS.md",
|
||||
"CLAUDE.md": "CLAUDE.md"
|
||||
},
|
||||
"composer-scripts": {
|
||||
"cache:clear": "symfony-cmd",
|
||||
"assets:install %PUBLIC_DIR%": "symfony-cmd"
|
||||
},
|
||||
"env": {
|
||||
"APP_ENV": "dev",
|
||||
"APP_SECRET": "",
|
||||
"APP_SHARE_DIR": "%VAR_DIR%/share"
|
||||
},
|
||||
"dotenv": {
|
||||
"dev": {
|
||||
"APP_SECRET": "%generate(secret)%"
|
||||
}
|
||||
},
|
||||
"gitignore": [
|
||||
"/.env.local",
|
||||
"/.env.local.php",
|
||||
"/.env.*.local",
|
||||
"/%CONFIG_DIR%/secrets/prod/prod.decrypt.private.php",
|
||||
"/%PUBLIC_DIR%/bundles/",
|
||||
"/%VAR_DIR%/",
|
||||
"/vendor/"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
* <fg=blue>Run</> your application:
|
||||
1. Go to the project directory
|
||||
2. Create your code repository with the <comment>git init</comment> command
|
||||
3. Download the Symfony CLI at <comment>https://symfony.com/download</> to install a development web server
|
||||
|
||||
* <fg=blue>Read</> the documentation at <comment>https://symfony.com/doc</>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
use App\Kernel;
|
||||
|
||||
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
|
||||
|
||||
return static function (array $context) {
|
||||
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App;
|
||||
|
||||
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
|
||||
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
|
||||
|
||||
class Kernel extends BaseKernel
|
||||
{
|
||||
use MicroKernelTrait;
|
||||
|
||||
/**
|
||||
* @return list<string> An array of allowed values for APP_ENV
|
||||
*/
|
||||
private function getAllowedEnvs(): array
|
||||
{
|
||||
return ['prod', 'dev', 'test'];
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,20 @@
|
||||
"position": "after_target",
|
||||
"target": "{% block javascripts %}",
|
||||
"warn_if_missing": true
|
||||
},
|
||||
{
|
||||
"file": ".symfony.local.yaml",
|
||||
"content": [
|
||||
" # Start the Vite dev server",
|
||||
" vite:",
|
||||
" cmd: ['npx', 'vite']",
|
||||
" # Or instead, if you use Rsbuild (https://rsbuild.rs/)",
|
||||
" #rsbuild:",
|
||||
" # cmd: ['npx', 'rsbuild', 'dev']"
|
||||
],
|
||||
"position": "after_target",
|
||||
"target": "workers:",
|
||||
"warn_if_missing": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -37,6 +37,20 @@
|
||||
"position": "after_target",
|
||||
"target": "{% block stylesheets %}",
|
||||
"warn_if_missing": true
|
||||
},
|
||||
{
|
||||
"file": ".symfony.local.yaml",
|
||||
"content": [
|
||||
" # Watch and build front assets using Webpack Encore",
|
||||
" npm_encore_watch:",
|
||||
" cmd: ['npm', 'run', 'watch']",
|
||||
" # Or instead, run the Webpack Dev Server (https://symfony.com/doc/current/frontend/encore/dev-server.html)",
|
||||
" #npm_encore_dev_server:",
|
||||
" # cmd: ['npm', 'run', 'dev-server']"
|
||||
],
|
||||
"position": "after_target",
|
||||
"target": "workers:",
|
||||
"warn_if_missing": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
// add your SASS styles in this file
|
||||
@@ -0,0 +1,3 @@
|
||||
symfonycasts_sass:
|
||||
root_sass:
|
||||
- 'assets/styles/app.scss'
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"bundles": {
|
||||
"Symfonycasts\\SassBundle\\SymfonycastsSassBundle": ["all"]
|
||||
},
|
||||
"copy-from-recipe": {
|
||||
"config/": "%CONFIG_DIR%/",
|
||||
"assets/": "assets/"
|
||||
},
|
||||
"aliases": ["symfonycasts_sass"],
|
||||
"gitignore": [
|
||||
"/%PUBLIC_DIR%/assets/"
|
||||
],
|
||||
"add-lines": [
|
||||
{
|
||||
"requires": "symfony/asset-mapper",
|
||||
"file": "config/packages/asset_mapper.yaml",
|
||||
"position": "after_target",
|
||||
"warn_if_missing": true,
|
||||
"target": " missing_import_mode: strict",
|
||||
"content": [
|
||||
" excluded_patterns:",
|
||||
" - '**/assets/styles/*/_*.scss'"
|
||||
]
|
||||
},
|
||||
{
|
||||
"file": ".symfony.local.yaml",
|
||||
"content": [
|
||||
" # Watch and build Sass files",
|
||||
" sass:",
|
||||
" cmd: ['symfony', 'console', 'sass:build', '--watch']"
|
||||
],
|
||||
"position": "after_target",
|
||||
"target": "workers:",
|
||||
"warn_if_missing": true
|
||||
}
|
||||
],
|
||||
"conflict": {
|
||||
"symfony/asset-mapper": "<6.3"
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,18 @@
|
||||
"bundles": {
|
||||
"Symfonycasts\\TailwindBundle\\SymfonycastsTailwindBundle": ["all"]
|
||||
},
|
||||
"aliases": ["tailwind", "tailwindcss"]
|
||||
"aliases": ["tailwind", "tailwindcss"],
|
||||
"add-lines": [
|
||||
{
|
||||
"file": ".symfony.local.yaml",
|
||||
"content": [
|
||||
" # Watch and build CSS files using Tailwind CSS",
|
||||
" tailwind:",
|
||||
" cmd: ['symfony', 'console', 'tailwind:build', '--watch']"
|
||||
],
|
||||
"position": "after_target",
|
||||
"target": "workers:",
|
||||
"warn_if_missing": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user