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

Skeleton App Laravel Package

ppi/skeleton-app

A starter skeleton application for the PPi PHP framework, providing the base structure, bootstrap wiring, and configuration needed to quickly create and launch a new PPi project.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a project template, not a library — you don't require it into an existing app, you scaffold from it. Treat composer create-project (or a manual clone + composer install) as step one, and expect to own the resulting codebase outright.

  1. Read composer.json first. It tells you the PHP constraint, the ppi/framework version it pins, and which "extra goodies" (templating, ORM, mailer, logging) are actually wired in versus merely suggested. Everything else in the skeleton exists to satisfy this file.
  2. Confirm prerequisites. The 2016-era release targets PHP 5.6/7.0-era code. Check the require block before you install anything modern; if you're on PHP 8 you're in for dependency surgery, not a create-project and go.
  3. Commit your own composer.lock immediately. As of 2.1.2 the skeleton no longer ships a lock file, so composer install resolves fresh every time against floating constraints. Do one install, verify it boots, commit the resulting lock, and treat that lock as part of your project — see the gotchas for why this matters more here than usual.
  4. Scaffold and point a vhost at public/. public/index.php is the front controller — the document root must be public, never the repo root. For a quick look: php -S 127.0.0.1:8000 -t public. Make sure the cache and log directories are writable before you debug a blank page.
  5. Read the boot sequence in order: public/index.php → app/config/ → app/modules/. That chain is the whole mental model of the framework. index.php selects the environment and boots the application; config layers are merged; modules register their services and routes.
  6. First real use case: copy the bundled/default module into a new namespace, rename it, add one route and one controller action returning a response, and confirm it renders. Once that round-trip works you understand the module contract, and everything else is repetition of that pattern. (2.1.2 fixed the skeleton module so it no longer references a PSR-7 interface — the demo module is once again a clean starting point, but that also means the PSR-7 plumbing example is gone; look at the framework source under vendor/ppi/ if you need to see how HTTP messages are actually wired.)

Implementation Patterns

Module-per-feature. The module is the unit of composition: each has a Module.php with lifecycle hooks (init/boot-style) where you register services, routes, and event listeners. Organize your own code the same way — one module per bounded feature, not one giant "App" module. Modules are also the cheapest thing to extract later if you need to reuse code elsewhere.

Service container as the seam. Define services and dependencies in the module, resolve them through the container, and inject into controllers. Resist pulling the container into domain/business classes — that's the one decision that makes or breaks maintainability in a container-driven framework, and it's easy to get wrong when you're learning from the skeleton's demo code.

Layered config. Expect module-level defaults overridden by application-level config, merged by environment. Keep environment-specific values (DB credentials, debug flags, mail transport) out of module config and in your app-level env config so modules stay portable.

Routing stays in the module. Register routes alongside the services they serve. That keeps a module self-contained and deletable.

Third-party libraries via Composer, wrapped in a module. Don't sprinkle vendor calls through controllers; register one service per dependency so swapping or mocking is a one-line config change. Pin those dependencies explicitly in your lock file — with no lock shipped upstream, a floating ^ constraint is the thing most likely to break your build six months from now.

Deployment workflow: composer install --no-dev -o on the target from a committed lock file, clear the compiled cache, docroot at public/, writable cache/log dirs, debug off. Do that sequence in a script — the cache step is the one people forget and then chase ghosts over.

Gotchas and Tips

  • It's effectively archived. Last release 2016, 53 stars, zero dependents. That means no community answers, no security patches, and a shrinking pool of PHP versions it will run on. Use it as a learning base or to maintain an existing install — not as the foundation for a new greenfield project without accepting the maintenance burden.
  • No lock file since 2.1.2. The skeleton used to pin a working dependency set for you; now composer install floats against whatever satisfies the constraints today. For a framework this old, that's a real risk of pulling a newer transitive dependency that breaks a 2016 codebase. Generate a lock on day one, commit it, and use composer install (not update) everywhere thereafter.
  • The vendor tree is your documentation. With no ecosystem around it, vendor/ppi/ source is the reference. When a lifecycle hook or config key doesn't behave as the README implies, read the framework class — it's small.
  • Cache staleness is the #1 false bug. Routes and config get compiled; edits appear not to take effect until you clear the cache directory. If you change config and nothing happens, clear before you debug.
  • Blank pages are usually permissions. Unwritable cache/log directories fail silently or near-silently depending on debug mode. Check directory ownership before touching application code.
  • Autoloading new modules requires a composer dump-autoload. Add the namespace to composer.json (PSR-0/PSR-4 as the skeleton demonstrates) and regenerate. A module that loads in one environment and not another is almost always an autoloader dump that didn't happen.
  • Turn debug on during development, unconditionally off in production. Error verbosity and cache behavior typically key off one environment flag; get it wrong and production will either leak stack traces or hide real failures.
  • Modern PHP + old constraints = --ignore-platform-reqs smell. If you find yourself bypassing platform checks to install, stop and reconsider the dependency set rather than papering over it — you're trading a five-minute fix for a debugging session later. Same applies to forcing resolution because the lockless install picked something incompatible.
  • Extension points worth knowing: custom modules, service definitions/parameters in the container, and event listeners. Those three cover most integration needs without forking the framework.
  • Escape hatch: because the app is yours, extract anything that grows beyond a demo into a namespaced package with its own tests. Treat the skeleton itself as disposable scaffolding.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings