My goal is to have a fully functional CRUD admin UI by creating 3 files (an entity yml, a list twig and an edit twig) and editing another 3 existing ones (services.yml, parameters.yml and routing.yml).
The twigs will inherit a base template that ensures the context (header, sidebar, footer, bootstrap styling, javascripts, etc.), while the entity yml will require a doctriine:generate:entities command so I can get the entity as a plain php object.
Example:
Entities:
Job:
- title
- description
- from
- till
- url
Project:
- title:
- status:
- url:
- description
User (inheriting FOSUserBundle Entity):
- clientId
- clientSecret
- socialNetwork
- profile
- avatar
Since I want my code to be DRY, I thought I should use a service controller that gets some setter Injection for the requirements. One of the injected objects is a class for defining the controller configuration (e.g. what Repository to query, what method to use in that repository, what template to render, etc.), called Configurator.
Based on the above entities example, in order to get a functional Job listing, I figured I need the following services:
- a Repository service
- a Configurator service
- a Controller service
In services.yml will be a batch of these three services above for each entity, all with different names. Example: admin.job.repository, admin.project.repository. At first sight, it's not very DRY, but as long as you have to duplicate only configuration files, my lucky guess is that I'm still achieving my main purpose.
Example:
Repository service: admin.job.repository: class: Doctrine\ORM\EntityRepository factory_service: doctrine.orm.default_entity_manager factory_method: getRepository arguments: - AppBundle\Entity\Job
Configurator service:
admin.job.config.list: class: AppBundle\Configurator\ListControllerConfigurator arguments: - @admin.job.repository - "AdminBundle:Job:list.html.twig" calls: - [ setRepoMethod, ["findJobsForTimeline"] ] - [ setPerPage, [%knp_paginator.page_range%]] - [ setParameters, [%admin.job.list.parameters%]]
In Configurator, I used arguments for mandatory injections and setters as optional parameters that have hardcoded default fallbacks in PHP. (e.g. findAll for repo, 10 for perPage, etc.).
Controller service: admin.job.controller.list: class: AdminBundle\ListController arguments: - @admin.job.config.list calls: - [setContainer, [@service_container] ]
Routing configuration:
admin_Job_list: path: /{page} defaults: { _controller: admin.job.controller.list:listAction, page: 1 } requirements: page: \d+
The code is fully functional and renders the listing pages as intended.
My questions are:
- is there any other better way to handle the code duplication? I got myself inspired from Sonata, EasyAdmin and other similar bundles while creating this; all of the above are mature, complex bundles, but I what I wanted is a self-made wheel that has a didactic (show-off) purpose
- why does any request take between 5 and 30 seconds to complete after any change in services.yml, routing.yml or parameters.yml? from what I've seen, services.yml gets translated into plain PHP in app/cache/dev/appDevDebugProjectContainer.php - is this the cause?