Models
Models are the heart of your application's data layer. They represent database tables and provide an expressive, object-oriented interface for interacting with your data. The Ecommerce\Core\Database\Query\Model class encapsulates table naming, attribute handling, relationships, and persistence.
Core Methods
The following methods are available on all models extending the base Model class.
All Records
Retrieve all records for the model.
Description:
The all() method returns a collection of all records in the model's table. It is equivalent to running a SELECT * query without constraints.
Method Signature:
public static function all(array|mixed $columns = ['*']): Collection
Parameters:
$columns- (Optional) Array of columns to select. Defaults to all columns.
Examples:
use Ecommerce\Models\Product;
// Get all products
$products = Product::all();
foreach ($products as $product) {
echo $product->name;
}
// Get specific columns
$products = Product::all(['id', 'name', 'price']);
Find Record
Retrieve a single model instance by its primary key.
Description:
The find() method retrieves a record by its primary key (usually id). If the record is found, it returns a hydrated model instance; otherwise, it returns null.
Method Signature:
public static function find(int $id): ?Model
Parameters:
$id- The primary key value to search for.
Examples:
// Find product with ID 1
$product = Product::find(1);
if ($product) {
echo $product->name;
}
Create Record
Create and persist a new model instance.
Description:
The create() method creates a new model instance, assigns the provided attributes, and saves it to the database in a single operation. It adheres to the model's fillable or guarded property configuration for mass assignment protection.
Method Signature:
public static function create(array $attributes): Model
Parameters:
$attributes- Associative array of attributes to assign.
Examples:
// Create a new product
$product = Product::create([
'name' => 'New T-Shirt',
'sku' => 'TS-001',
'price' => 2999,
'stock' => 100
]);
echo $product->id; // The new ID is available immediately
Save Model
Persist the model to the database.
Description:
The save() method inserts the model into the database if it's new, or updates the existing record if it already exists. It automatically manages created_at and updated_at timestamps if enabled.
Method Signature:
public function save(): bool
Examples:
// Create a new instance and save
$product = new Product();
$product->name = 'Yellow Scarf';
$product->price = 1500;
$product->save();
// Update an existing instance
$product = Product::find(1);
$product->price = 1200;
$product->save();
Update Model
Update attributes and persist changes.
Description:
The update() method fills the model with the given attributes and saves it. This is a convenient shortcut for fill() followed by save().
Method Signature:
public function update(array $attributes = []): bool
Parameters:
$attributes- Associative array of attributes to update.
Examples:
$product = Product::find(1);
// Update specific fields
$product->update([
'price' => 1800,
'stock' => 50
]);
Delete Model
Delete the model's record from the database.
Description:
The delete() method removes the record associated with the model instance from the database.
Method Signature:
public function delete(): bool
Examples:
$product = Product::find(1);
if ($product) {
$product->delete();
}
Destroy Records
Delete one or more models by primary key.
Description:
The destroy() method deletes records by their primary key without retrieving the model instances first (unless model events are needed, though currently implementation fetches models first).
Method Signature:
public static function destroy(mixed $ids): int
Parameters:
$ids- Single ID, array of IDs, or list of IDs.
Examples:
// Delete single record
Product::destroy(1);
// Delete multiple records
Product::destroy([1, 2, 3]);
// Delete multiple records (variadic)
Product::destroy(1, 2, 3);
Fill Attributes
Mass assign attributes to the model.
Description:
The fill() method assigns an array of attributes to the model. It filters out any attributes that are not in the fillable array or are in the guarded array, protecting against mass assignment vulnerabilities.
Method Signature:
public function fill(array $attributes): Model
Parameters:
$attributes- Associative array of attributes to assign.
Examples:
$product = new Product();
// Safely fill attributes
$product->fill([
'name' => 'Blue Jeans',
'price' => 4500,
'is_admin' => true, // Ignored if not fillable
]);
Load Relationships
Eager load relationships onto an existing model instance.
Description:
The load() method eager loads relationships for a model that has already been retrieved. This helps resolve the N+1 query problem when you decide to access relationships after the initial query.
Method Signature:
public function load(mixed $relations): Model
Parameters:
$relations- Relation name string or array of relation names.
Examples:
$product = Product::find(1);
// Later in the code, load variants
$product->load('variants');
// Load multiple relations
$product->load(['variants', 'images']);
Fresh Instance
Reload the model instance from the database.
Description:
The fresh() method retrieves a fresh instance of the model from the database. The existing model instance is not affected.
Method Signature:
public function fresh(array|string $with = []): ?Model
Parameters:
$with- (Optional) Relations to eager load on the fresh instance.
Examples:
$product = Product::find(1);
// ... some external process updates the database ...
// Get a fresh copy with updated data
$freshProduct = $product->fresh();
Refresh Instance
Refresh the current model instance from the database.
Description:
The refresh() method re-hydrates the existing model instance with fresh data from the database. It also resets any loaded relationships.
Method Signature:
public function refresh(): Model
Examples:
$product = Product::find(1);
// ... perform operations ...
// Refresh attributes in-place
$product->refresh();
Mass Assignment
Mass assignment allows you to send an array of data to the model creation or update methods. However, to protect your application from security vulnerabilities, you must define which attributes are assignable.
Fillable Attributes
To whitelist attributes that can be mass assigned, use the $fillable property.
Description:
The $fillable property specifies which attributes allowed to be mass assigned.
Methods:
Get Fillable Attributes
public function get_fillable(): array
Set Fillable Attributes
public function fillable(array $fillable): static
Merge Fillable Attributes
public function merge_fillable(array $fillable): static
Examples:
class Product extends Model
{
protected $fillable = ['name', 'price', 'description'];
}
// In usage
$product = new Product();
$product->fillable(['name', 'price']); // Dynamically set fillable
Guarded Attributes
Alternatively, you can blacklist attributes using the $guarded property.
Description:
The $guarded property specifies which attributes are NOT allowed to be mass assigned. Use ['*'] to protect all attributes.
Methods:
Get Guarded Attributes
public function get_guarded(): array
Set Guarded Attributes
public function guard(array $guarded): static
Merge Guarded Attributes
public function merge_guarded(array $guarded): static
Unguard Attributes
Temporarily disable mass assignment protection.
public static function unguard(bool $state = true): void
Reguard Attributes
Re-enable mass assignment protection.
public static function reguard(): void
Examples:
class User extends Model
{
protected $guarded = ['is_admin'];
}
// Temporarily unguard
Model::unguard();
User::create(['name' => 'Admin', 'is_admin' => true]);
Model::reguard();
Mutators & Casting
Mutators and casting allow you to transform attribute values when you retrieve or set them on model instances.
Accessors & Mutators
And accessor transforms an attribute value when it is accessed. A mutator transforms an attribute value when it is set.
Naming Convention:
- Accessor:
get_{Attribute}_attribute - Mutator:
set_{Attribute}_attribute
Examples:
class User extends Model
{
// Accessor: Get name in uppercase
public function get_name_attribute($value)
{
return strtoupper($value);
}
// Mutator: Hash password before saving
public function set_password_attribute($value)
{
$this->attributes['password'] = password_hash($value, PASSWORD_BCRYPT);
}
}
Attribute Casting
Attribute casting provides a convenient way to convert attributes to common data types.
Supported Cast Types:
intintegerrealfloatdoubledecimal:digitsstringboolbooleanobjectarrayjsondatedatetimetimestamp
Description:
The $casts property maps attribute names to the desired cast type.
Methods:
Get Casts
public function get_casts(): array
Merge Casts
public function merge_casts(array $casts): static
Examples:
class Product extends Model
{
protected $casts = [
'is_active' => 'boolean',
'options' => 'array',
'price' => 'decimal:2',
'published_at' => 'datetime'
];
}
$product = Product::find(1);
var_dump($product->is_active); // bool(true)
var_dump($product->options); // array(...)
Scopes
Scopes allow you to define common sets of constraints that you may easily re-use throughout your application.
Named Scopes
Description:
Named scopes are defined by adding a scope_ prefix to a method name. These methods should return the query builder instance.
Methods:
Check Named Scope
public function has_named_scope(string $scope): bool
Examples:
class Product extends Model
{
// Define scope 'active'
public function scope_active($query)
{
return $query->where('is_active', true);
}
// Define scope 'price_greater_than'
public function scope_price_greater_than($query, $price)
{
return $query->where('price', '>', $price);
}
}
// Usage
$activeProducts = Product::query()->active()->get();
$expensiveProducts = Product::query()->price_greater_than(100)->get();