# Ashes ORM
# Table of Contents
- Introduction
- Generating Model Classes
- Model Conventions
- Retrieving Models
- Saving Models
- Updating Models
- Deleting Models
# Introduction
Phenix uses the Data Mapper pattern for the modeling layer, allowing a clear separation between business logic and data access logic. Models use class properties with PHP attributes to map table columns in the database to model properties. Attributes also allow you to define relationships.
# Generating Model Classes
Phenix provides a command to generate models with additional options to create a controller, migration, model query builder, and model collection. To create a model, you can use the following command:
php phenix make:model User
# Command Options
Create a model with a controller:
php phenix make:model User --controller
php phenix make:model User -c
Create a model with a migration:
php phenix make:model User --migration
php phenix make:model User -m
Create with a custom collection:
php phenix make:model User --collection
php phenix make:model User -cn
Create with a custom query builder:
php phenix make:model User --query
php phenix make:model User -qb
Create with a controller, migration, query builder, and model collection:
php phenix make:model User --all
php phenix make:model User -a
Database models extend from Phenix\Database\Models\DatabaseModel
:
<?php
declare(strict_types=1);
namespace App\Models;
use Phenix\Database\Models\DatabaseModel;
class User extends DatabaseModel
{
public static function table(): string
{
//
}
}
# Model Conventions
# Defining Table
When a model is created, the first thing to do is to define the database table.
public static function table(): string
{
return 'users';
}
# Model Properties
Model properties are defined using PHP attributes. Here are the available attributes:
# Available Attributes
Id
: Defines a property as the primary key of the model.
use Phenix\Database\Models\Attributes\Id;
#[Id]
public int $id;
Column
: Defines a property as a column in the database.
use Phenix\Database\Models\Attributes\Column;
#[Column]
public string $name;
DateTime
: Defines a property as a date/time column.
use Phenix\Database\Models\Attributes\DateTime;
#[DateTime(name: 'created_at', autoInit: true)]
public Date $createdAt;
ForeignKey
: Defines a property as a foreign key.
use Phenix\Database\Models\Attributes\ForeignKey;
#[ForeignKey(name: 'user_id')]
public int $userId;
# Relationships
Relationships between models are defined using specific attributes:
BelongsTo
: Defines a one-to-many relationship where the model belongs to another model.
use Phenix\Database\Models\Attributes\BelongsTo;
use Phenix\Database\Models\Attributes\ForeignKey;
#[ForeignKey(name: 'user_id')]
public int $userId;
#[BelongsTo(foreignProperty: 'userId')]
public User $user;
The name of the model property that was assigned as the foreign key is passed as a parameter to the BelongsTo
attribute. In turn, the foreign key maps to the foreign key column name in the database to the ForeignKey
attribute.
HasMany
: Defines a one-to-many relationship where the model has many of another model.
use Phenix\Database\Models\Attributes\HasMany;
#[HasMany(model: Product::class, foreignKey: 'user_id')]
public Collection $products;
BelongsToMany
: Defines a many-to-many relationship.
use Phenix\Database\Models\Attributes\BelongsToMany;
#[BelongsToMany(
table: 'invoice_product',
foreignKey: 'product_id',
relatedModel: Invoice::class,
relatedForeignKey: 'invoice_id'
)]
public Collection $invoices;
# Property-Column Mapping
When the column name in the database and the property name in the model are different, you can assign a column name to be used in the mapping:
use Phenix\Database\Models\Attributes\Id;
use Phenix\Database\Models\Attributes\Column;
#[Id(name: 'idKey')] // Column name in DB
public int $id;
#[Column(name: 'customerName')] // Column name in DB
public string $name;
This is what a model looks like with its properties defined:
<?php
declare(strict_types=1);
namespace App\Models;
use Phenix\Database\Models\Attributes\Column;
use Phenix\Database\Models\Attributes\DateTime;
use Phenix\Database\Models\Attributes\HasMany;
use Phenix\Database\Models\Attributes\Id;
use Phenix\Database\Models\Collection;
use Phenix\Database\Models\DatabaseModel;
use Phenix\Util\Date;
class User extends DatabaseModel
{
#[Id]
public int $id;
#[Column]
public string $name;
#[Column]
public string $email;
#[DateTime(name: 'created_at', autoInit: true)]
public Date $createdAt;
#[DateTime(name: 'updated_at')]
public Date|null $updatedAt = null;
#[HasMany(model: Product::class, foreignKey: 'user_id')]
public Collection $products;
#[HasMany(model: Comment::class, foreignKey: 'user_id', chaperone: true)]
public Collection $comments;
public static function table(): string
{
return 'users';
}
}
# Retrieving Models
The model query builder allows executing queries and mapping the results into models. If the query retrieves multiple records, they are added to a collection.
# Single Model
To query a single model, you can use the first
method on the query builder. This method retrieves the first record that matches the query criteria and maps it to a model instance. For example, to get a user with a specific ID, you can use the whereEqual
method to specify the condition and then call first
to get the user model. More information can be found in the query builder section.
$user = User::query()->whereEqual('id', 1)->first();
echo $user->name;
Phenix ORM also provides a shorthand syntax for querying models. Instead of using the query builder, you can use the find
method directly on the model class to retrieve a single record by its primary key. This method accepts the primary key value and an optional array of columns to select:
$user = User::find(1, ['id', 'name']);
echo $user->name;
This approach simplifies the code and makes it more readable when you need to fetch a single model by its primary key.
# Collections
When a query retrieves multiple records, they are automatically mapped into a collection, which provides an array-like interface with additional methods for filtering, sorting, and manipulating the data. Collections make it easy to work with groups of models, allowing you to iterate over them, apply transformations, and perform bulk operations efficiently.
$users = User::query()->selectAllColumns()->get();
foreach ($users as $user) {
echo $user->name;
}
# Pagination
The paginate
method is used to retrieve a paginated set of results from the database. It simplifies the process of fetching and displaying paginated data, making it easier to handle large datasets by breaking them into manageable chunks.
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use App\Models\User;
use Phenix\Http\Request;
use Phenix\Http\Response;
use Phenix\Http\Controller;
class UserController extends Controller
{
public function index(Request $request): Response
{
$users = User::query()
->selectAllColumns()
->paginate($request->getUri());
return response()->json($users);
}
}
# Paginate Signature
use League\Uri\Http;
use Phenix\Database\Paginator;
public function paginate(Http $uri, int $defaultPage = 1, int $defaultPerPage = 15): Paginator
Http $uri
: An instance of theHttp
class from theLeague\Uri
package, representing the current URI. This is used to extract query parameters for pagination.int $defaultPage
: The default page number to use if no page parameter is present in the URI. Defaults to1
.int $defaultPerPage
: The default number of items per page if no per_page parameter is present in the URI. Defaults to15
.
# Saving Models
The save
method is used to persist a model instance to the database. This method handles both the creation of new records and the updating of existing records.
$user = new User();
$user->name = 'John Doe';
$user->email = 'john@example.com';
$user->save();
The create
method is a static method used to create a new model instance with the given attributes. This method simplifies the process of instantiating a model, setting its properties, and saving it to the database in a single step.
$user = User::create([
'name' => 'John Doe',
'email' => 'john@example.com',
'created_at' => Date::now(),
]);
# Updating Models
To update an existing model, first retrieve the model, make the necessary changes, and then call the save
method:
$user = User::find(1);
$user->email = 'newemail@example.com';
$user->save();
# Deleting Models
To delete a model from the database, call the delete
method:
$user = User::find(1);
$user->delete();