1
votes

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?
1

1 Answers

2
votes

You could create your own DI Extension. It basically allows you to specify your own YML configuration tree and how to generate services / parameters from it. You could only specify relevant items in the YML and all the repository / configurator / controller services generate dynamically:

my_superior_crud:
    Job:
        fields:
            - Title
            - Description
            - From
            # ...
        template: 'AdminBundle:Job:list.html.twig'
        route_path: '/{page}'
        # ...
    # ...

The extensions are briefly mentioned in the docs, but you can find some decent articles (like this one, or this one). Also see the existing extensions (twig is quite easy to understand).

And to your second question, yes, it is very likely the cache generation.