atk4/core
Agile Core is a set of reusable PHP traits for building object-oriented frameworks. Provides containers (parent/child), hooks with priorities, automatic init, dynamic methods, factory by class string, app scope injection, and improved exceptions.
Installation:
composer require atk4/core
Add to composer.json if using Laravel:
"require": {
"atk4/core": "^6.0"
}
First Use Case:
Use HookTrait to add event-driven behavior to a Laravel service or model:
use Atk4\Core\HookTrait;
class UserService
{
use HookTrait;
public function __construct()
{
$this->addHook('beforeSave', function($user) {
// Pre-save logic
});
}
}
Key Entry Points:
HookTrait, ContainerTrait, FactoryTrait).src/Atk4/Core/ for trait implementations.class OrderProcessor
{
use HookTrait;
public function process(Order $order)
{
$this->callHook('validate', [$order]);
$this->callHook('preSave', [$order]);
$order->save();
}
}
boot() methods of service providers:public function boot()
{
$this->app->make(OrderProcessor::class)
->addHook('validate', function($order) {
if ($order->isInvalid()) {
throw new \Exception("Invalid order");
}
});
}
DiContainerTraitclass UserRepository
{
use DiContainerTrait;
public function __construct()
{
$this->setDefault('db', \DB::connection('mysql'));
}
}
assertInstanceOf() to enforce type safety:$this->assertInstanceOf(\Illuminate\Database\Connection::class, $this->get('db'));
class User extends \Illuminate\Database\Eloquent\Model
{
use DynamicMethodTrait;
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->addDynamicMethod('getFullName', function() {
return "{$this->first_name} {$this->last_name}";
});
}
}
Order ↔ OrderItem):class Order
{
use ContainerTrait;
protected $items = [];
public function addItem(OrderItem $item)
{
$this->addChild($item);
}
}
addChild() in afterCreate() hooks:public static function afterCreate(Order $order)
{
$order->addChild(new OrderItem(['product_id' => 1]));
}
class UserFactory
{
use FactoryTrait;
protected $seeds = [
'admin' => ['role' => 'admin'],
'guest' => ['role' => 'guest']
];
}
$this->app->singleton(UserFactory::class, function() {
return new UserFactory();
});
Atk4\Core\Exception for richer debugging:try {
$user->save();
} catch (\Atk4\Core\Exception $e) {
report($e->getTraceAsString()); // HTML-friendly trace
}
Exception::render() in Laravel’s App\Exceptions\Handler:public function render($request, Throwable $exception)
{
if ($exception instanceof \Atk4\Core\Exception) {
return response($exception->render(), 500);
}
return parent::render($request, $exception);
}
Hook Priorities Collisions:
100, 200).$this->addHook('beforeSave', $callback, 100);
Circular Dependencies in Containers:
ContainerTrait throws CircularDependencyException if parent-child cycles exist.$order->assertNoCircularDependencies();
Dynamic Methods Overwriting:
hasMethod() to check:if (!$this->hasMethod('getFullName')) {
$this->addDynamicMethod('getFullName', ...);
}
Factory Seed Conflicts:
$factory->mergeSeeds(['user' => ['id' => 1]], true); // Force overwrite
PHP 8.2+ Strict Typing:
NameTrait) enforce strict types for properties like $name.#[Assert\Type('string')]
protected string $name;
Exception Rendering in CLI:
Exception::render('text'):echo $e->render('text');
Hook Debugging:
$this->setHookDebug(true);
print_r($this->getHooks('beforeSave'));
Container Inspection:
print_r($this->getChildren());
var_dump($this->getParent());
Dynamic Method Introspection:
print_r($this->getDynamicMethods());
Factory Seed Inspection:
print_r($this->getSeeds());
Custom Exception Renderers:
ExceptionRenderer to add Laravel-specific formatting:class LaravelExceptionRenderer extends \Atk4\Core\ExceptionRenderer
{
public function render(Throwable $e, string $format = 'html')
{
if ($format === 'laravel') {
return view('errors.atk4', ['exception' => $e]);
}
return parent::render($e, $format);
}
}
Hook Middleware:
class HookMiddleware
{
public function handle($request, Closure $next)
{
$response = $next($request);
$this->app->make(OrderProcessor::class)->callHook('postRequest');
return $response;
}
}
Trait Composition:
HookTrait + DiContainerTrait):class EventDispatcher
{
use HookTrait, DiContainerTrait;
public function __construct()
{
$this->setDefault('logger', \Log::getMonolog());
}
}
Laravel Service Provider Integration:
public function register()
{
$this->app->bind('hookable', function() {
return new class {
use HookTrait;
};
});
}
Hook Overhead:
callHookSilent() to bypass priority sorting for non-critical hooks.Dynamic Methods:
__call() or HandleDynamicProperties.3
How can I help you explore Laravel packages today?