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

Api Model Laravel Package

outrightvision/api-model

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use

  1. Installation:

    composer require outrightvision/api-model
    

    No additional configuration is required—just start using the package.

  2. Create Your First Model: Define a model class extending OUTRIGHTVision\ApiModel:

    // app/Api/Models/User.php
    namespace App\Api\Models;
    use OUTRIGHTVision\ApiModel;
    
    class User extends ApiModel {}
    
  3. Instantiate with API Data: Pass raw API response data to the model:

    $userData = json_decode(file_get_contents('api-response.json'), true);
    $user = new User($userData['data']);
    echo $user->name; // Access properties directly
    
  4. Basic Relationship Casting: Define $cast_model to auto-cast nested objects:

    class User extends ApiModel {
        protected $cast_model = [
            'company' => Company::class,
            'posts'  => Post::class,
        ];
    }
    

    Now access relationships like Eloquent:

    echo $user->company->name; // "Romaguera-Crona"
    

First Use Case: Quick API Wrapper

Use this package to rapidly wrap a third-party API or expose legacy data as Laravel-like models. Example:

// Fetch data from an external API
$response = Http::get('https://jsonplaceholder.typicode.com/users/1');
$user = new User($response->json()['data']);

// Use relationships
echo $user->company->catchPhrase; // "Multi-layered client-server neural-net"

Implementation Patterns

Core Workflows

1. Model Definition

  • Standard Models: Extend ApiModel and define $cast_model for nested objects:

    class User extends ApiModel {
        protected $cast_model = [
            'address' => Address::class,
            'company' => Company::class,
        ];
    }
    
  • Dynamic Casting: Use get_data() helper for dot/arrow notation access:

    $lat = get_data($user, 'company.geo->lat'); // "-35.3159"
    

2. Relationships

  • Single Relationships (belongsTo/hasOne): Define methods to lazy-load relationships:

    class User extends ApiModel {
        public function company() {
            return $this->belongsTo(Company::class, 'company');
        }
    }
    

    Access via $user->company (lazy-loaded).

  • HasMany Relationships: Cast collections and eager-load with included_default:

    class User extends ApiModel {
        protected $included_default = ['posts'];
    
        public function posts() {
            return $this->hasMany(Post::class, 'posts');
        }
    }
    

3. Data Transformation

  • Custom Date Handling: Override $cast_dates to change default Carbon parsing:

    class User extends ApiModel {
        protected $cast_dates = ['created_at' => 'Y-m-d H:i:s'];
    }
    
  • Required Parameters: Enforce validation via $requiredParameters:

    class User extends ApiModel {
        protected $requiredParameters = ['id', 'email'];
    }
    

4. Integration with Laravel

  • API Resources: Convert ApiModel to Laravel’s ApiResource for responses:

    use Illuminate\Http\Resources\Json\JsonResource;
    
    class UserResource extends JsonResource {
        public function toArray($request) {
            return (new User($this->resource))->toArray();
        }
    }
    
  • Service Providers: Bind models to the container for dependency injection:

    $this->app->bind('api.user', function () {
        return new User($this->fetchApiData());
    });
    

Best Practices

  1. Modularize Models: Group models under App\Api\Models and use namespaces for clarity. Example:

    /app
      /Api
        /Models
          User.php
          Company.php
          Post.php
    
  2. Lazy-Loading Strategy: Avoid eager-loading relationships unless necessary (default behavior is lazy).

  3. Type Safety: Use PHP 8’s constructor property promotion for stricter typing:

    class User extends ApiModel {
        public function __construct(
            public int $id,
            public string $name,
            public array $data
        ) {
            parent::__construct($data);
        }
    }
    
  4. Testing: Mock API responses in tests:

    $mockData = ['data' => ['id' => 1, 'name' => 'Test']];
    $user = new User($mockData);
    $this->assertEquals('Test', $user->name);
    

Gotchas and Tips

Pitfalls

  1. Relationships Not Auto-Discovered:

    • Issue: Defining $cast_model does not automatically create relationship methods.
    • Fix: Explicitly define belongsTo/hasMany methods for lazy-loading:
      public function company() {
          return $this->belongsTo(Company::class, 'company');
      }
      
  2. Date Parsing Overhead:

    • Issue: Default Carbon::parse() may slow down high-frequency API calls.
    • Fix: Disable date casting or customize $cast_dates:
      protected $cast_dates = []; // Disable all date casting
      
  3. Nested Relationships:

    • Issue: Deeply nested relationships (e.g., user->company->geo) may cause performance issues if not lazy-loaded.
    • Fix: Use get_data() for one-off accesses:
      $lat = get_data($user, 'company.geo->lat');
      
  4. Circular References:

    • Issue: Bidirectional relationships (e.g., User->Company and Company->Users) can cause infinite loops.
    • Fix: Avoid circular $cast_model definitions or use get_data() for safe access.
  5. Timezone Mismatches:

    • Issue: Default date_timezone may not match your application’s timezone.
    • Fix: Set it explicitly:
      protected $date_timezone = 'America/New_York';
      

Debugging Tips

  1. Inspect Raw Data: Use dd($this->attributes) in a model’s __construct to verify data structure.

  2. Check Casting Logic: Override castAttribute() to debug casting:

    protected function castAttribute($key, $value) {
        if ($key === 'company' && !($value instanceof Company)) {
            dd("Company not casted: ", $value);
        }
        return parent::castAttribute($key, $value);
    }
    
  3. Lazy-Loading Debugging: Add a debug() method to track relationship loading:

    public function debug() {
        echo "Relationships: " . print_r($this->relationships, true);
    }
    

Extension Points

  1. Custom Casting: Extend ApiModel to add custom type casting:

    class User extends ApiModel {
        protected $casts = [
            'is_active' => 'boolean',
            'score'     => 'float',
        ];
    }
    
  2. Hooks for API Calls: Override fetch() to intercept API requests:

    protected function fetch($url) {
        $this->logRequest($url);
        return parent::fetch($url);
    }
    
  3. Global Configuration: Set defaults in a service provider:

    ApiModel::setDefaultTimezone('UTC');
    ApiModel::disableDateCasting();
    
  4. Custom Helpers: Extend get_data() for project-specific needs:

    function get_data_with_default($data, $path, $default = null) {
        return get_data($data, $path) ?? $default;
    }
    

Performance Optimizations

  1. Disable Unused Features:

    class User extends ApiModel {
        protected $cast_model = []; // Disable all casting
        protected $cast_dates = []; // Disable date parsing
    }
    
  2. Cache Relationships: Manually cache loaded relationships:

    if (!$this->relationships['company']) {
        $this->relationships['company'] = new Company($this->company);
    }
    
  3. Batch Loading: For hasMany, fetch all data at once:

    $posts = collect($this->posts['data'])->map(fn($post) => new Post($post));
    
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.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity