tobento / app-database
App database support.
Requires
- php: >=8.0
- tobento/app: ^1.0.6
- tobento/app-migration: ^1.0
- tobento/service-database: ^1.1.1
- tobento/service-database-storage: ^1.0
- tobento/service-dir: ^1.0
- tobento/service-migration: ^1.0
- tobento/service-seeder: ^1.0.1
- tobento/service-storage: ^1.1.9
Requires (Dev)
- phpunit/phpunit: ^9.5
- tobento/service-filesystem: ^1.0
- vimeo/psalm: ^4.0
README
Database support for the app.
Table of Contents
Getting Started
Add the latest version of the app database project running this command.
composer require tobento/app-database
Requirements
- PHP 8.0 or greater
Documentation
App
Check out the App Skeleton if you are using the skeleton.
You may also check out the App to learn more about the app in general.
Database Boot
The database boot does the following:
- Registers databases based on its configuration file
- Binds DatabasesInterface to the app container.
- Binds PdoDatabaseInterface to the app container using the default pdo database
- Binds PDO to the app container for autowiring by using the default pdo database
- Binds StorageInterface to the app container.
Database Config
The configuration for the database is located in the app/config/database.php
file at the default App Skeleton config location.
use function Tobento\App\{directory}; return [ /* |-------------------------------------------------------------------------- | Default Database Names |-------------------------------------------------------------------------- | | Specify the default database names you wish to use for your application. | | The default "pdo" is used by the application for the default | PdoDatabaseInterface implementation. | Moreover, it is used for autowiring classes with PDO parameters and | may be used in other app boots. | If you do not need it at all, just ignore or remove it. | | The default "storage" is used by the application for the default | StorageInterface implementation and may be used in other app boots. | If you do not need it at all, just ignore or remove it. | */ 'defaults' => [ 'pdo' => 'mysql', 'storage' => 'file', ], /* |-------------------------------------------------------------------------- | Databases |-------------------------------------------------------------------------- | | Configure any databases needed for your application. | */ 'databases' => [ 'mysql' => [ 'factory' => \Tobento\Service\Database\PdoDatabaseFactory::class, 'config' => [ 'driver' => 'mysql', 'host' => 'localhost', 'port' => null, 'database' => 'app', 'username' => 'root', 'password' => '', 'charset' => 'utf8mb4', 'options' => [ \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION, \PDO::ATTR_EMULATE_PREPARES => false, ], ], ], 'file' => [ 'factory' => \Tobento\Service\Database\Storage\StorageDatabaseFactory::class, 'config' => [ 'storage' => Tobento\Service\Storage\JsonFileStorage::class, 'dir' => directory('app').'storage/database/file/', ], ], 'mysql-storage' => [ 'factory' => \Tobento\Service\Database\Storage\StorageDatabaseFactory::class, 'config' => [ 'storage' => \Tobento\Service\Storage\PdoMySqlStorage::class, 'database' => 'mysql', ], ], ], /* |-------------------------------------------------------------------------- | Database Processors |-------------------------------------------------------------------------- | | The processors used for migration. | */ 'processors' => [ // Processor for MySql and MariaDb: \Tobento\Service\Database\Processor\PdoMySqlProcessor::class, \Tobento\Service\Database\Storage\StorageDatabaseProcessor::class, ], ];
Pdo Database Factory
Check out the Database Service - Pdo Database Factory for its config parameters.
Storage Database Factory
Check out the Database Storage Service for its documentation.
Check out the Storage Service - Storages for the available storages.
Database Usage
You may access the default databases by the app:
use Tobento\App\AppFactory; use Tobento\Service\Database\DatabasesInterface; use Tobento\Service\Database\PdoDatabaseInterface; use Tobento\Service\Database\Processor\ProcessorInterface; use Tobento\Service\Storage\StorageInterface; // Create the app $app = (new AppFactory())->createApp(); // Add directories: $app->dirs() ->dir(realpath(__DIR__.'/../'), 'root') ->dir(realpath(__DIR__.'/app/'), 'app') ->dir($app->dir('app').'config', 'config', group: 'config'); // Adding boots $app->boot(\Tobento\App\Database\Boot\Database::class); $app->booting(); // Databases: $databases = $app->get(DatabasesInterface::class); // Default Pdo Database: $database = $app->get(PdoDatabaseInterface::class); // Default Storage: $storage = $app->get(StorageInterface::class); // Processor for migration: $processor = $app->get(ProcessorInterface::class); // Run the app $app->run();
Check out the Database Service - Databases to learn more about the usage of the DatabasesInterface::class
.
Check out the Database Service - Using PDO Database to learn more about the usage of the PdoDatabaseInterface::class
.
Check out the Storage Service - Queries to learn more about the usage of the StorageInterface::class
.
Using autowiring
You can also request the databases or the processor in any class resolved by the app.
use Tobento\Service\Database\DatabasesInterface; use Tobento\Service\Database\PdoDatabaseInterface; use Tobento\Service\Database\Processor\ProcessorInterface; use Tobento\Service\Storage\StorageInterface; use PDO; class SomeService { public function __construct( protected DatabasesInterface $databases, protected PdoDatabaseInterface $database, protected ProcessorInterface $processor, protected StorageInterface $storage, protected PDO $pdo, ) {} }
Migration
Create Migration
Create a migration class by extending the DatabaseMigration::class
and using the registerTables
method to specifiy your tables.
use Tobento\Service\Database\Migration\DatabaseMigration; use Tobento\Service\Database\Schema\Table; class DbMigrations extends DatabaseMigration { public function description(): string { return 'db migrations'; } /** * Register tables used by the install and uninstall methods * to create the actions from. * * @return void */ protected function registerTables(): void { $this->registerTable( table: function(): Table { $table = new Table(name: 'users'); $table->primary('id'); //... return $table; }, database: $this->databases->default('pdo'), name: 'Users', description: 'Users desc', ); $this->registerTable( table: function(): Table { $table = new Table(name: 'products'); $table->primary('id'); //... return $table; }, database: $this->databases->default('pdo'), ); } }
Check out the Database Service - Table Schema for its documentation.
Check out the Database Service - Create Migration to learn more about it.
Install And Uninstall Migration
Check out the App Migration - Install And Uninstall Migration to learn more about it.
App Migration Example
use Tobento\App\AppFactory; use Tobento\Service\Database\Migration\DatabaseMigration; use Tobento\Service\Database\Schema\Table; use Tobento\Service\Database\DatabasesInterface; class DbMigrations extends DatabaseMigration { public function description(): string { return 'db migrations'; } protected function registerTables(): void { $this->registerTable( table: function(): Table { $table = new Table(name: 'users'); $table->primary('id'); $table->string('name'); $table->items(iterable: [ ['name' => 'John'], ['name' => 'Mia'], ]); return $table; }, database: $this->databases->default('pdo'), ); } } $app = (new AppFactory())->createApp(); // Add directories: $app->dirs() ->dir(realpath(__DIR__.'/../'), 'root') ->dir(realpath(__DIR__.'/app/'), 'app') ->dir($app->dir('app').'config', 'config', group: 'config'); // Adding boots: $app->boot(\Tobento\App\Database\Boot\Database::class); $app->booting(); // Install migration: $app->install(DbMigrations::class); // Fetch user names: $database = $app->get(DatabasesInterface::class)->default('pdo'); $userNames = $database->execute( statement: 'SELECT name FROM users', )->fetchAll(\PDO::FETCH_COLUMN); // var_dump($userNames); // array(2) { [0]=> string(4) "John" [1]=> string(3) "Mia" } // Run the app: $app->run();
Seeding
Seeding Boot
The seeding boot does the following:
- SeedInterface implementation
The following seeders will be availbale:
Keep in mind that no Resources are set as they may be specific to your app needs. Therefore, the seeders mostly using the Lorem Seeder as fallback.
use Tobento\App\AppFactory; use Tobento\Service\Seeder\SeedInterface; // Create the app $app = (new AppFactory())->createApp(); // Adding boots $app->boot(\Tobento\App\Database\Boot\Seeding::class); $app->booting(); $seed = $app->get(SeedInterface::class); // Run the app $app->run();
Create Migration Seeder
Create a migration class for seeding by extending the DatabaseMigrationSeeder::class
and using the registerTables
method to specifiy your tables.
use Tobento\Service\Database\Migration\DatabaseMigrationSeeder; use Tobento\Service\Database\Schema\Table; use Tobento\Service\Iterable\ItemFactoryIterator; class DbMigrationsSeeder extends DatabaseMigrationSeeder { public function description(): string { return 'db migrations seeding'; } /** * Register tables used by the install and uninstall methods * to create the actions from. * * @return void */ protected function registerTables(): void { $this->registerTable( table: function(): Table { $table = new Table(name: 'users'); // no need to specifiy columns again // if you have migrated the table before. // seeding: $table->items(new ItemFactoryIterator( factory: function(): array { $fullname = $this->seed->fullname(); return [ 'name' => $fullname, 'email' => $this->seed->email(from: $fullname), 'weekday' => $this->seed->locale(['de', 'en'])->weekday(1, 7, 'EEEE'), ]; }, create: 10000 )) ->chunk(length: 2000) ->useTransaction(false) // default is true ->forceInsert(true); // default is false return $table; }, database: $this->databases->default('pdo'), name: 'Users seeding', description: 'Users seeded', ); } }
Check out the Database Service - Create Migration Seeder to learn more about it.
Check out the Seeder Service for its documentation.
Check out the Database Service - Table Schema for its documentation.
Seeder Resources
You may add seeder resources by the following ways:
Globally by using the app on method
use Tobento\App\AppFactory; use Tobento\Service\Seeder\SeedInterface; use Tobento\Service\Seeder\Resource; // Create the app $app = (new AppFactory())->createApp(); // Adding boots $app->boot(\Tobento\App\Database\Boot\Seeding::class); $app->booting(); // Add resources: $app->on(SeedInterface::class, function(SeedInterface $seed) { $seed->resources()->add(new Resource('countries', 'en', [ 'Usa', 'Switzerland', 'Germany', ])); }); $seed = $app->get(SeedInterface::class); var_dump($seed->country()); // string(7) "Germany" // Run the app $app->run();
Specific on your migration seeder
use Tobento\Service\Database\Migration\DatabaseMigrationSeeder; use Tobento\Service\Seeder\Resource; class DbMigrationsSeeder extends DatabaseMigrationSeeder { // ... protected function registerTables(): void { $this->seed->resources()->add(new Resource('countries', 'en', [ 'Usa', 'Switzerland', 'Germany', ])); // register tables: } }
You may check out Seeder Service - Resources or Seeder Service - Files Resources for its documentation.
App Migration Seeder Example
use Tobento\App\AppFactory; use Tobento\Service\Database\Migration\DatabaseMigration; use Tobento\Service\Database\Migration\DatabaseMigrationSeeder; use Tobento\Service\Database\Schema\Table; use Tobento\Service\Database\DatabasesInterface; use Tobento\Service\Iterable\ItemFactoryIterator; class DbMigrations extends DatabaseMigration { public function description(): string { return 'db migrations'; } protected function registerTables(): void { $this->registerTable( table: function(): Table { $table = new Table(name: 'users'); $table->primary('id'); $table->string('name'); $table->string('email'); return $table; }, database: $this->databases->default('pdo'), ); } } class DbMigrationsSeeder extends DatabaseMigrationSeeder { public function description(): string { return 'db migrations'; } protected function registerTables(): void { $this->registerTable( table: function(): Table { $table = new Table(name: 'users'); $table->items(new ItemFactoryIterator( factory: function(): array { $fullname = $this->seed->fullname(); return [ 'name' => $fullname, 'email' => $this->seed->email(from: $fullname), ]; }, create: 10, )) ->chunk(length: 2000) ->useTransaction(false) // default is true ->forceInsert(true); // default is false return $table; }, database: $this->databases->default('pdo'), ); } } $app = (new AppFactory())->createApp(); // Add directories: $app->dirs() ->dir(realpath(__DIR__.'/../'), 'root') ->dir(realpath(__DIR__.'/app/'), 'app') ->dir($app->dir('app').'config', 'config', group: 'config'); // Adding boots: $app->boot(\Tobento\App\Database\Boot\Database::class); $app->boot(\Tobento\App\Database\Boot\Seeding::class); $app->booting(); // Install migration: $app->install(DbMigrations::class); $app->install(DbMigrationsSeeder::class); // Fetch user names: $database = $app->get(DatabasesInterface::class)->default('pdo'); $emailsToNames = $database->execute( statement: 'SELECT email, name FROM users', )->fetchAll(\PDO::FETCH_KEY_PAIR); var_dump($emailsToNames); // array(10) { ["vitae.elit@example.org"]=> string(10) "Vitae Elit" ... } // Run the app: $app->run();
Repository
In progress...