Loading Modules From Models
Most of the time, model files only need database access. That's their job.
But sometimes you need a model to use another module - email sending, file processing, API calls, payment gateways, etc.
Trongate v2 lets you do this explicitly with $this->module().
Heads up: This is an edge case. Most models won't need to load and use other modules. If you're just using your model files for database queries, you can skip this page entirely.
The Syntax
To use a module from within a model file, explicitly load it first:
<?php
// In Users_model.php
class Users_model extends Model {
public function send_welcome_email($user) {
// Load the email module
$this->module('email_sender');
// Now use it
$this->email_sender->send(
$user->email,
'Welcome to Our Site!',
$this->build_message($user)
);
}
private function build_message($user) {
return "Hello {$user->name}, welcome aboard!";
}
}That's it. Call $this->module('whatever') before using $this->whatever.
Database vs. Module: The Key Difference
There's an important distinction to understand:
Database Access (No module() call needed)
// These work automatically - no module() call required
$users = $this->db->get('id', 'users'); // default database
$stats = $this->analytics->get('page_views'); // analytics database
$stock = $this->warehouse->get_where(42, 'items'); // warehouse databaseModule Usage (Requires explicit loading)
// Must call module() first
$this->module('tax');
$total = $this->tax->calculate($amount);
$this->module('payment_processor');
$this->payment_processor->charge($customer, $amount);Why the difference? Database groups are defined in config/database.php, so Trongate knows they're databases. Modules must be explicitly loaded to signal your intent to use a module rather than access a database.
Complete Example
Here's a realistic scenario: processing an order that requires database queries, tax calculation, and email sending.
<?php
class Orders_model extends Model {
public function process_order($order_id) {
// 1. Fetch order from database (automatic)
$order = $this->db->get_where($order_id, 'orders');
if (!$order) {
return false;
}
// 2. Calculate tax using Tax module (requires loading)
$this->module('tax');
$tax_amount = $this->tax->calculate($order->subtotal, $order->state);
// 3. Update order total in database (automatic)
$update_data = [
'tax_amount' => $tax_amount,
'total' => $order->subtotal + $tax_amount,
'processed_at' => time()
];
$this->db->update($order_id, $update_data, 'orders');
// 4. Send confirmation email (requires loading)
$this->module('email_sender');
$this->email_sender->send(
$order->customer_email,
'Order Confirmation',
$this->build_confirmation_email($order, $tax_amount)
);
// 5. Log to analytics database (automatic)
$analytics_data = [
'order_id' => $order_id,
'amount' => $update_data['total'],
'timestamp' => time()
];
$this->analytics->insert($analytics_data, 'order_events');
return true;
}
private function build_confirmation_email($order, $tax_amount) {
$message = "Thank you for your order #" . $order->id . "\n\n";
$message .= "Subtotal: $" . number_format($order->subtotal, 2) . "\n";
$message .= "Tax: $" . number_format($tax_amount, 2) . "\n";
$message .= "Total: $" . number_format($order->subtotal + $tax_amount, 2);
return $message;
}
}In this example:
$this->dbworks automatically (default database)$this->analyticsworks automatically (configured database group)$this->taxrequires$this->module('tax')first$this->email_senderrequires$this->module('email_sender')first
Loading Multiple Modules
If you need several modules, load them all at the start of your method for clarity:
public function complex_operation($data) {
// Load all required modules upfront
$this->module('tax');
$this->module('email_sender');
$this->module('payment_processor');
$this->module('inventory');
// Now use them
$tax = $this->tax->calculate($data['amount']);
$this->payment_processor->charge($data['customer'], $tax);
// ... etc
}Common Use Cases
You'll typically need $this->module() in models when:
- Sending emails after database operations
- Processing payments and updating order records
- Calling external APIs based on database data
- Generating PDFs or files from database content
- Complex calculations that live in separate modules (tax, shipping, discounts)
- Logging or notifications after data changes
Keep it simple: If your model is loading 5+ modules, consider whether some logic belongs in the controller instead. Models should focus on data operations.
What About Controllers?
Controllers work differently. They support both explicit and automatic module loading:
// In a controller - both styles work:
// Style 1: Explicit (optional)
$this->module('tax');
$total = $this->tax->calculate($amount);
// Style 2: Automatic (recommended in v2)
$total = $this->tax->calculate($amount); // loads automaticallyIn models, you must use explicit $this->module() calls. This keeps the distinction clear: databases are automatic, modules are explicit.
Troubleshooting
Error: "Undefined property: Model::$something"
You tried to use a module without loading it first.
Fix: Add $this->module('something') before using $this->something.
Error: "Module controller not found"
The module doesn't exist or isn't named correctly.
Check:
- Module directory exists:
modules/whatever/ - Controller file exists:
modules/whatever/Whatever.php - Class name matches:
class Whatever extends Trongate
Best Practices
- Load modules at the start of your method for clarity
- Database access never needs
module()calls - If you forget to load a module, the error message will remind you
- Keep models focused on data - don't turn them into mini-applications
- When in doubt, put complex orchestration in the controller
We're continually improving the Trongate documentation. If anything is incorrect, unclear, incomplete, or could be better, we'd genuinely appreciate your input.
Share your thoughts in the Documentation Feedback.