add documentation

This commit is contained in:
Simon Vieille 2021-05-31 16:30:46 +02:00
parent d7154ac6c9
commit 112e90056d
11 changed files with 718 additions and 22 deletions

View file

@ -1,3 +1,15 @@
.wy-menu p.caption {
margin-top: 10px;
margin-top: 20px;
}
table {
margin-bottom: 15px;
}
td, th {
padding: 5px 10px;
}
td code {
border: 0 !important;
}

View file

@ -1,2 +1,241 @@
# Configuration
A generated crud controller contains a method named `getConfiguration`. This methods returns a instance of `App\Core\Crud\CrudConfiguration`.
## setPageTitle
`setPageTitle(string $page, string $title)`
Set the title of the given page.
Example of usage in a CRUD template: `<title>{{ configuration.pageTitle('index') }}</title>`.
## setPageRoute
`setPageRoute(string $page, string $route)`
Set the route of the given page. By default, pages are: `index`, `edit`, `new`, `show`. You can create a custom page for a custom controller.
Example of usage in a CRUD template: `<a href="{{ path(configuration.pageRoute('new')) }}">...</a>`.
## setForm
`setForm(string $context, string $form, `array` $options = [])`
Set the form used in the given context.
## setFormOptions
`setFormOptions(string $context, `array` $options = [])`
Defines options given to a form.
## setAction
`setAction(string $page, string $action, bool $enabled)`
Set if an action is enabled or not in the given page. Take a look at `core/Resources/views/admin/crud/*.html.twig` for more information.
Usage in a CRUD template: `{% if configuration.action('index', 'new')%}...{% endif %}`.
## setActionTitle
`setActionTitle(string $page, string $action, string $title)`
Set the title of an action in the given page.
Example of usage in a CRUD template: `{{ configuration.actionTitle(context, 'new', 'New')|trans }}`
## setView
`setView(string $context, string $view)`
Override a view.
| Controller (context) | View | Description |
| ---------- | ---- | ----------- |
| `index` | `@Core/admin/crud/index.html.twig` | Template of the page `index` |
| `edit` | `@Core/admin/crud/edit.html.twig` | Template of the page `edit` |
| `new` | `@Core/admin/crud/new.html.twig` | Template of the page `new` |
| `show` | `@Core/admin/crud/show.html.twig` | Template of the page `show` |
| `filter` | `@Core/admin/crud/filter.html.twig` | Template of the page `filter` |
| Form (context) | View | Description |
| ---- | ---- | ----------- |
| `form` | `@Core/admin/crud/_form.html.twig` | Template to render a form |
| `form_widget` | `@Core/admin/crud/_form_widget.html.twig` | Template to render a form widget |
| `form_translations` | `@Core/admin/crud/_form_translations.html.twig` | Template to render a the translation field |
| Entity (context) | View | Description |
| ------ | ---- | ----------- |
| `show_entity` | @Core/admin/crud/_show.html.twig | Template to render the entity |
## setViewDatas
`setViewDatas(string $context, `array` $datas)` and `addViewData(string $context, string $name, $value)`
Add datas given to a view. Useful in a custom controller.
## setField
`setField(string $context, string $label, string $field, `array` $options)`
Add a field displayed in the given context. Used in the index.
```
use App\Core\Crud\Field;
$configuration->setField('index', 'Title', Field\TextField::class, [
// options
])
```
All fields have these options:
| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `property` | `string` | `null` | Entity's property to display |
| `property__builder` | `callable` | `null` | A callable data and used to generate the content displayed |
| `view` | `string` | `@Core/admin/crud/field/text.html.twig` | The templated rendered |
| `raw` | `boolean` | `false` | Render as HTML |
| `sort` | `array|callable` | `null` | Defines how to sort |
Examples:
```
$configuration->setField('index', 'My field', TextField::class, [
'property' => 'myProperty',
// OR
'property_builder' => function($entity, array $options) {
return $entity->getMyProperty();
},
])
$configuration->setField('index', 'My field', TextField::class, [
'raw' => true,
'property_builder' => function($entity, array $options) {
return sprintf('<span class="foo">%s</span>', $entity->getBar());
},
])
// https://127.0.0.7:8000/admin/my_entity?_sort=property&_sort_direction=asc
$configuration->setField('index', 'My field', TextField::class, [
'property' => 'myProperty'
'sort' => ['property', '.myProperty'],
// OR
'sort' => ['property', function(MyEntityRepositoryQuery $query, $direction) {
$query->orderBy('.myProperty', $direction);
}],
])
```
### TextField
`App\Core\Crud\Field\TextField`
| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `view` | `string` | `@Core/admin/crud/field/text.html.twig` | The templated rendered |
### DateField
`App\Core\Crud\Field\DateField`
| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `view` | `string` | `@Core/admin/crud/field/date.html.twig` | The templated rendered |
| `format` | `string` | `Y-m-d` | The date format |
### DatetimeField
`App\Core\Crud\Field\DatetimeField`
| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `view` | `string` | `@Core/admin/crud/field/date.html.twig` | The templated rendered |
| `format` | `string` | `Y-m-d H:i:s` | The date format |
### ButtonField
`App\Core\Crud\Field\ButtonField`
| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `view` | `string` | `@Core/admin/crud/field/button.html.twig` | The templated rendered |
| `button_attr` | `array` | `[]` | Button HTML attributes |
| `button_tag` | `string` | `button` | HTML tag of the button |
### ImageField
`App\Core\Crud\Field\ImageField`
| Option | Type | Default | Description |
| ------ | ---- | ------- | ----------- |
| `view` | `string` | `@Core/admin/crud/field/image.html.twig` | The templated rendered |
| `image_attr` | `array` | `[]` | Image HTML attributes |
## setMaxPerPage
`setMaxPerPage(string $page, int $max)`
Set how many elements are displayed in a single page.
## setI18n
`setI18n(array $locales, string $defaultLocale)`
Set an array of locales for a translatable entity. The default locale is used in the index page.
Compatible with [https://github.com/KnpLabs/DoctrineBehaviors/blob/master/docs/translatable.md](https://github.com/KnpLabs/DoctrineBehaviors/blob/master/docs/translatable.md).
## setDefaultSort
`setDefaultSort(string $context, string $label, string $direction = 'asc')`
Set the default sort applied in the repository query.
```
$configuration
->setDefaultSort('index', 'title', 'asc')
->setField('index', 'Title', Field\TextField::class, [
'property' => 'title',
'sort' => ['title', '.title'],
]);
```
## setIsSortableCollection
`setIsSortableCollection(string $page, bool $isSortableCollection)`
It enables the drag & drop to sort entities.
```
class MyEntity implements EntityInterface
{
// ...
/**
* @ORM\Column(type="integer", nullable=true)
*/
private $sortOrder;
public function getSortOrder(): ?int
{
return $this->sortOrder;
}
public function setSortOrder(?int $sortOrder): self
{
$this->sortOrder = $sortOrder;
return $this;
}
// ...
}
```
## setSortableCollectionProperty
`setSortableCollectionProperty(string $sortableCollectionProperty)`
In order to sort entities, the default property used is `sortOrder`. You can set something else.

View file

@ -1,2 +1,145 @@
# Generator
## Prepare your entity
* implements `App\Core\Entity\EntityInterface` (see [Entity Manager](/entities/em/))
* creates a repository query (see [Repository Query](/entities/query/))
* creates a factory (see [Factory](/entities/factory/))
* generates a form (see `php bin/console make:form --help`)
## Generation
The generation is performed in CLI. These information are required:
* The name of the futur controller (eg: `MyEntityAdminController`)
* The namespace of the entity (eg: `App\Entity\MyEntity`)
* The namespace of the entity repository query (eg: `App\Repository\MyEntityRepositoryQuery`)
* The namespace of the the entity factory (eg: `App\Factory\MyEntityFactory`)
* The namespace of the form used to create and update the entity (eg: `App\Form\MyEntityType`)
Simply run `php bin/console make:crud-controller`.
The next controller will be generated:
```
// src/Controller/MyEntityAdminController
namespace App\Controller;
use App\Core\Controller\Admin\Crud\CrudController;
use App\Core\Crud\CrudConfiguration;
use App\Core\Crud\Field;
use App\Core\Entity\EntityInterface;
use App\Core\Manager\EntityManager;
use App\Entity\MyEntity as Entity;
use App\Factory\MyEntityFactory as Factory;
use App\Form\MyEntityType as Type;
use App\Repository\MyEntityRepositoryQuery as RepositoryQuery;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Routing\Annotation\Route;
class MyEntityAdminController extends CrudController
{
/**
* @Route("/admin/my_entity/{page}", name="admin_my_entity_index", methods={"GET"}, requirements={"page":"\d+"})
*/
public function index(int $page = 1, RepositoryQuery $query, Request $request, Session $session): Response
{
return $this->doIndex($page, $query, $request, $session);
}
/**
* @Route("/admin/my_entity/new", name="admin_my_entity_new", methods={"GET", "POST"})
*/
public function new(Factory $factory, EntityManager $entityManager, Request $request): Response
{
return $this->doNew($factory->create(), $entityManager, $request);
}
/**
* @Route("/admin/my_entity/show/{entity}", name="admin_my_entity_show", methods={"GET"})
*/
public function show(Entity $entity): Response
{
return $this->doShow($entity);
}
/**
* @Route("/admin/my_entity/filter", name="admin_my_entity_filter", methods={"GET"})
*/
public function filter(Session $session): Response
{
return $this->doFilter($session);
}
/**
* @Route("/admin/my_entity/edit/{entity}", name="admin_my_entity_edit", methods={"GET", "POST"})
*/
public function edit(Entity $entity, EntityManager $entityManager, Request $request): Response
{
return $this->doEdit($entity, $entityManager, $request);
}
/**
* @Route("/admin/my_entity/sort/{page}", name="admin_my_entity_sort", methods={"POST"}, requirements={"page":"\d+"})
*/
public function sort(int $page = 1, RepositoryQuery $query, EntityManager $entityManager, Request $request, Session $session): Response
{
return $this->doSort($page, $query, $entityManager, $request, $session);
}
/**
* @Route("/admin/my_entity/delete/{entity}", name="admin_my_entity_delete", methods={"DELETE"})
*/
public function delete(Entity $entity, EntityManager $entityManager, Request $request): Response
{
return $this->doDelete($entity, $entityManager, $request);
}
protected function getConfiguration(): CrudConfiguration
{
return CrudConfiguration::create()
->setPageTitle('index', 'List of App\Entity\MyEntity')
->setPageTitle('edit', 'Edition of {id}')
->setPageTitle('new', 'New App\Entity\MyEntity')
->setPageTitle('show', 'View of {id}')
->setPageRoute('index', 'admin_my_entity_index')
->setPageRoute('new', 'admin_my_entity_new')
->setPageRoute('edit', 'admin_my_entity_edit')
->setPageRoute('show', 'admin_my_entity_show')
->setPageRoute('sort', 'admin_my_entity_sort')
->setPageRoute('delete', 'admin_my_entity_delete')
->setPageRoute('filter', 'admin_my_entity_filter')
->setForm('edit', Type::class, [])
->setForm('new', Type::class)
// ->setForm('filter', Type::class)
// ->setMaxPerPage('index', 20)
// ->setIsSortableCollection('index', false)
// ->setSortableCollectionProperty('sortOrder')
// ->setAction('index', 'new', true)
// ->setAction('index', 'show', true)
// ->setAction('index', 'edit', true)
// ->setAction('index', 'delete', true)
// ->setAction('edit', 'back', true)
// ->setAction('edit', 'show', true)
// ->setAction('edit', 'delete', true)
// ->setField('index', 'Label', Field\TextField::class, [
// 'property' => 'label',
// ])
;
}
protected function getSection(): string
{
return 'my_entity';
}
}
```

View file

@ -1,2 +1,19 @@
# CRUD
Murph helps you to manage specific entities with a CRUD manager:
* **C**reate entities
* **R**ead (Show) entities
* **U**pdate entities
* **D**elete entities
You can configure almost anything:
* How to list entities:
* Information to show
* Available actions
* Filters
* Sorting
* ...
* How to show an entity
* How to create and update an entity

135
docs/entities/em.md Normal file
View file

@ -0,0 +1,135 @@
# Entity Manager
The entity manager of Muprh is a proxy of the Doctrine's entity manager. It gives you an easy way to create, update and delete an entity and dispatches events easy to subscribe to.
## Implementation
Entities must implements `App\Core\Entity\EntityInterface`.
```
// src/Entity/MyEntity.php
namespace App\Entity;
use App\Repository\MyEntityRepository;
use Doctrine\ORM\Mapping as ORM;
use App\Core\Entity\EntityInterface;
/**
* @ORM\Entity(repositoryClass=MyEntityRepository::class)
*/
class MyEntity implements EntityInterface
{
// ...
}
```
## Usage
There are 2 entity managers which are services:
* `App\Core\Manager\EntityManager` used for all entities
* `App\Core\Manager\TranslatableEntityManager` used for translatable entities
```
// src/Controller/FooController.php
namespace App\Controller;
use App\Core\Manager\EntityManager
use App\Entity\MyEntity;
use Symfony\Component\HttpFoundation\Response;
class FooController
{
public function foo(EntityManager $entityManager): Response
{
$myEntity = new MyEntity();
// Creates an entity
$entityManager->create($myEntity);
// Updates an entity
$entityManager->update($myEntity);
// Deletes an entity
$entityManager->delete($myEntity);
// ...
}
}
```
## Events
Events are dispatched before and after creation, update and deletion. All entities of Muprh use the entity manager.
```
// src/EventSuscriber/MyEntityEventSubscriber.php
namespace App\EventSuscriber;
use App\Core\Entity\EntityInterface;
use App\Core\Event\EntityManager\EntityManagerEvent;
use App\Core\EventSuscriber\EntityManagerEventSubscriber;
use App\Entity\MyEntity;
class MyEntityEventSubscriber extends EntityManagerEventSubscriber
{
public function support(EntityInterface $entity)
{
return $entity instanceof MyEntity;
}
public function onCreate(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
// ...
}
public function onUpdate(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
// ...
}
public function onDelete(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
// ...
}
public function onPreCreate(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
// ...
}
public function onPreUpdate(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
// ...
}
public function onPreDelete(EntityManagerEvent $event)
{
if (!$this->support($event->getEntity())) {
return;
}
// ...
}
}
```

44
docs/entities/factory.md Normal file
View file

@ -0,0 +1,44 @@
# Factory
Each entity should have a factory that helps to generate a new entity.
A factory must implements `App\Core\Factory\FactoryInterface`.
## Implementation
A factory is basically a service which contain at lease a method named `create`.
```
// src/Factory/MyEntityFactory;
namespace App\Factory;
use App\Core\Factory\FactoryInterface;
use App\Entity\MyEntity;
class MyEntityFactory implements FactoryInterface
{
public function create(/* specify parameters if needed */): MyEntity
{
return new MyEntity();
}
}
```
## Usage
```
// src/Controller/FooController.php
namespace App\Controller;
use App\Factory\MyEntityFactory;
use Symfony\Component\HttpFoundation\Response;
class FooController
{
public function foo(MyEntityFactory $factory): Response
{
$entity = $factory->create();
// ...
}
}
```

99
docs/entities/query.md Normal file
View file

@ -0,0 +1,99 @@
# Repository Query
A Repository query is an abstraction of the doctrine repository.
## Implementation
Entities must implements `App\Core\Entity\EntityInterface`.
```
// src/Entity/MyEntity.php
namespace App\Entity;
use App\Repository\MyEntityRepository;
use Doctrine\ORM\Mapping as ORM;
use App\Core\Entity\EntityInterface;
/**
* @ORM\Entity(repositoryClass=MyEntityRepository::class)
*/
class MyEntity implements EntityInterface
{
// ...
}
```
Each entity has its own repository query which is a service.
```
// src/Repository/MyEntityRepositoryQuery;
namespace App\Repository;
use App\Core\Repository\RepositoryQuery;
use Knp\Component\Pager\PaginatorInterface;
class MyEntityRepositoryQuery extends RepositoryQuery
{
public function __construct(MyEntityRepository $repository, PaginatorInterface $paginator)
{
parent::__construct($repository, 'm', $paginator);
}
// Example of custom filter
public function filterByFooBar(bool $foo, bool $bar): self
{
$this
->andWhere('.foo = :foo')
->andWhere('.bar = :bar')
->setParameter(':foo', $foo)
->setParameter(':bar', $bar);
return $this;
}
}
```
## Usage
You are able to find entities in an easy way, without knowing the identification variable and without creating a query builder.
```
// src/Controller/FooController.php
namespace App\Controller;
use App\Repository\MyEntityRepositoryQuery
use Symfony\Component\HttpFoundation\Response;
class FooController
{
public function foo(MyEntityRepositoryQuery $query): Response
{
$entities = $query->create()->find();
$entity = $query->create()->findOne();
// Filtered and sorted entities
$entities = $query->create()
->orderBy('.id', 'DESC')
->where('.isPublished = true')
->find();
// ...
}
}
```
If you haved implemented specific methods:
```
$entities = $query->create()
->filterByFoo($foo, $bar)
->find();
```
## Pager
You can paginate entities (`Knp\Component\Pager\Pagination\PaginationInterface`):
```
$pager = $query->create()->paginate($page, $maxPerPage);
```

View file

@ -1,7 +1,5 @@
# Global settings
![](/_static/img/settings/02.png)
## Create settings
The creation of settings is based on events.
@ -66,6 +64,10 @@ class SettingEventSubscriber extends EventSubscriber
}
```
Result:
![](/_static/img/settings/02.png)
## Access settings
Settings are accessible using `App\Core\Setting\SettingManager` which is a service.

View file

@ -1,7 +1,5 @@
# Navigation settings
![](/_static/img/settings/03.png)
## Create settings
The creation of settings is based on events.
@ -67,6 +65,9 @@ class NavigationSettingEventSubscriber extends EventSubscriber
}
}
```
Result:
![](/_static/img/settings/03.png)
## Access settings
@ -82,13 +83,13 @@ use Symfony\Component\HttpFoundation\Response;
class FooController
{
public function foo(NavigationSettingManager $settingManager, SiteRequest $siteRequest): Response
{
$trackerCode = $settingManager->get($siteRequest->getNavigation(), 'nav_tracker_code');
$contactEmail = $settingManager->get($siteRequest->getNavigation(), 'nav_contact_email');
public function foo(NavigationSettingManager $settingManager, SiteRequest $siteRequest): Response
{
$trackerCode = $settingManager->get($siteRequest->getNavigation(), 'nav_tracker_code');
$contactEmail = $settingManager->get('my_nav', 'nav_contact_email');
// ...
}
// ...
}
}
```
@ -113,13 +114,13 @@ use Symfony\Component\HttpFoundation\Response;
class FooController
{
public function foo(NavigationSettingManager $settingManager, SiteRequest $siteRequest): Response
{
$settingManager->set($siteRequest->getNavigation(), 'nav_tracker_code', '...');
$settingManager->set('my_nav', 'nav_contact_email', '...');
public function foo(NavigationSettingManager $settingManager, SiteRequest $siteRequest): Response
{
$settingManager->set($siteRequest->getNavigation(), 'nav_tracker_code', '...');
$settingManager->set('my_nav', 'nav_contact_email', '...');
// ...
}
// ...
}
}
```

View file

@ -1,8 +1,6 @@
# Tasks
![](/img/tasks/01.png)
Tasks are executable from UI. The creation of tasks is based on events.
Tasks are scripts executabled from UI. The creation of tasks is based on events.
```
// src/EventSuscriber/MyTaskEventSubscriber.php
@ -34,4 +32,6 @@ class MyTaskEventSubscriber extends TaskEventSubscriber
}
```
![](/img/tasks/02.png)
![](/_static/img/tasks/01.png)
![](/_static/img/tasks/02.png)

View file

@ -10,6 +10,10 @@ nav:
- Overview: tree/index.md
- Navigation: tree/navigation.md
- Menu: tree/menu.md
- Entities:
- 'Entity Manager': entities/em.md
- 'Repository Query': entities/query.md
- Factory: entities/factory.md
- CRUD:
- Overview: crud/index.md
- Generator: crud/generator.md
@ -19,5 +23,5 @@ nav:
- 'Navigation settings': settings/navigation.md
- Users:
- Users: users.md
- Others:
- Tasks:
- Tasks: tasks.md