Weave Code
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

Data Laravel Package

atk4/data

ATK Data is a PHP data model abstraction that separates business logic from UI and persistence. Works with SQL/NoSQL/APIs, supports relations, expressions, aggregation, and user actions with ACL metadata—integrates easily with ATK UI and ATK API.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require atk4/data
    

    Requires atk4/core as a dependency.

  2. Define a Basic Model:

    use Atk4\Data\Model;
    
    $db = new \Atk4\Data\Persistence\Sql('mysql:host=localhost;dbname=test', 'user', 'pass');
    $client = new Model($db);
    $client->addField('name');
    $client->addField('email');
    
  3. First Use Case:

    // Insert a record
    $client->insert(['name' => 'John Doe', 'email' => 'john@example.com']);
    
    // Fetch records with a condition
    $vipClients = $client->addCondition('is_vip', true)->getCollection();
    

Where to Look First


Implementation Patterns

Core Workflows

  1. Model Definition:

    class Client extends Model
    {
        protected function init(): void
        {
            parent::init();
            $this->addField('name');
            $this->addField('email');
            $this->addField('is_vip')->type('boolean');
        }
    }
    
    • Use init() for field definitions and relations.
    • Leverage field types (e.g., type('atk4_money')) for validation and formatting.
  2. Querying Data:

    $clients = (new Client($db))
        ->addCondition('is_vip', true)
        ->addOrder('name')
        ->getCollection();
    
    • Chain methods like addCondition(), addOrder(), and addJoin() for complex queries.
    • Use expressions for dynamic calculations:
      $client->addExpression('full_name', ['expr' => '[name] || \' \' || [surname]']);
      
  3. Relations:

    class Invoice extends Model
    {
        protected function init(): void
        {
            parent::init();
            $this->hasOne('client_id', ['model' => 'Client']);
            $this->addField('total')->type('atk4_money');
        }
    }
    
    • Define relations with hasOne(), hasMany(), or belongsTo().
    • Use lazy loading for related data:
      $invoice = (new Invoice($db))->load(1);
      $clientName = $invoice->ref('client_id')->getOne('name');
      
  4. Actions:

    $client->addAction('send_email', ['email' => 'john@example.com'])
        ->perform();
    
    • Define custom actions in init():
      $this->addAction('archive', ['confirm' => true]);
      
    • Use ACL (Access Control Lists) to restrict actions:
      $this->addAction('delete')->setPermission('admin');
      
  5. Integration with UI/API:

    // UI (Agile UI)
    Crud::addTo($app)->setModel(new Client($db), ['name', 'email']);
    
    // API (Agile API)
    $api->rest('/clients', new Client($db));
    
    • Pass models directly to UI components (e.g., Crud, Grid, Form).
    • For APIs, use Agile\Api to expose models as REST endpoints.

Laravel-Specific Patterns

  1. Service Provider Setup:

    // config/app.php
    'providers' => [
        Atk4\Laravel\Ad\AdServiceProvider::class,
    ],
    

    Install the Laravel AD package for seamless integration.

  2. Model Binding:

    // In a Laravel controller
    $client = app(Client::class)->setPersistence($db);
    

    Use dependency injection or the app() helper to resolve models.

  3. Query Builder Integration:

    $query = Client::query()->where('is_vip', true);
    

    Extend Laravel’s query builder with ATK Data methods via traits or macros.

  4. Middleware for ACL:

    // app/Http/Middleware/CheckPermission.php
    public function handle($request, Closure $next)
    {
        $model = app(Client::class);
        if (!$model->checkPermission($request->user(), 'edit')) {
            abort(403);
        }
        return $next($request);
    }
    
  5. Event Hooks:

    // Listen to model events (e.g., afterSave)
    $client->on('afterSave', function ($model) {
        Log::info("Client saved: " . $model->get('name'));
    });
    

Performance Tips

  1. Eager Loading:

    $client = (new Client($db))->load(1, ['invoice']);
    

    Load related data in a single query using load() with relation names.

  2. Batch Operations:

    $client->update(['is_vip' => true], ['id' => [1, 2, 3]]);
    

    Use bulk methods like update(), delete(), or insert() for efficiency.

  3. Persistence Caching:

    $db = new \Atk4\Data\Persistence\Sql('mysql:...');
    $db->setCache(new \Atk4\Data\Persistence\Cache\File());
    

    Enable caching for repeated queries (e.g., Redis or file-based).

  4. Aggregate Queries:

    $total = (new Client($db))
        ->action('fx', ['sum', 'total'])
        ->getOne();
    

    Offload aggregation to the database with action('fx', ['aggregate', 'field']).


Gotchas and Tips

Pitfalls

  1. Lazy Loading Overhead:

    • Avoid excessive lazy loading of relations in loops. Use getCollection() with load() or preload() for related data.
    • Example:
      $clients = (new Client($db))->getCollection(['invoice']);
      
  2. Permission Misconfiguration:

    • Forgetting to set permissions on actions can lead to security gaps. Always define ACL:
      $this->addAction('delete')->setPermission('admin');
      
  3. Expression Syntax Errors:

    • ATK Data uses a SQL-like expression syntax. Test expressions in your database client first.
    • Example of a common mistake:
      // Wrong: Missing brackets
      $this->addExpression('profit', ['expr' => '[revenue] - cost']);
      
      // Correct:
      $this->addExpression('profit', ['expr' => '[revenue] - [cost]']);
      
  4. Circular References:

    • Infinite loops can occur with bidirectional relations (e.g., hasOne + belongsTo). Use ->setLazy() to disable eager loading for one side:
      $this->hasOne('client_id', ['model' => 'Client'])->setLazy();
      
  5. Persistence-Specific Quirks:

    • Not all persistence backends support the same features (e.g., action('fx') may not work with NoSQL). Check the persistence documentation.

Debugging Tips

  1. Enable SQL Logging:

    $db->setDebug(true);
    

    Logs all generated SQL queries to storage/logs/atk4-data.log.

  2. Inspect Model Structure:

    echo $model->dump();
    

    Outputs the model’s fields, relations, and conditions for debugging.

  3. Use getOne() vs getCollection():

    • getOne() returns a single value (e.g., sum(total)).
    • getCollection() returns an array of records. Mixing them can cause type errors.
  4. Handle Exceptions:

    try {
        $model->perform('delete');
    } catch (\Atk4\Data\Exception\Validation $e) {
        echo $e->getMessage();
    }
    

    Catch Validation exceptions for failed actions or data issues.


Extension Points

  1. Custom Field Types:
    class CustomField extends \Atk4\Data\Field
    {
        public function validate($value)
        {
            return $value === 'expected';
        }
    }
    
    Extend `\Atk4\Data\
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.
babenkoivan/elastic-client
innmind/static-analysis
innmind/coding-standard
datacore/hub-sdk
alengo/sulu-http-cache-bundle
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity