Contracts¶
Contracts are interfaces you type-hint in your constructor. The DI container resolves the concrete implementation automatically.
use local_middag\framework\contract\command_bus_interface;
class my_service extends \local_middag\base\service
{
public function __construct(
private readonly command_bus_interface $bus,
) {}
}
All contracts listed on this page are classified Group A (@api) and follow SemVer evolution policy.
Cross-cutting contracts¶
Commonly injected by any extension:
| Interface | Purpose | Example |
|---|---|---|
command_bus_interface |
Dispatch commands (sync/async) | $bus->handle(new my_command(...)) |
dispatcher_interface |
Publish typed signals | $dispatcher->dispatch($signal) |
item_service_interface |
CRUD operations on items | $items->create($type, $data) |
item_repository_interface |
Direct repository access | $repo->find($id) |
form_request_interface |
Declarative input validation | Auto-injected before controller executes |
job_service_interface |
Async job governance | $jobs->create($command, $correlationId) |
Psr\Log\LoggerInterface |
PSR-3 logging | $logger->warning('msg', $context) |
Core Capability contracts (ADR-607)¶
The framework exposes 6 Core Capabilities (CCs) as bounded contexts. Each CC provides one or more @api contracts that extensions consume via DI. CCs live in local_middag\framework\contract\.
Overview¶
| CC | Domain | Primary contract(s) | Extension point | Facade |
|---|---|---|---|---|
| CC-02 | core.connectors |
connector_interface, connector_registry_interface |
-- | -- |
| CC-03 | core.workflow |
workflow_action_interface, workflow_registry_interface |
-- | -- |
| CC-06 | core.instancegroup |
instancegroup_interface |
-- | -- |
| CC-07 | core.segments |
segments_interface |
criteria_provider_interface |
-- |
| CC-08 | core.compliance |
compliance_interface |
-- | -- |
| CC-09 | core.conditions |
conditions_interface |
condition_provider_interface |
-- |
CCs do not have dedicated facades. Consume them exclusively via constructor injection.
CC-02 -- Connectors¶
Catalog of external service connection types. Manages credentials, health checks, and per-extension binding. Extensions that integrate with third-party APIs (e.g. Twilio, BigQuery) implement connector_interface and register via connector_registry_interface during register().
CC-03 -- Workflow¶
Discrete work actions triggered by forms, events, or scheduled tasks. The workflow engine evaluates triggers and dispatches the matching action. Extensions implement workflow_action_interface and register via workflow_registry_interface during boot().
CC-06 -- Instance Group¶
Logical grouping and versioning of courses/resources. Extensions reference groups instead of individual courses, enabling course equivalence, re-enrolment, and progression logic. Consumed through instancegroup_interface.
CC-07 -- Segments¶
Rule-based audience segmentation engine. Segments return SQL subqueries (not materialized lists) for composability and performance at scale. Extensions add custom criteria types by implementing criteria_provider_interface and registering during boot().
CC-08 -- Compliance¶
Profile compliance verification against a Moodle context. Checks whether a user meets all mandatory profile requirements. When no provider is registered, consumers treat users as compliant (graceful degradation). Consumed through compliance_interface.
CC-09 -- Conditions¶
Inclusion/exclusion rule engine evaluated against Moodle contexts (categories, courses, activity types). Works like display conditions in page builders. Extensions add custom condition types by implementing condition_provider_interface and registering during boot().
How to consume¶
Type-hint the contract in your constructor. The container resolves it:
use local_middag\framework\contract\segments_interface;
use local_middag\framework\contract\compliance_interface;
class my_service extends \local_middag\base\service
{
public function __construct(
private readonly segments_interface $segments,
private readonly compliance_interface $compliance,
) {}
}
When a CC provider may not be available, check before consuming:
if (!$this->container->has(compliance_interface::class)) {
return true; // No provider -- treat as compliant.
}
For detailed method signatures, value objects, and code examples for each CC, see Core Capabilities.
Boundary contracts (Moodle)¶
Implemented by extensions to integrate with Moodle subsystems:
| Interface | When to implement |
|---|---|
privacy_provider_interface |
Extension stores personal data (GDPR) |
backup_steps_provider_interface |
Extension participates in backup/restore |
file_area_handler_interface |
Extension manages files via Moodle File API |
Attributes¶
| Attribute | Where to use |
|---|---|
#[item_type('slug:type')] |
On an entity class to declare an item type |
#[schedule('0 * * * *')] |
On an extension method to schedule periodic execution |
#[on('middag/item/created')] |
On a subscriber method for auto-discovery of hooks |
Moodle traditional vs MIDDAG¶
| Aspect | Moodle traditional | MIDDAG |
|---|---|---|
| Dependency injection | new my_class() or manual factory |
Type-hint in constructor, container resolves |
| Logging | debugging('msg', DEBUG_DEVELOPER) |
LoggerInterface via DI |
| Backup/Restore | Implement backup_*_stepslib.php by hand |
backup_steps_provider_interface with typed definitions |
| Privacy | provider.php with static methods |
privacy_provider_interface with repository delegation |
Cross-references¶
- Core Capabilities -- full method signatures and code examples for each CC
- API Classification -- Group A/B/C rules and inventory
- Base Classes -- extension, service, controller base classes
- ADR-607 -- Core subdomain model
- ADR-601 -- Container and dependency injection
- ADR-602 -- Extension lifecycle (register/boot/compile)