Skip to content

Latest commit

 

History

History
391 lines (283 loc) · 10.3 KB

File metadata and controls

391 lines (283 loc) · 10.3 KB

Model Loading

This guide explains how the model loading system works in EasyAPP and the different ways you can access loaded models.


Table of Contents

  1. Overview
  2. Loading Patterns
  3. How It Works
  4. Best Practices
  5. Examples

Overview

EasyAPP provides a flexible model loading system that supports multiple access patterns. When you load a model, it is:

  1. Instantiated - The model class is created with the registry
  2. Returned - The instance is returned to you directly
  3. Registered - The instance is automatically registered in the registry for magic access

This dual behavior gives you maximum flexibility in how you work with models.


Loading Patterns

Pattern 1: Explicit Variable (Recommended)

Capture the returned instance in a variable:

$userModel = $this->load->model('user');
$users = $userModel->getAll();
$user = $userModel->getById(1);

Advantages:

  • Clear and explicit
  • Easy to understand
  • Good for multiple method calls
  • Better for code completion in IDEs

Use When:

  • You need multiple method calls on the same model
  • Working in complex logic
  • Code clarity is important
  • Teaching/documenting code

Pattern 2: Magic Access (Auto-Registered)

Use the magic property access via registry:

$this->load->model('user');
$users = $this->model_user->getAll();
$user = $this->model_user->getById(1);

Advantages:

  • Concise syntax
  • No variable declaration needed
  • Familiar to users of other frameworks

Use When:

  • Quick one-time access
  • Prefer shorter syntax
  • Already familiar with this pattern

Pattern 3: Method Chaining (Immediate)

Load and use immediately in one line:

$users = $this->load->model('user')->getAll();
$user = $this->load->model('user')->getById(1);

Advantages:

  • Most concise
  • One-liner operations
  • No variable pollution

Use When:

  • Single method call needed
  • One-time operations
  • Functional programming style

How It Works

The Loading Process

When you call $this->load->model('user'), the framework:

  1. Resolves the path - Converts 'user' to app/model/user.php
  2. Checks cache - Returns cached instance if already loaded
  3. Includes the file - Requires the model file if not loaded
  4. Instantiates the model - Creates instance: new ModelUser($registry)
  5. Caches the instance - Stores in internal cache for reuse
  6. Registers in registry - Sets in registry with key 'user'
  7. Returns the instance - Returns model object to caller

Registry Key Generation

The registry key is generated by adding model_ prefix and replacing slashes with underscores:

$registryKey = 'model_' . str_replace('/', '_', $sanitizedRoute);

Examples:

  • 'user' → Registry key: 'model_user' → Access: $this->model_user
  • 'common/helper' → Registry key: 'model_common_helper' → Access: $this->model_common_helper
  • 'admin/user' → Registry key: 'model_admin_user' → Access: $this->model_admin_user

Magic Method Access

Models registered in the registry are accessible via magic __get() method:

class Controller {
    public function __get($key) {
        return $this->registry->get($key);
    }
}

// When you access $this->model_user
// It calls $this->__get('model_user')
// Which calls $this->registry->get('model_user')
// Which returns the registered model instance

Best Practices

When to Use Each Pattern

class ControllerUser extends Controller {
    
    // Pattern 1: Multiple operations (RECOMMENDED)
    public function index() {
        $userModel = $this->load->model('user');
        $users = $userModel->getAll();
        $count = $userModel->count();
        $active = $userModel->getActive();
        
        $data = [
            'users' => $users,
            'count' => $count,
            'active' => $active
        ];
        
        $this->response->setOutput($this->load->view('user/list.html', $data));
    }
    
    // Pattern 2: Quick single access
    public function delete() {
        $userId = $this->request->get('id');
        
        $this->load->model('user');
        if ($this->model_user->delete($userId)) {
            $this->response->json(['success' => true]);
        }
    }
    
    // Pattern 3: One-liner
    public function count() {
        $count = $this->load->model('user')->count();
        $this->response->json(['count' => $count]);
    }
}

Consistency

Choose one primary pattern for your project and stick with it:

// ✓ GOOD: Consistent use of Pattern 1
class ControllerProduct extends Controller {
    
    public function index() {
        $productModel = $this->load->model('product');
        $products = $productModel->getAll();
    }
    
    public function view() {
        $productModel = $this->load->model('product');
        $product = $productModel->getById($this->request->get('id'));
    }
}

