Download the PHP package monad/skeleton without Composer

On this page you can find all versions of the php package monad/skeleton. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package skeleton

Monad Skeleton

Application skeleton for the Monad Framework — an MVC-based PHP framework for solo developers and small teams. This is the project you clone/create to build an app; the framework itself lives in monad/clarity, installed as a dependency.

Status: 1.2.0, published on Packagist. Depends on monad/clarity ^1.0, which currently resolves to 1.8.0. The two packages have independent version lines; each repository's CHANGELOG.md is the authoritative record of its own.

Requirements

Installation

create-project writes .env for you, from .env_example and with a freshly generated APP_SECRET (scripts/setup-env.php, Composer's post-create-project-cmd). The secret is generated rather than left blank because a blank one does not fail: App\Middlewares\Csrf passes it to Clarity's HMAC::sign(), which signs happily with an empty key, so the application would boot and issue CSRF and session tokens that anyone can forge. Every other key arrives present and empty, documented in place.

It never overwrites an existing .env, and never fails the installation — if it cannot write the file it says so and tells you to cp .env_example .env yourself.

npm install is not optional for a working page. Its postinstall hook runs npm run build:all, which does two things nothing else does:

Re-run npm run build:css (or npm run watch:css while developing) whenever you add Tailwind classes the previous build never saw.

Project layout

Controllers, Models, Services, and Middlewares are capitalised deliberately: PSR-4 resolves namespaces to paths case-sensitively, so the directory case must match the namespace segment exactly (App\Controllers\UserController → app/Controllers/ UserController.php). routes/ and views/ stay lowercase since neither is namespace-autoloaded.

The mitosis CLI

Custom commands are registered in app/routes/cli.php.

checkout:install is deliberately separate from setup: payments are opt-in, so an application that takes none never creates the four checkout tables. Run it only if you use Monad\Clarity\Services\Checkout (Clarity 1.2.0+). schedule:install is separate for the same reason — see below.

Scheduled jobs

Monad\Clarity\Services\Scheduler (Clarity 1.5.0+) keeps the application's schedule in code rather than in a crontab, so jobs travel with a deploy and are visible to code review. The system cron gets exactly one line, for the life of the application:

Add it on every node that should be eligible to run jobs — three nodes give three chances a due job runs, and no chance it runs three times: each due job is claimed cluster-wide before it runs.

Note the deliberate absence of > /dev/null 2>&1. A tick where nothing was due, or where another node already claimed everything, prints nothing and exits 0 — so silence is the healthy signal, and the one line you do get is the alert. The reflexive redirect throws the failures away along with the quiet.

To adopt it:

  1. php mitosis schedule:install — once, per database context.
  2. Register jobs in app/routes/cli.php with Scheduler::job().
  3. php mitosis schedule:list — confirms what is registered and, once the jobs start running, how each one last went. It is read-only and always exits 0, so it is the safe thing to run when you want to know what the cluster thinks it is doing.
  4. Add the crontab line above, on every node that should run jobs.

app/routes/cli.php ships with a commented-out example. Jobs are registered with Scheduler::job($name, $cronExpression, $work, staleAfterMinutes: 60); the console kernel loads that file before every dispatch, so a malformed expression breaks the next mitosis invocation in plain sight rather than producing a job that quietly never fires.

Cron expressions are evaluated on the application's own clock — the TIMEZONE value in .env, which config/bootstrap.php hands to date_default_timezone_set(). That is not necessarily the timezone the system cron runs in, and every node in a cluster must agree on it or they are running two different schedules.

Running the crontab line before schedule:install is safe: the tick exits 1 every minute naming the install command, loudly, rather than silently doing nothing.

Sending mail

Monad\Clarity\Services\Mail (Clarity 1.6.0+) sends through any of seven mailers — Postmark, Resend, SendGrid, Mailgun, Mailtrap, Amazon SES, or plain SMTP — behind one contract, so changing provider is a change to .env and nothing else. There is no mitosis command and no table: Mail owns no state.

config/mail.php builds the mailer and hands it back. Application code requires it and sends:

MAIL_MAILERS is the whole of the multi-mailer decision. One name gives you that mailer; a comma-separated list gives you a pool that tries them left to right, so a provider outage does not take password resets down with it:

Both return a Services\Mail, so nothing downstream changes when you switch between them. There is no separate "enable failover" flag — the list is it.

Three things worth knowing before you rely on a pool:

Check $sent->failedOver() and log $sent->attempts if you pool: Clarity keeps no delivery table, so that return value is the only record a mailer is failing.

Taking payments

Monad\Clarity\Services\Checkout (Clarity 1.2.0+) puts Stripe and Paddle behind one contract: begin a checkout, re-query it, verify a callback, refund it. Changing gateway is a change to .env and a checkout:install you have probably already run.

Two commands before the first payment — the tables are opt-in, so an application that takes no payments never carries them:

config/checkout.php reads the credentials and builds the adapter for the one gateway named in CHECKOUT_GATEWAY:

The two Paddle names are not interchangeable. Paddle's past_due means Pending for a subscription and Failed for a one-time payment (Clarity ReleaseNotes_1.4.0.md §2.6), so the name here decides what a live callback is taken to mean, not merely which object gets built.

The callback endpoint is shipped; the sale is not

POST /webhooks/checkout (app/routes/api.php) is built and tested. Point Stripe > Webhooks or Paddle > Notifications at it and put the signing secret it issues into .env. It verifies the signature, applies the event to TransactionLedger, and answers 204 when it worked or was a redelivery, 400 when the callback did not verify or was not a checkout event, and 404 when it named a transaction this ledger never opened — which asks the gateway to retry, and is what resolves a race against the sale that records it.

With CHECKOUT_GATEWAY=paddle_subscription it handles both families a Paddle notification destination delivers to that one URL, routed on the event type's prefix: transaction.* events go to TransactionLedger, and the subscription.* events describing the plan's life afterwards go to SubscriptionLedger. A subscription is born from a transaction (Clarity ReleaseNotes_1.4.0.md §2.3), so both streams arrive, and the endpoint also joins the two references when the paying transaction carries the subscription it created.

This half is shipped because it is identical in every application, and because without it a paid transaction sits at Pending in the ledger for ever: the redirect back from a checkout page tells you where the customer went, not what the bank did.

The other half — createCheckout() — is not shipped, and that is deliberate. What is being sold, at what price, with which success and cancel URLs is your product, and a skeleton that guessed it would be guessing. Build it where the sale happens:

A signing secret is not optional. Clarity refuses to verify a callback without one rather than accepting it unverified, so the endpoint answers 400 for every delivery until it is set.

Testing

Tests live in resources/tests/ and use an in-memory SQLite database — no real database required to run the suite. resources/tests/bootstrap.php sets up the small amount of ambient state (PATH, APP_SECRET) a few App\Middlewares\* stubs read at construction.

Middleware stubs

app/Middlewares/* are thin, zero-argument-constructor subclasses of Clarity's engines (Csrf, RateLimiter, CORS, Jsonify, Logger, Authentication, RBAC) — customise by overriding the protected extension points documented on each parent class, or by changing what the constructor passes through (env-driven config, resolver closures against your own tables). Authentication/RBAC here are wired against the example users table (database/migrations/20260101000000_create_users_table.php).

License

MIT. See LICENSE.


All versions of skeleton with dependencies

PHP Build Version
Package Version
Requires php Version >=8.2
monad/clarity Version ^1.0
vlucas/phpdotenv Version ^5.6
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package monad/skeleton contains the following files

Loading the files please wait ...