This guide helps you get from "I have a database" to "my feature can inject a repository" without hand-building database connections in every service.
It is about wiring the ORM into an Assegai app cleanly:
- installing the package
- configuring databases with the CLI
- choosing where a feature gets its default data source
- injecting repositories without hand-building connections in every service
Install the ORM
For an existing project:
composer require assegaiphp/orm
For a new project, the usual path is to choose database setup during assegai new and let the CLI scaffold the config for you.
Configure a database with the CLI
If you skipped database setup during project creation, you can add it later:
assegai database:configure blog --mysql
assegai database:setup blog --mysql
assegai migration:setup blog --mysql
Common combinations:
--mysqlfor a long-running app backed by MySQL--pgsqlfor PostgreSQL--sqlitefor local development, tests, prototypes, and smaller apps
database:configure writes connection details into config/default.php. database:setup prepares the database itself. migration:setup creates the migrations workspace for that connection.
What the config looks like
The generated config template already contains the database sections the ORM expects:
<?php
return [
'databases' => [
'mysql' => [
'blog' => [
'host' => '127.0.0.1',
'user' => 'root',
'password' => '',
'port' => 3306,
],
],
'sqlite' => [
'local' => [
'path' => '.data/local.sq3',
],
],
],
];
For SQLite, the path is relative to the project root unless you choose one of the in-memory modes through the CLI.
Choose where a feature gets its data source
Assegai gives you three useful levels for this choice.
App-wide default
If most of the app uses one connection, the root module can carry that default:
<?php
namespace Assegaiphp\BlogApi;
use Assegai\Core\Attributes\Modules\Module;
use Assegaiphp\BlogApi\Posts\PostsModule;
#[Module(
imports: [PostsModule::class],
config: ['data_source' => 'blog'],
)]
class AppModule
{
}
Module-level default
This is usually the sweet spot for real applications:
<?php
namespace Assegaiphp\BlogApi\Posts;
use Assegai\Core\Attributes\Modules\Module;
#[Module(
providers: [PostsService::class],
controllers: [PostsController::class],
config: ['data_source' => 'blog'],
)]
class PostsModule
{
}
That keeps the choice close to the feature without repeating it on every entity.
Entity-level override
If a particular entity must always live on a specific connection, put it directly on the entity:
<?php
namespace Assegaiphp\BlogApi\Posts\Entities;
use Assegai\Orm\Attributes\Entity;
#[Entity(
table: 'posts',
database: 'blog',
)]
class PostEntity
{
}
You can also set the driver explicitly on the entity when that helps clarify the target:
<?php
use Assegai\Orm\Enumerations\DataSourceType;
#[Entity(
table: 'notes',
database: 'local',
driver: DataSourceType::SQLITE,
)]
class NoteEntity
{
}
How repository injection resolves the connection
#[InjectRepository(SomeEntity::class)] resolves the data source in this order:
- the entity's
databasevalue - the active module config key
data_source - an error if neither is available
If the configured data source string includes a driver prefix like sqlite:local, the driver is derived from that prefix.
Inject a repository into a service
This is the standard application-level pattern:
<?php
namespace Assegaiphp\BlogApi\Posts;
use Assegai\Core\Attributes\Injectable;
use Assegai\Orm\Attributes\InjectRepository;
use Assegai\Orm\Management\Repository;
use Assegaiphp\BlogApi\Posts\Entities\PostEntity;
#[Injectable]
class PostsService
{
public function __construct(
#[InjectRepository(PostEntity::class)]
private Repository $postsRepository,
) {
}
}
That keeps the service focused on application behavior instead of connection management.
Use DataSource directly when you really need to
Direct DataSource usage is still useful for scripts, tests, tooling, or low-level debugging:
<?php
use App\Entities\NoteEntity;
use Assegai\Orm\DataSource\DataSource;
use Assegai\Orm\DataSource\DataSourceOptions;
use Assegai\Orm\Enumerations\DataSourceType;
$dataSource = new DataSource(new DataSourceOptions(
entities: [NoteEntity::class],
name: 'local',
type: DataSourceType::SQLITE,
));
$notes = $dataSource->getRepository(NoteEntity::class);
Inside an Assegai module, repository injection is still the preferred path.
Next steps
Once the data source is settled, move on to: