Database
Assegai can be used with any type of database, whether it is SQL or NoSQL. This flexibility allows you to choose the database that best fits your needs. To connect Assegai to a database, you will need the PHP PDO extension installed and enabled along with any PHP drivers that are compatible with the database you have chosen. Once the extension is installed, you will be able to easily integrate Assegai with your database.
ORM integration
Assegai includes the assegaiphp/orm
package to facilitate integration with both SQL and NoSQL
databases.
$ composer require assegaiphp/orm ext-pdo
After completing the installation process, the default ORM data source can be configured in the root
AppModule
.
return [ ... 'databases' => [ 'mysql' => [ 'test' => [ 'host' => 'localhost', 'user' => 'root', 'password' => 'root', 'port' => 3306, ], ], ], ... ];
use Assegai\Core\Attributes\Modules\Module; #[Module( providers: [AppService::class], controllers: [AppController::class], imports: [], config: [ 'data_source' => 'test' ] )] class AppModule { }
After completing this step, the ORM DataSource
and EntityManager
objects will be
able to be injected into any part of the project without the need to import any additional modules, for
example:
use Assegai\Core\Attributes\Modules\Module; use Assegai\Orm\DataSource\DataSource; #[Module( providers: [AppService::class], controllers: [AppController::class], imports: [], config: [ 'data_source' => 'test' ] )] class AppModule { public function __construct(private DataSource $dataSource) { } }
Repository pattern
The Assegai ORM implements the repository design pattern, which means that each entity has a dedicated repository that can be accessed through the database data source.
To continue the example, we need to define at least one entity. In this case, we will create a
User
entity.
use Assegai\Orm\Attributes\Columns\Column; use Assegai\Orm\Attributes\Columns\EmailColumn; use Assegai\Orm\Attributes\Columns\PrimaryGeneratedColumn; use Assegai\Orm\Attributes\Entity; use Assegai\Orm\Queries\Sql\ColumnType; #[Entity(table: 'users')] class UserEntity { #[PrimaryGeneratedColumn] public int $id = 0; #[EmailColumn] public string $email = ''; #[Column] public string $firstName = ''; #[Column] public string $lastName = ''; #[Column(type: ColumnType::BOOLEAN, default: false)] public bool $isVerified = false; }
Tip Find out more about entities in the ORM documentation
The UserEntity
file is located in the users
directory, which contains all files
related to the UsersModule
. While you can choose where to store your model files, it is generally
recommended to place them in the corresponding module directory to keep them organized by domain.
Now, let's examine the UsersModule
use Assegai\Core\Attributes\Modules\Module; #[Module( providers: [UsersService::class], controllers: [UsersController::class], imports: [], exports: [], )] class UsersModule {}
Next, we can use the #[InjectRepository]
attribute to inject the UsersRepository
into the UsersService
:
use Assegai\App\Users\Dto\CreateUserDto; use Assegai\App\Users\Dto\UpdateUserDto; use Assegai\App\Users\Entities\UserEntity; use Assegai\Core\Attributes\Injectable; use Assegai\Orm\Attributes\InjectRepository; use Assegai\Orm\Management\Repository; #[Injectable] class UsersService { public function __construct( #[InjectRepository(UserEntity::class)] private readonly Repository $usersRepository ) {} function create(CreateUserDto $createUserDto) { $user = $this->usersRepository->create($createUserDto); $results = $this->usersRepository->save($user); return $this->findOne($results->id); } function findAll() { return $this->usersRepository->find(); } function findOne(int $id) { return $this->usersRepository->findOne([ 'where' => ['id' => $id] ]); } function update(int $id, UpdateUserDto $updateUserDto) { $results = $this->usersRepository->update(['id' => $id], $updateUserDto); return $this->findOne($id); } function remove(int $id) { $results = $this->usersRepository->delete(['id' => $id]); return ['ids' => $id]; }
Notice Remember to import theUsersModule
into the rootAppModule
Relations
Assegai ORM supports relationships between entities. To define relations in entities you can use the following attributes:
#[OneToOne] |
Every row in the primary table has one and only one associated row in the foreign table. Use the #[OneToOne] attribute to define this type of relation. |
#[OneToMany] |
Defines a one-to-many relationship between two entities. This means that a single row in the primary table can be associated with multiple rows in the foreign table. Use the #[OneToMany] attribute to define this type of relation. |
#[ManyToOne] |
Every entity has a many-to-one relationship with another entity. This means that multiple rows in the primary table reference a single row in the foreign table. Use the #[ManyToOne] attribute to define this type of relation. Use the #[JoinColumn] attribute to specify the foreign key. |
#[ManyToMany] |
Every row in the primary table has many related rows in the foreign table, and every record in the foreign table has many related rows in the primary table. Use the #[ManyToMany] attribute to define this type of relation. Use the #[JoinTable] to specify the junction/join table that will be used for the relation. |
Examples
use Assegai\Orm\Attributes\Columns\Column; use Assegai\Orm\Attributes\Columns\EmailColumn; use Assegai\Orm\Attributes\Columns\PrimaryGeneratedColumn; use Assegai\Orm\Attributes\Entity; use Assegai\Orm\Queries\Sql\ColumnType; use Assegai\App\Posts\Entities\PostEntity; use Assegai\App\Profiles\Entities\ProfileEntity; use Assegai\App\Teams\Entities\TeamEntity; #[Entity(table: 'users')] class UserEntity { #[PrimaryGeneratedColumn] public int $id = 0; #[EmailColumn] public string $email = ''; #[Column] public string $firstName = ''; #[Column] public string $lastName = ''; #[Column(type: ColumnType::BOOLEAN, default: false)] public bool $isVerified = false; #[OneToOne(ProfileEntity::class)] public ?ProfileEntity $profile = null; #[ManyToOne(TeamEntity::class)] #[JoinColumn('team_id')] public ?TeamEntity $team = null; #[OneToMany(PostEntity::class)] public array $posts = [] }
Then you can load your relations by passing a list of relations to your FindOptions
object and passing that object to your repository's find
method. Like this:
#[Entity('users')] class UsersService { public function __construct( #[InjectRepository(UserEntity::class)] protected Repository $usersRepository ) {} public function findOneById(int $id): FindResult { $options = new FindOptions(where: ['id' => $id], relations: ['profile', 'team', 'posts']); return $this->usersRepository->find($options); } }
Now, let's assume you have a development server listening on port 3000
. You can make a GET
request to the /users/:id
endpoint.
$ curl --location 'localhost:3000/users/1'
After that, you can expect a response similar to the following:
{ "id": 1, "email": "user@example.com", "firstName": "John", "lastName": "Doe", "isVerified": true, "profile": { "id": 1, "bio": "Hello, I'm John Doe", "avatar": "https://example.com/avatar.jpg", }, "team": { "id": 1, "name": "Team A", }, "posts": [ { "id": 1, "title": "Post 1", "content": "This is the content of post 1", }, { "id": 2, "title": "Post 2", "content": "This is the content of post 2", } ] }