A data source is the configured place your ORM work reads from and writes to.
That sounds simple, but it is an important idea because it combines several pieces:
- the driver family, such as
mysql,pgsql,sqlite, ormssql - the connection details, such as host, port, credentials, or file path
- the name the rest of the app uses to refer to that store
- the connection object you work with at runtime
In other words, a data source is more than a database name. It is the full configured persistence endpoint.
Why the docs say data_source
In Assegai module config, the key is data_source, not database.
That is intentional. The abstraction is wider than one SQL engine, so the configuration key stays broad too.
Named data sources
The ORM expects named data sources.
That means you do not usually say connect to PostgreSQL somehow. You say connect to the named PostgreSQL data source called cinema.
Inside Assegai module config, that usually looks like:
'data_source' => 'pgsql:cinema'
That string has two parts:
pgsqlis the driver tokencinemais the configured data source name
This format is preferred because it is explicit and easy to scan.
OrmRuntime::configure() versus direct DataSource
Use OrmRuntime::configure() when:
- you want to define named data sources once and reuse them
- you want helpers such as schema or migration tooling to resolve the same named config
- you want to keep connection details out of the rest of the script
Use direct DataSource construction when:
- you are writing a small one-file script or job
- the connection details are already known right there
- you want the shortest path to a working repository
A direct DataSource does not require OrmRuntime::configure() if you pass the full connection details in DataSourceOptions.
Standalone configuration with OrmRuntime
In standalone PHP, configure named data sources through OrmRuntime when you want name-based resolution.
<?php
use Assegai\Orm\Support\OrmRuntime;
OrmRuntime::configure([
'databases' => [
'mysql' => [
'catalog' => [
'host' => '127.0.0.1',
'user' => 'root',
'password' => '',
'port' => 3306,
],
],
'pgsql' => [
'analytics' => [
'host' => '127.0.0.1',
'user' => 'postgres',
'password' => 'secret',
'port' => 5432,
],
],
'sqlite' => [
'local' => [
'path' => __DIR__ . '/local.sqlite',
],
],
'mssql' => [
'reporting' => [
'host' => '127.0.0.1',
'user' => 'sa',
'password' => 'secret',
'port' => 1433,
],
],
],
]);
How to read this:
mysql,pgsql,sqlite, andmssqlgroup data sources by driver family- each nested key, such as
catalogorreporting, is a named data source - the value contains the connection details that driver needs
Creating a DataSource directly
If you already know the connection details, you can create a DataSource object directly and skip runtime configuration.
SQLite example
<?php
use App\Entities\MovieEntity;
use Assegai\Orm\DataSource\DataSource;
use Assegai\Orm\DataSource\DataSourceOptions;
use Assegai\Orm\Enumerations\DataSourceType;
$dataSource = new DataSource(new DataSourceOptions(
entities: [MovieEntity::class],
name: 'catalog',
type: DataSourceType::SQLITE,
path: __DIR__ . '/catalog.sqlite',
));
MSSQL example
<?php
use App\Entities\MovieEntity;
use Assegai\Orm\DataSource\DataSource;
use Assegai\Orm\DataSource\DataSourceOptions;
use Assegai\Orm\Enumerations\DataSourceType;
$dataSource = new DataSource(new DataSourceOptions(
entities: [MovieEntity::class],
name: 'reporting',
type: DataSourceType::MSSQL,
host: '127.0.0.1',
port: 1433,
username: 'sa',
password: 'secret',
));
What each option means:
entitieslists the entity classes this data source should know aboutnameis the data source nametypeis the driver familypathis the SQLite database file path when you are using SQLitehost,port,username, andpasswordare the network connection details for MySQL, MariaDB, PostgreSQL, or MSSQL
Creating a DataSource from named runtime config
If you have already called OrmRuntime::configure(), you can let the runtime supply the missing details.
<?php
use App\Entities\MovieEntity;
use Assegai\Orm\DataSource\DataSource;
use Assegai\Orm\DataSource\DataSourceOptions;
use Assegai\Orm\Enumerations\DataSourceType;
$dataSource = new DataSource(new DataSourceOptions(
entities: [MovieEntity::class],
name: 'local',
type: DataSourceType::SQLITE,
));
In that version:
nameandtypeidentify the configured data sourceresolveOptions(...)insideDataSourcemerges in the configured path or credentials- the script no longer has to repeat the same connection details everywhere
The same idea works for a named MSSQL source:
<?php
$dataSource = new DataSource(new DataSourceOptions(
entities: [MovieEntity::class],
name: 'reporting',
type: DataSourceType::MSSQL,
));
Using a data source directly
Once a DataSource exists, you can work through:
- repositories via
$dataSource->getRepository(...) - the entity manager via
$dataSource->manager - the underlying client via
$dataSource->getClient()
Example:
<?php
$movies = $dataSource->getRepository(MovieEntity::class);
$entityManager = $dataSource->manager;
$pdo = $dataSource->getClient();
Use the highest-level tool that fits the job:
- repository for entity-scoped app work
- entity manager for broader persistence workflows
- raw client or query builder for lower-level SQL work
Using data sources inside Assegai
In an Assegai app, the most common choice is to let the framework resolve the data source for you.
The CLI can scaffold MySQL, MariaDB, PostgreSQL, SQLite, and MSSQL sources. It writes the same nested databases.<driver>.<name> shape shown below.
Example:
<?php
return [
'databases' => [
'mssql' => [
'reporting' => [
'host' => '127.0.0.1',
'user' => 'sa',
'password' => 'secret',
'port' => 1433,
],
],
],
];
Module-level default
This is usually the best default for real features:
<?php
namespace Assegaiphp\CinemaHub\Reports;
use Assegai\Core\Attributes\Modules\Module;
#[Module(
providers: [ReportsService::class],
controllers: [ReportsController::class],
config: ['data_source' => 'mssql:reporting'],
)]
class ReportsModule
{
}
App-wide default
If most of the app uses one data source, the root module can provide it:
<?php
#[Module(
imports: [MoviesModule::class, ReportsModule::class],
config: ['data_source' => 'mssql:reporting'],
)]
class AppModule
{
}
Entity-level override
If one entity must always use a specific data source, put that decision on the entity:
<?php
use Assegai\Orm\Attributes\Entity;
use Assegai\Orm\Enumerations\DataSourceType;
#[Entity(
table: 'audit_logs',
database: 'analytics',
driver: DataSourceType::POSTGRESQL,
)]
class AuditLogEntity
{
}
Resolution order in Assegai
When #[InjectRepository(SomeEntity::class)] is used inside an Assegai app, the ORM resolves the connection in this order:
- the entity's
databasevalue - the current module's
data_source - an error if neither is available
That is why module-level defaults are so useful. They remove repetition while keeping the chosen data source obvious.
Practical advice
- Prefer named data sources over ad-hoc connection setup scattered through services.
- Prefer module-level
data_sourcedefaults unless one entity truly needs a different store. - Use the fully qualified
driver:nameform in Assegai config. - Keep standalone configuration in one place when several scripts or helpers need to share it.
- Use direct
DataSourceconstruction for very small scripts when repeating the connection details is acceptable. - Treat data sources as application boundaries, not just plumbing.
Next steps
Once the connection side is clear, move on to Entities.