Your First App¶
To illustrate how to build apps using the DMS, let’s go through building a simple TODO list app. See installation guide if necessary
Defining your domain model¶
Firstly lets build our entities. Lets create a file app/Domain/Entities/TodoItem.php
.
<?php declare(strict_types = 1);
namespace App\Domain\Entities;
use Dms\Core\Model\Object\ClassDefinition;
use Dms\Core\Model\Object\Entity;
/**
* Your first entity.
*
* An item on the TODO list.
*/
class TodoItem extends Entity
{
// Define constants for property names
const DESCRIPTION = 'description';
const COMPLETED = 'completed';
/**
* @var string
*/
public $description;
/**
* @var bool
*/
public $completed;
/**
* Initialises a new TODO item.
*
* @param string $description
*/
public function __construct(string $description)
{
parent::__construct();
$this->description = $description;
$this->completed = false;
}
/**
* Defines the structure of this entity.
*
* @param ClassDefinition $class
*/
protected function defineEntity(ClassDefinition $class)
{
// Enables strong typing for this entity
$class->property($this->description)->asString();
$class->property($this->completed)->asBool();
}
}
Building your persistence layer¶
So now we have our entities, we need a way to persist them to a database.
Defining the mapper¶
Create the entity mapper under app/Infrastructure/Persistence/TodoItemMapper.php
.
Configure how to map the entity to the database table.
<?php declare(strict_types = 1);
namespace App\Infrastructure\Persistence;
use Dms\Core\Persistence\Db\Mapping\Definition\MapperDefinition;
use Dms\Core\Persistence\Db\Mapping\EntityMapper;
use App\Domain\Entities\TodoItem;
/**
* Your first entity mapper.
*
* The App\Domain\Entities\TodoItem entity mapper.
*/
class TodoItemMapper extends EntityMapper
{
/**
* Defines the entity mapper
*
* @param MapperDefinition $map
*
* @return void
*/
protected function define(MapperDefinition $map)
{
$map->type(TodoItem::class);
$map->toTable('todo_items');
$map->idToPrimaryKey('id');
$map->property(TodoItem::DESCRIPTION)->to('description')->asVarchar(255);
$map->property(TodoItem::COMPLETED)->to('completed')->asBool();
}
}
Register the mapper in app/AppOrm.php
:
<?php declare(strict_types = 1);
namespace App;
use App\Domain\Entities\TodoItem;
use App\Infrastructure\Persistence\TodoItemMapper;
use Dms\Core\Persistence\Db\Mapping\Definition\Orm\OrmDefinition;
use Dms\Core\Persistence\Db\Mapping\Orm;
use Dms\Web\Laravel\Persistence\Db\DmsOrm;
/**
* The application's orm.
*
* @author Elliot Levin <elliotlevin@hotmail.com>
*/
class AppOrm extends Orm
{
/**
* Defines the object mappers registered in the orm.
*
* @param OrmDefinition $orm
*
* @return void
*/
protected function define(OrmDefinition $orm)
{
$orm->enableLazyLoading();
$orm->encompass(DmsOrm::inDefaultNamespace());
// You can register your mappers here
$orm->entities([
TodoItem::class => TodoItemMapper::class
]);
}
}
Defining the repository interface¶
Create the repository interface app/Domain/Services/ITodoItemRepository.php
.
<?php declare(strict_types = 1);
namespace App\Domain\Services\Persistence;
use Dms\Core\Model\ICriteria;
use Dms\Core\Model\ISpecification;
use Dms\Core\Persistence\IRepository;
use App\Domain\Entities\TodoItem;
/**
* The repository for the App\Domain\Entities\TodoItem entity.
*/
interface ITodoItemRepository extends IRepository
{
/**
* {@inheritDoc}
*
* @return TodoItem[]
*/
public function getAll() : array;
/**
* {@inheritDoc}
*
* @return TodoItem
*/
public function get($id);
/**
* {@inheritDoc}
*
* @return TodoItem[]
*/
public function getAllById(array $ids) : array;
/**
* {@inheritDoc}
*
* @return TodoItem|null
*/
public function tryGet($id);
/**
* {@inheritDoc}
*
* @return TodoItem[]
*/
public function tryGetAll(array $ids) : array;
/**
* {@inheritDoc}
*
* @return TodoItem[]
*/
public function matching(ICriteria $criteria) : array;
/**
* {@inheritDoc}
*
* @return TodoItem[]
*/
public function satisfying(ISpecification $specification) : array;
}
Defining the repository implementation¶
Create the repository implementation app/Infrastructure/Persistence/DbTodoItemRepository.php
.
<?php declare(strict_types = 1);
namespace App\Infrastructure\Persistence;
use Dms\Core\Persistence\Db\Connection\IConnection;
use Dms\Core\Persistence\Db\Mapping\IOrm;
use Dms\Core\Persistence\DbRepository;
use App\Domain\Services\Persistence\ITodoItemRepository;
use App\Domain\Entities\TodoItem;
/**
* The database repository implementation for the App\Domain\Entities\TodoItem entity.
*/
class DbTodoItemRepository extends DbRepository implements ITodoItemRepository
{
public function __construct(IConnection $connection, IOrm $orm)
{
parent::__construct($connection, $orm->getEntityMapper(TodoItem::class));
}
// Custom queries can go here...
}
Bind your repository implementation to the interface in app/Providers/AppServiceProvider.php
<?php
namespace App\Providers;
use App\AppCms;
use App\AppOrm;
use App\Domain\Services\Persistence\ITodoItemRepository;
use App\Infrastructure\Persistence\DbTodoItemRepository;
use Dms\Core\ICms;
use Dms\Core\Persistence\Db\Mapping\IOrm;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
//
}
/**
* Register any application services.
*
* @return void
*/
public function register()
{
$this->app->singleton(IOrm::class, AppOrm::class);
$this->app->singleton(ICms::class, AppCms::class);
// Bind your repositories here
$this->app->singleton(ITodoItemRepository::class, DbTodoItemRepository::class);
}
}
Migrating the database¶
To sync the database we must generate a migration and run it:
# Auto-generate a migration to sync the database
php artisan dms:make:migration add_todo_items_table
# Run the migration
php artisan migrate
You can review the generated migration under the database/migrations/
directory
Building the CMS¶
Defining your modules¶
To build the backend we must first configure the module app/Cms/Modules/TodoItemModule.php
<?php declare(strict_types = 1);
namespace App\Cms\Modules;
use Dms\Core\Auth\IAuthSystem;
use Dms\Core\Common\Crud\CrudModule;
use Dms\Core\Common\Crud\Definition\CrudModuleDefinition;
use Dms\Core\Common\Crud\Definition\Form\CrudFormDefinition;
use Dms\Core\Common\Crud\Definition\Table\SummaryTableDefinition;
use App\Domain\Services\Persistence\ITodoItemRepository;
use App\Domain\Entities\TodoItem;
use Dms\Common\Structure\Field;
/**
* The todo-item module.
*/
class TodoItemModule extends CrudModule
{
public function __construct(ITodoItemRepository $dataSource, IAuthSystem $authSystem)
{
parent::__construct($dataSource, $authSystem);
}
/**
* Defines the structure of this module.
*
* @param CrudModuleDefinition $module
*/
protected function defineCrudModule(CrudModuleDefinition $module)
{
$module->name('todo-item');
$module->labelObjects()->fromProperty(TodoItem::DESCRIPTION);
$module->metadata([
'icon' => 'list', // Choose icon from http://fontawesome.io/icons/
]);
$module->crudForm(function (CrudFormDefinition $form) {
$form->section('Details', [
$form->field(
Field::create('description', 'Description')->string()->required()
)->bindToProperty(TodoItem::DESCRIPTION),
//
$form->field(
Field::create('completed', 'Completed')->bool()
)->bindToProperty(TodoItem::COMPLETED),
]);
});
$module->removeAction()->deleteFromDataSource();
$module->summaryTable(function (SummaryTableDefinition $table) {
$table->mapProperty(TodoItem::DESCRIPTION)->to(Field::create('description', 'Description')->string()->required());
$table->mapProperty(TodoItem::COMPLETED)->to(Field::create('completed', 'Completed')->bool());
$table->view('all', 'All')
->loadAll()
->asDefault();
});
}
}
Defining your package¶
Create the package (a group of modules) app/Cms/TodoAppPackage.php
<?php declare(strict_types = 1);
namespace App\Cms;
use Dms\Core\Package\Definition\PackageDefinition;
use Dms\Core\Package\Package;
use App\Cms\Modules\TodoItemModule;
/**
* The todo-app package.
*/
class TodoAppPackage extends Package
{
/**
* Defines the structure of this cms package.
*
* @param PackageDefinition $package
*
* @return void
*/
protected function define(PackageDefinition $package)
{
$package->name('todo-app');
$package->metadata([
'icon' => 'check-square', // Choose icon from http://fontawesome.io/icons/
]);
$package->modules([
'todo-item' => TodoItemModule::class,
]);
}
}
Register the package in app/AppCms.php
<?php declare(strict_types=1);
namespace App;
use App\Cms\TodoAppPackage;
use Dms\Core\Cms;
use Dms\Core\CmsDefinition;
use Dms\Package\Analytics\AnalyticsPackage;
use Dms\Web\Laravel\Auth\AdminPackage;
use Dms\Web\Laravel\Document\PublicFilePackage;
/**
* The application's cms.
*
* @author Elliot Levin <elliotlevin@hotmail.com>
*/
class AppCms extends Cms
{
/**
* Defines the structure and installed packages of the cms.
*
* @param CmsDefinition $cms
*
* @return void
*/
protected function define(CmsDefinition $cms)
{
$cms->packages([
// Default packages installed out of the box
'admin' => AdminPackage::class,
'documents' => PublicFilePackage::class,
'analytics' => AnalyticsPackage::class,
// Register your packages here...
'todo-app' => TodoAppPackage::class,
]);
}
}
Visit http://your-app-domain/dms
and login to see your first backend: