{ "manifests": { "kocal/symfony-app-pack": { "manifest": { "copy-from-recipe": { ".github/": ".github/", "tools/": "tools/", ".twig-cs-fixer.php": ".twig-cs-fixer.php", "ecs.php": "ecs.php", "Makefile.local": "Makefile.local", "php.ini": "php.ini", "phpstan.dist.neon": "phpstan.dist.neon", "rector.php": "rector.php" }, "gitignore": [ "/Makefile.local" ], "makefile": [ "ROOT_DIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))", "include $(ROOT_DIR)/tools/make/text.mk", "include $(ROOT_DIR)/tools/make/help.mk", "include $(ROOT_DIR)/tools/make/os.mk", "include $(ROOT_DIR)/tools/make/git.mk", "", ".DEFAULT_GOAL := help", "", "# Executables", "SF := symfony", "SF_PROXY = $(shell $(SF) local:proxy:url)", "SF_CONSOLE := $(SF) console", "PHP := $(SF) php", "COMPOSER := $(SF) composer", "", "UID := $(shell id -u)", "GID := $(shell id -g)", "DC := USER_ID=$(UID) GROUP_ID=$(GID) docker compose --env-file /dev/null", "", "## Install everything needed to start the project", "install:", "\t$(SF) local:server:ca:install", "\t$(MAKE) start", "\t$(MAKE) app.install", "", "## Start the environment", "start:", "\t$(DC) up -d", "\t$(SF) proxy:start", "\t$(SF) serve", "", "## Stop the environment", "stop:", "\t$(DC) kill", "", "## Stop and delete the environment and project data (database, logs, etc.)", "delete:", "\t$(DC) down -v --remove-orphans", "", "## App - Install the application", "app.install:", "\t@$(call action, Installing PHP dependencies...)", "\t$(COMPOSER) install --prefer-dist", "", "\t@$(call action, Running DB migrations...)", "\t$(SF_CONSOLE) doctrine:migrations:migrate --no-interaction --all-or-nothing", "", "## App - Install the application (alias to \"make app.install\")", "app.update: app.install", "", "######", "# QA #", "######", "", "## QA - Run all QA checks", "qa: archi refactor cs lint phpstan test", "", "## QA - Run all QA checks and fix issues", "qa.fix: archi refactor.fix cs.fix lint.fix phpstan test", "", "#########", "# Archi #", "#########", "", "## Architecture - Run architecture checks", "archi: archi.back", "", "## Architecture - Run architecture checks for backend", "archi.back:", "\t$(PHP) vendor/bin/deptrac --report-uncovered --fail-on-uncovered", "", "############", "# Refactor #", "############", "", "## Refactor - Run all refactor checks", "refactor: refactor.back", "", "## Refactor - Run all refactor checks and fix issues", "refactor.fix: refactor.back.fix", "", "## Refactor - Run refactor checks for backend", "refactor.back:", "\t$(PHP) vendor/bin/rector process --dry-run", "", "## Refactor - Run refactor checks for backend and fix issues", "refactor.back.fix:", "\t$(PHP) vendor/bin/rector process", "", "################", "# Coding style #", "################", "", "## Coding style - Run all coding style checks", "cs: cs.back cs.front", "", "## Coding style - Run all coding style checks and fix issues", "cs.fix: cs.back.fix cs.front.fix", "", "## Coding style - Check backend coding style", "cs.back:", "\t$(PHP) vendor/bin/ecs check", "\t$(PHP) vendor/bin/twig-cs-fixer", "", "## Coding style - Check backend coding style and fix issues", "cs.back.fix:", "\t$(PHP) vendor/bin/ecs check --fix", "\t$(PHP) vendor/bin/twig-cs-fixer --fix", "", "## Coding style - Check frontend coding style", "cs.front: bin/oxfmt", "\tbin/oxfmt --check", "", "## Coding style - Check frontend coding style and fix issues", "cs.front.fix: bin/oxfmt", "\tbin/oxfmt", "", "bin/oxfmt:", "\t@$(call action, Downloading oxfmt...)", "\t$(SF_CONSOLE) oxc:download:oxfmt", "\t@$(call success, oxfmt downloaded successfully)", "", "##########", "# Linter #", "##########", "", "## Linter - Run all linters", "lint: lint.back lint.front", "", "## Linter - Run all linters and fix issues", "lint.fix: lint.back lint.front.fix", "", "## Linter - Run linters for backend", "lint.back:", "\t$(SF_CONSOLE) lint:container", "\t$(SF_CONSOLE) lint:xliff translations", "\t$(SF_CONSOLE) lint:yaml --parse-tags config", "\t$(SF_CONSOLE) lint:twig templates", "\t#$(SF_CONSOLE) doctrine:schema:validate", "", "## Linter - Lint front files", "lint.front: bin/oxlint", "\tbin/oxlint", "", "## Linter - Lint front files and fix issues", "lint.front.fix: bin/oxlint", "\tbin/oxlint --fix", "", "bin/oxlint:", "\t@$(call action, Downloading oxlint...)", "\t$(SF_CONSOLE) oxc:download:oxlint", "", "###########", "# PHPStan #", "###########", "", "## PHPStan - Run PHPStan", "phpstan:", "\t$(PHP) vendor/bin/phpstan analyse", "", "## PHPStan - Run PHPStan and update the baseline", "phpstan.generate-baseline:", "\t$(PHP) vendor/bin/phpstan analyse --generate-baseline", "", "#########", "# Tests #", "#########", "", "## Tests - Run all tests", "test: test.back", "", "## Tests - Run backend tests", "test.back:", "\t$(PHP) vendor/bin/phpunit", "## Tests - Run backend tests with coverage", "", "test.back.coverage:", "\t$(PHP) vendor/bin/phpunit --coverage-html .cache/phpunit/coverage-html", "", "-include $(ROOT_DIR)/Makefile.local" ] }, "files": { ".github/dependabot.yaml": { "contents": [ "# To get started with Dependabot version updates, you'll need to specify which", "# package ecosystems to update and where the package manifests are located.", "# Please see the documentation for all configuration options:", "# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file", "", "version: 2", "updates:", " - package-ecosystem: \"composer\" # See documentation for possible values", " directory: \"/\" # Location of package manifests", " schedule:", " interval: \"weekly\"", "" ], "executable": false }, ".github/workflows/ci.yaml": { "contents": [ "name: CI", "", "defaults:", " run:", " shell: bash", "", "on:", " pull_request:", " types: [ opened, synchronize, reopened, ready_for_review ]", " push:", " branches:", " - main", "", "concurrency:", " group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}", " cancel-in-progress: true", "", "jobs:", " qa:", " if: ${{ ! github.event.pull_request.draft }}", " name: Quality Assurance", " timeout-minutes: 10", " runs-on: ubuntu-latest", " steps:", " - name: Checkout", " uses: actions/checkout@v4", "", " - name: Setup PHP", " uses: shivammathur/setup-php@v2", " with:", " extensions: ctype, iconv, mbstring", " tools: symfony", "", " - name: Start Docker containers", " run: docker compose up -d --wait", "", " - name: Install project", " run: make app.install", "", " - name: QA", " run: make qa", "" ], "executable": false }, ".twig-cs-fixer.php": { "contents": [ "addStandard(new TwigCsFixer\\Standard\\Symfony());", "", "$config = new TwigCsFixer\\Config\\Config();", "$config->setCacheFile(__DIR__.'/tools/.cache/twig-cs-fixer');", "$config->setRuleset($ruleset);", "", "return $config;", "" ], "executable": false }, "Makefile.local": { "contents": [ "# Local targets that should not be committed to git", "" ], "executable": false }, "ecs.php": { "contents": [ "withParallel()", " ->withCache(__DIR__ . '/tools/.cache/ecs')", " ->withPaths([", " __DIR__ . '/assets',", " __DIR__ . '/config',", " __DIR__ . '/public',", " __DIR__ . '/src',", " __DIR__ . '/tests',", " __DIR__ . '/tools',", " ])", " ->withSkip([", " __DIR__ . '/tools/.cache',", " __DIR__ . '/config/bundles.php',", " __DIR__ . '/config/reference.php',", " ])", " ->withPreparedSets(", " psr12: true,", " common: true,", " strict: true,", " cleanCode: true,", " )", ";", "" ], "executable": false }, "php.ini": { "contents": [ "memory_limit = -1", "" ], "executable": false }, "phpstan.dist.neon": { "contents": [ "includes:", " - vendor/kocal/phpstan-symfony-ux/extension.neon", " - vendor/phpstan/phpstan-symfony/extension.neon", " - vendor/phpstan/phpstan-doctrine/extension.neon", " - tools/phpstan/symfony-configuration.php", "", "parameters:", " level: 9", " paths:", " - bin/", " - config/", " - public/", " - src/", " - tools/", " - tests/", " excludePaths:", " - config/reference.php", " - tools/.cache", "", " tmpDir: tools/.cache/phpstan", "", " symfony:", " consoleApplicationLoader: tools/phpstan/console-application.php", "", " doctrine:", " objectManagerLoader: tools/phpstan/object-manager.php", "", "rules:", " - Kocal\\PHPStanSymfonyUX\\Rules\\TwigComponent\\ClassMustBeFinalRule", " - Kocal\\PHPStanSymfonyUX\\Rules\\TwigComponent\\ClassNameMustNotEndWithComponentRule", " - Kocal\\PHPStanSymfonyUX\\Rules\\TwigComponent\\ForbiddenAttributesPropertyRule", " - Kocal\\PHPStanSymfonyUX\\Rules\\TwigComponent\\ForbiddenClassPropertyRule", " - Kocal\\PHPStanSymfonyUX\\Rules\\TwigComponent\\MethodsVisibilityRule", " - Kocal\\PHPStanSymfonyUX\\Rules\\TwigComponent\\PostMountMethodSignatureRule", " - Kocal\\PHPStanSymfonyUX\\Rules\\TwigComponent\\PreMountMethodSignatureRule", " - Kocal\\PHPStanSymfonyUX\\Rules\\TwigComponent\\PublicPropertiesMustBeCamelCaseRule", "" ], "executable": false }, "rector.php": { "contents": [ "withParallel()", " ->withCache(__DIR__ . '/tools/.cache/rector')", " ->withPaths([", " __DIR__ . '/config',", " __DIR__ . '/public',", " __DIR__ . '/src',", " __DIR__ . '/tests',", " __DIR__ . '/tools',", " ])", " ->withPhpSets()", " ->withPreparedSets(", " deadCode: true,", " codeQuality: true,", " codingStyle: true,", " typeDeclarations: true,", " privatization: true,", " instanceOf: true,", " earlyReturn: true,", " phpunitCodeQuality: true,", " doctrineCodeQuality: true,", " symfonyCodeQuality: true,", " )", " ->withSkip([", " __DIR__ . '/config/bundles.php',", " __DIR__ . '/config/reference.php',", " __DIR__ . '/tools/.cache',", " ControllerMethodInjectionToConstructorRector::class,", " ])", ";", "" ], "executable": false }, "tools/.gitignore": { "contents": [ ".cache/", "" ], "executable": false }, "tools/make/git.mk": { "contents": [ "########", "# Diff #", "########", "", "# Returns the list of changed files for some given extensions and some given folders.", "#", "# @param $1 The file extensions of changed files", "# @param $2 The relative folders to parse for changed files", "#", "# Examples:", "#", "# Example #1: list PHP and Javascript files changed in the src and test folders", "#", "# $(call git_diff, php js, src test)", "", "define git_diff", "$(shell \\", "\tfor ext in $(if $(strip $(1)),$(strip $(1)),\"\") ; \\", "\tdo \\", "\t\tfor dir in $(if $(strip $(2)),$(strip $(2)),\"\") ; \\", "\t\tdo \\", "\t\t\tgit --no-pager diff --name-status \"$$(git merge-base HEAD origin/master)\" \\", "\t\t\t\t| grep \"$${ext}\\$$\" \\", "\t\t\t\t| grep \"\\\\s$${dir}\" \\", "\t\t\t\t| grep -v '^D' \\", "\t\t\t\t| awk '{ print $$NF }' || true ; \\", "\t\tdone ; \\", "\tdone \\", ")", "endef", "" ], "executable": false }, "tools/make/help.mk": { "contents": [ "########", "# Help #", "########", "", ".DEFAULT_GOAL := help", "", "HELP = \\", "\tUsage: make [$(COLOR_INFO)command$(COLOR_RESET)] \\", "\t$(call help_section, Help) \\", "\t$(call help,help,This help)", "", "define help_section", "\t\\n\\n$(COLOR_COMMENT)$(strip $(1)):$(COLOR_RESET)", "endef", "", "define help", " \\n $(COLOR_INFO)$(1)$(COLOR_RESET) $(2)", "endef", "", "", "help:", "\t@printf \"\\n$(HELP)\"", "\t@awk ' \\", "\t\tBEGIN { \\", "\t\t\tsectionsName[1] = \"Commands\" ; \\", "\t\t\tsectionsCount = 1 ; \\", "\t\t} \\", "\t\t/^[-a-zA-Z0-9_.@%\\/+]+:/ { \\", "\t\t\tif (match(lastLine, /^## (.*)/)) { \\", "\t\t\t\tcommand = substr($$1, 1, index($$1, \":\") - 1) ; \\", "\t\t\t\tsection = substr(lastLine, RSTART + 3, index(lastLine, \" - \") - 4) ; \\", "\t\t\t\tif (section) { \\", "\t\t\t\t\tmessage = substr(lastLine, index(lastLine, \" - \") + 3, RLENGTH) ; \\", "\t\t\t\t\tsectionIndex = 0 ; \\", "\t\t\t\t\tfor (i = 1; i <= sectionsCount; i++) { \\", "\t\t\t\t\t\tif (sectionsName[i] == section) { \\", "\t\t\t\t\t\t\tsectionIndex = i ; \\", "\t\t\t\t\t\t} \\", "\t\t\t\t\t} \\", "\t\t\t\t\tif (!sectionIndex) { \\", "\t\t\t\t\t\tsectionIndex = sectionsCount++ + 1 ; \\", "\t\t\t\t\t\tsectionsName[sectionIndex] = section ; \\", "\t\t\t\t\t} \\", "\t\t\t\t} else { \\", "\t\t\t\t\tmessage = substr(lastLine, RSTART + 3, RLENGTH) ; \\", "\t\t\t\t\tsectionIndex = 1 ; \\", "\t\t\t\t} \\", "\t\t\t\tif (length(command) > sectionsCommandLength[sectionIndex]) { \\", "\t\t\t\t\tsectionsCommandLength[sectionIndex] = length(command) ; \\", "\t\t\t\t} \\", "\t\t\t\tsectionCommandIndex = sectionsCommandCount[sectionIndex]++ + 1; \\", "\t\t\t\thelpsCommand[sectionIndex, sectionCommandIndex] = command ; \\", "\t\t\t\thelpsMessage[sectionIndex, sectionCommandIndex] = message ; \\", "\t\t\t} \\", "\t\t} \\", "\t\t{ lastLine = $$0 } \\", "\t\tEND { \\", "\t\t\tfor (i = 1; i <= sectionsCount; i++) { \\", "\t\t\t\tif (sectionsCommandCount[i]) { \\", "\t\t\t\t\tprintf \"\\n\\n$(COLOR_COMMENT)%s:$(COLOR_RESET)\", sectionsName[i] ; \\", "\t\t\t\t\tfor (j = 1; j <= sectionsCommandCount[i]; j++) { \\", "\t\t\t\t\t\tprintf \"\\n $(COLOR_INFO)%-\" sectionsCommandLength[i] \"s$(COLOR_RESET) %s\", helpsCommand[i, j], helpsMessage[i, j] ; \\", "\t\t\t\t\t} \\", "\t\t\t\t} \\", "\t\t\t} \\", "\t\t} \\", "\t' $(MAKEFILE_LIST)", "\t@printf \"\\n\\n\"", "", ".PHONY: help", "" ], "executable": false }, "tools/make/os.mk": { "contents": [ "######", "# Os #", "######", "", "# Os detection helpers.", "#", "# Examples:", "#", "# Example #1: conditions on linux", "#", "# echo $(if $(OS_LINUX),Running on Linux,*NOT* running on Linux)", "", "ifeq ($(OS),Windows_NT)", "OS = windows", "OS_WINDOWS = 1", "else", "# See: https://make.mad-scientist.net/deferred-simple-variable-expansion/", "OS = $(eval OS := $$(shell uname -s | tr '[:upper:]' '[:lower:]'))$(OS)", "OS_LINUX = $(if $(findstring linux,$(OS)),1)", "OS_DARWIN = $(if $(findstring darwin,$(OS)),1)", "endif", "" ], "executable": false }, "tools/make/text.mk": { "contents": [ "##########", "# Colors #", "##########", "", "COLOR_RESET := \\033[0m", "COLOR_BOLD_ITALIC := \\033[1;4m", "COLOR_ERROR := \\033[31m", "COLOR_INFO := \\033[32m", "COLOR_WARNING := \\033[33m", "COLOR_COMMENT := \\033[36m", "", "######################", "# Special Characters #", "######################", "", "# Usage:", "# $(call message, Foo$(,) bar) = Foo, bar", "", ", := ,", "", "########", "# Time #", "########", "", "# Usage:", "# $(call time) = 11:06:20", "", "define time", "`date -u +%T`", "endef", "", "###########", "# Message #", "###########", "", "# Usage:", "# $(call message, Foo bar) = Foo bar", "# $(call message_success, Foo bar) = (\u3063\u25d5\u203f\u25d5)\u3063 Foo bar", "# $(call message_warning, Foo bar) = \u00af\\_(\u30c4)_/\u00af Foo bar", "# $(call message_error, Foo bar) = (\u256f\u00b0\u25a1\u00b0)\u256f\ufe35 \u253b\u2501\u253b Foo bar", "", "define message", "\tprintf \"$(COLOR_INFO)$(strip $(1))$(COLOR_RESET)\\n\"", "endef", "", "define message_success", "\tprintf \"$(COLOR_INFO)(\u3063\u25d5\u203f\u25d5)\u3063 $(strip $(1))$(COLOR_RESET)\\n\"", "endef", "", "define message_warning", "\tprintf \"$(COLOR_WARNING)$(strip $(1))$(COLOR_RESET)\\n\"", "endef", "", "define message_error", "\tprintf \"$(COLOR_ERROR)(\u256f\u00b0\u25a1\u00b0)\u256f\ufe35 \u253b\u2501\u253b $(strip $(1))$(COLOR_RESET)\\n\"", "endef", "", "###########", "# Confirm #", "###########", "", "# Usage:", "# $(call confirm, Foo bar) = \u0f3c \u3064 \u25d5_\u25d5 \u0f3d\u3064 Foo bar (y/N):", "", "define confirm", "\t$(if $(CONFIRM),, \\", "\t\tprintf \"$(COLOR_INFO) \u0f3c \u3064 \u25d5_\u25d5 \u0f3d\u3064 $(COLOR_WARNING)$(strip $(1)) $(COLOR_RESET)$(COLOR_WARNING)(y/N)$(COLOR_RESET): \"; \\", "\t\tread CONFIRM ; if [ \"$$CONFIRM\" != \"y\" ]; then printf \"\\n\"; exit 1; fi; \\", "\t)", "endef", "", "#######", "# Log #", "#######", "", "# Usage:", "# $(call log, Foo bar) = [11:06:20] [target] Foo bar", "# $(call log_warning, Foo bar) = [11:06:20] [target] \u00af\\_(\u30c4)_/\u00af Foo bar", "# $(call log_error, Foo bar) = [11:06:20] [target] (\u256f\u00b0\u25a1\u00b0)\u256f\ufe35 \u253b\u2501\u253b Foo bar", "# $(call log_and_call, echo 'Message') = [11:06:20] [target] echo 'Message' then execute the command", "", "define log", "\tprintf \"[$(COLOR_COMMENT)$(call time)$(COLOR_RESET)] [$(COLOR_COMMENT)$(@)$(COLOR_RESET)] \" ; $(call message, $(1))", "endef", "", "define log_warning", "\tprintf \"[$(COLOR_COMMENT)$(call time)$(COLOR_RESET)] [$(COLOR_COMMENT)$(@)$(COLOR_RESET)] \" ; $(call message_warning, $(1))", "endef", "", "define log_error", "\tprintf \"[$(COLOR_COMMENT)$(call time)$(COLOR_RESET)] [$(COLOR_COMMENT)$(@)$(COLOR_RESET)] \" ; $(call message_error, $(1))", "endef", "", "##########", "# Action #", "##########", "", "# Usage:", "# $(call action, Foo bar) = > Foo bar (in bold)", "", "define action", "\tprintf \"\\n$(COLOR_BOLD_ITALIC)>>> $(strip $(1))$(COLOR_RESET)\\n\\n\"", "endef", "" ], "executable": false }, "tools/phpstan/console-application.php": { "contents": [ "bootEnv(__DIR__ . '/../../.env');", "", "// @phpstan-ignore-next-line argument.type", "$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);", "", "return new Application($kernel);", "" ], "executable": false }, "tools/phpstan/object-manager.php": { "contents": [ "bootEnv(__DIR__ . '/../../.env');", "", "// @phpstan-ignore-next-line argument.type", "$kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);", "$kernel->boot();", "", "/** @var EntityManager $entityManager */", "$entityManager = $kernel->getContainer()->get('doctrine')->getManager();", "", "return $entityManager;", "" ], "executable": false }, "tools/phpstan/symfony-configuration.php": { "contents": [ " [", " 'symfony' => [", " 'containerXmlPath' => $xmlContainerFile,", " ],", " ],", "];", "" ], "executable": false } }, "ref": "090a78cd1f770682e72243dca41b9e73ec765eb6" } } }