Layers
A layer is a Composer package that lives in your repository, in one of the buckets: functional/ and technical/ by default. Its composer.json is its contract: its name, its namespace, the layers it requires and its service provider.
Anatomy of a layer
functional/orders/
├── composer.json ← "type": "layer"
├── config/
│ └── orders.php
├── src/
│ ├── Models/Order.php
│ ├── Http/Controllers/OrderController.php
│ ├── Listeners/SendOrderConfirmation.php
│ ├── Policies/OrderPolicy.php
│ ├── View/Components/Alert.php
│ └── Providers/OrdersServiceProvider.php
├── database/
│ ├── migrations/
│ ├── factories/OrderFactory.php
│ └── seeders/OrdersSeeder.php
├── lang/
│ └── en/messages.php
├── resources/
│ └── views/
├── routes/
│ ├── web.php
│ ├── api.php
│ ├── console.php
│ └── channels.php
└── tests/
├── Feature/
└── Unit/
Only composer.json is required. The generators create the other folders when you first need them.
The layer's composer.json
OSDD treats a folder as a layer when its composer.json has "type": "layer". osdd:layer writes this one:
{
"name": "functional/orders",
"description": "",
"type": "layer",
"version": "1.0.0",
"require": {
"lomkit/laravel-osdd": "*"
},
"autoload": {
"psr-4": {
"Functional\\Orders\\": "src/",
"Functional\\Orders\\Database\\Seeders\\": "database/seeders/",
"Functional\\Orders\\Database\\Factories\\": "database/factories/"
}
},
"minimum-stability": "stable",
"prefer-stable": true,
"extra": {
"laravel": {
"providers": [
"Functional\\Orders\\Providers\\OrdersServiceProvider"
]
}
}
}
nameis the layer's identifier: the--layeroption of every generator takes it, andosdd:phpunitnames the layer's test suite after it.- The shortest
psr-4prefix is the layer's root namespace, and its directory the layer's source directory. Generators write classes under it. extra.laravel.providerslets Laravel discover the layer's service provider, like any package.
A layer that depends on another one requires it:
"require": {
"lomkit/laravel-osdd": "*",
"functional/orders": "*"
}
Create a layer with its requirements with php artisan osdd:layer functional/billing --requires=functional/orders. osdd:check then makes sure the code only uses the layers it requires: see Boundaries.
Naming
A layer name is a Composer package name: vendor/package, in lowercase letters and digits, with words separated by -, _ or .. Each part starts with a letter, so that it maps to a PHP namespace. osdd:layer refuses any other name and writes nothing:
Invalid layer name [functional/My_Orders]. Use a Composer package name: vendor/package, in lowercase letters and digits, words separated by '-', '_' or '.' (functional/orders).
The name gives the namespace: each part is converted to PascalCase.
| Layer | Namespace | Service provider |
|---|---|---|
functional/orders | Functional\Orders | OrdersServiceProvider |
functional/external-accounts | Functional\ExternalAccounts | ExternalAccountsServiceProvider |
functional/sales.orders | Functional\SalesOrders | SalesOrdersServiceProvider |
technical/feature-flags | Technical\FeatureFlags | FeatureFlagsServiceProvider |
The vendor picks the bucket: osdd:layer functional/orders creates the layer in functional/. See Buckets.
Invalid composer.json files
A layer composer.json that OSDD cannot read is reported instead of breaking every command:
- invalid JSON, or a JSON value that is not an object;
- a missing or invalid
name; - an
autoload.psr-4,autoload-dev.psr-4,requireorrequire-devthat is not a map; - an
extra.laravel.providersthat is not a list of strings.
osdd:list shows the file with its error and keeps listing the valid layers. The generators, osdd:seed --layer, osdd:check, osdd:graph, osdd:phpunit and osdd:cache stop with exit code 1 and name the file:
Invalid layer manifest [functional/orders/composer.json]: it has no "name".
Registration
osdd:start and osdd:layer register each layer in the root composer.json:
{
"require": {
"functional/orders": "*",
"technical/osdd": "*"
},
"repositories": [
{ "type": "path", "url": "./functional/*" },
{ "type": "path", "url": "./technical/*" }
]
}
One path repository per folder covers every layer inside it. After composer update functional/orders, Composer symlinks the layer into vendor/ and Laravel discovers its service provider. Do not list layer providers in bootstrap/providers.php.
osdd:list shows each layer with its health: required in the root composer.json, covered by a path repository, installed, provider extending LayerServiceProvider, test suite in phpunit.xml.