// ✗ AVOID: Mixing patterns unnecessarily
class ControllerProduct extends Controller {
    
    public function index() {
        $products = $this->load->model('product')->getAll(); // Pattern 3
    }
    
    public function view() {
        $this->load->model('product'); // Pattern 2
        $product = $this->product->getById($this->request->get('id'));
    }
}

Constructor Initialization

For frequently used models, load in constructor:

class ControllerUser extends Controller {
    
    private $userModel;
    
    public function __construct($registry) {
        parent::__construct($registry);
        
        // Load once, use everywhere
        $this->userModel = $this->load->model('user');
    }
    
    public function index() {
        $users = $this->userModel->getAll();
    }
    
    public function view() {
        $user = $this->userModel->getById($this->request->get('id'));
    }
}

Examples

Basic CRUD Controller

class ControllerProduct extends Controller {
    
    public function index() {
        // Load model and get all products
        $productModel = $this->load->model('product');
        $products = $productModel->getAll();
        
        $data['products'] = $products;
        $this->response->setOutput($this->load->view('product/list.html', $data));
    }
    
    public function view() {
        $id = $this->request->get('id');
        
        // One-liner for single use
        $product = $this->load->model('product')->getById($id);
        
        if (!$product) {
            $this->response->redirect('/404');
            return;
        }
        
        $data['product'] = $product;
        $this->response->setOutput($this->load->view('product/view.html', $data));
    }
    
    public function create() {
        if ($this->request->server('REQUEST_METHOD') === 'POST') {
            $productData = $this->request->post;
            
            // Magic access for quick operation
            $this->load->model('product');
            $productId = $this->model_product->create($productData);
            
            $this->response->redirect('/product/view?id=' . $productId);
            return;
        }
        
        $this->response->setOutput($this->load->view('product/form.html'));
    }
}

Model Loading Other Models

class ModelOrder extends Model {
    
    public function getWithDetails($orderId) {
        // Get order
        $order = $this->getById($orderId);
        
        if (!$order) {
            return null;
        }
        
        // Load related models
        $userModel = $this->load->model('user');
        $orderItemModel = $this->load->model('order_item');
        
        // Get related data
        $order['user'] = $userModel->getById($order['user_id']);
        $order['items'] = $orderItemModel->getByOrderId($orderId);
        
        return $order;
    }
}

Service Using Models

class ServiceOrderService extends Service {
    
    public function processOrder($orderData) {
        // Load models in constructor or method
        $orderModel = $this->load->model('order');
        $inventoryModel = $this->load->model('inventory');
        $paymentModel = $this->load->model('payment');
        
        try {
            // Check inventory
            foreach ($orderData['items'] as $item) {
                if (!$inventoryModel->checkAvailability($item['product_id'], $item['quantity'])) {
                    throw new Exception('Product not available');
                }
            }
            
            // Create order
            $orderId = $orderModel->create($orderData);
            
            // Process payment
            $paymentModel->process($orderId, $orderData['payment']);
            
            // Update inventory
            $inventoryModel->reserve($orderData['items']);
            
            return $orderId;
            
        } catch (Exception $e) {
            $this->logger->error('Order processing failed: ' . $e->getMessage());
            throw $e;
        }
    }
}

Subdirectory Models

class ControllerAdmin extends Controller {
    
    public function dashboard() {
        // Load models from subdirectories
        $statsModel = $this->load->model('admin/stats');
        $reportModel = $this->load->model('admin/report');
        
        $data['stats'] = $statsModel->getDashboard();
        $data['reports'] = $reportModel->getRecent();
        
        // OR with magic access
        $this->load->model('admin/stats');
        $this->load->model('admin/report');
        
        $data['stats'] = $this->model_admin_stats->getDashboard();
        $data['reports'] = $this->model_admin_report->getRecent();
        
        $this->response->setOutput($this->load->view('admin/dashboard.html', $data));
    }
}

Summary

The model loading system in EasyAPP provides three patterns for maximum flexibility:

  1. Explicit Variable - $model = $this->load->model('name') - Recommended for clarity
  2. Magic Access - $this->load->model('name'); $this->model_name->method() - Concise syntax
  3. Method Chaining - $this->load->model('name')->method() - One-liners

All patterns work because the framework both returns the instance AND registers it in the registry with the model_ prefix.

Choose the pattern that best fits your coding style and project requirements, and use it consistently throughout your codebase.