Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Symfony Console Laravel Package

precision-soft/symfony-console

Adds Symfony Console support to Laravel, letting you run Artisan commands and build custom CLI applications with familiar Symfony components. A lightweight integration for creating console commands, handling interactive input, and extending your Laravel project's command-line tooling.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install the package, then read .example/ in the repository — not in vendor/. The directory is export-ignored, so composer require never delivers it. Clone the repo (or browse it on the host) and run .dev/validate/all.sh --example to get a green baseline you can diff your own work against.
  • The example is the fastest map of the public surface: two commands on AbstractCommand using InstancesTrait, MemoryAndTimeLimitsTrait and TimeLimitTrait, one bundle configuration whose environment selects the templates, and generated crontab rows, Supervisor programs, systemd units and Kubernetes values files.
  • First real use case: pick a bundle configuration for production, write one command extending AbstractCommand, and let it render a single SystemdServiceTemplate. Run it, inspect the file, then run it again with --diff to confirm idempotency. Nothing else in the package is worth learning until that loop is boring.
  • Wire --check into CI on day one. It is the only cheap guard against a config drifting between what the code says and what is committed.

Implementation Patterns

Bundle configuration as the environment switch. One bundle configuration, environment-selected templates. Keep the per-environment variance in the bundle config and out of the command bodies — the commands stay thin AbstractCommand subclasses and the templates stay dumb renderers. The example does exactly this; copy the shape rather than inventing a second convention.

Traits are opt-in, not automatic. InstancesTrait for multi-instance fan-out, MemoryAndTimeLimitsTrait and TimeLimitTrait for commands that render many files or shell out to verification tools. Add them where you actually need them; they change command behaviour and are easy to leave on accidentally when copy-pasting a command.

Generation → commit → verify. The stable workflow:

php artisan your:generate            # write files
php artisan your:generate --diff     # eyeball the change
php artisan your:generate --check    # CI gate: non-zero if anything drifted

Commit generated artifacts. --check then fails loudly when someone edits a unit by hand or changes a template without regenerating.

Use the three preview modes for review, not just for debugging. They are the cheapest way to get a reviewer to look at generated output; put the diff into the PR body for template changes.

Assert what the consumer reads. The example asserts crontab rows, Supervisor programs, systemd units and Kubernetes values files the way a deployment pipeline reads them, and runs systemd-analyze verify wherever it is on PATH. Do the same in your own tests: parse the artifact, don't assert on file_get_contents() equality, or you will re-baseline on every escaping fix.

Catch InvalidConfigurationException at the boundary. Template constructors reject bad values at generation time. If your command takes user input (a path, a command line, an environment file), wrap generation and turn the exception into a console error rather than a stack trace — the message names the offending field.

Gotchas and Tips

Upgrade once, expect one round of --check failures. v4.8.0 fixed several escaping bugs, so inputs that were silently broken now generate different bytes. Re-generate everything after upgrading and commit the result. Do not "fix" these diffs by hand.

Control characters are now refused. user, working_directory, environment_file, standard_output, standard_error, log_file, logs_dir, log_file_name, prefix and every command part reject any value containing a control character, with InvalidConfigurationException at generation time. This is a hardening, not a regression: a newline in working_directory used to end the directive and start a new one, so "/srv\nExecStartPre=..." produced a unit that systemd-analyze verify happily accepted with both lines. If you were feeding values from a YAML/env file, trim and strip before handing them to the templates — do not catch and swallow the exception.

Escaping is per-template and deliberately not uniform. Know the rules before you write a value:

  • systemd: $ is doubled in ExecStart arguments, so --secret=pa$word becomes pa$$word. A ; standing alone as an argument is written \; (bare, it splits into two ExecStart commands and a Type=simple unit refuses to load); a ; inside an argument is untouched.
  • crontab: % is escaped to \% in command parts, the log directory and the log file name. Unescaped, cron truncates the command there and pipes the rest to stdin — --date=%Y-%m-%d ran as --date= with Y- on stdin. Log paths are wrapped in POSIX single quotes, not escapeshellarg(), which under the C locale drops every byte above 0x7f; /srv/données now survives.
  • Supervisor: % is doubled in command and log paths because Supervisor %-interpolates (%(program_name)s); a bare % was a fatal format error at load. Placeholder substitution is now single-pass, so a command part literally spelling %user% is no longer rewritten to the user name.

Practical consequence: a % or $ you want to survive is not the same string across templates. Never share a raw command-line string between the three templates and assume it renders the same; build it per template or test each output.

CRLF vs LF is now diagnosable. ConfFileWriter::diff() compares bytes while ConfFileDiffRenderer compares lines, so a CRLF file regenerated as LF used to show as [changed] with nothing underneath and failed --check. It now emits the ---/+++ header plus \ line endings differ (ConfFileDiffRenderer::LINE_ENDINGS_MARKER). If you see that marker, fix the source of the drift — a .gitattributes eol=lf rule, an editor setting, a Windows checkout — rather than normalising in code. Byte-level equality is still the actual pass/fail criterion.

Deleted files show their contents. --diff reads the content of a file no command declares any more, so removals display under +++ /dev/null instead of an empty @@ -0,0 +0,0 @@ hunk. You can see what save() is about to delete before you run it.

Symlinks in output directories. A directory reachable through a symlink is no longer reported as a removed file that save() would then delete. A dangling symlink is still reported as removed — so a stale link under your output root is a real deletion, not noise.

Extension points. The three templates and ConfFileWriter/ConfFileDiffRenderer are the seams: subclass a template when you need an extra directive, and keep escaping inside the template rather than in the command so every caller inherits it. If you write your own renderer, mirror the [changed]/[added]/[removed] vocabulary and the line-endings marker, or --diff output becomes inconsistent across your command set.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource