Add Symfony 4-compatible element infrastructure#1367
Merged
Conversation
…istration for ElementInventoryService
…ce to work with element entities
…d attribute, provide mb-element, toolBarItem classes
…y) ElementFilter service
…ntity-only ElementFilter instead
… ApplicationAssetService
…g else with empty content markup)
…mponent\Element-unaware ElementEntityFactory)
… Application via backend
…Interface) in element inventory
…mespacing of Entity\\Element
… for service-type elements
…t in ElementFilter scope
…tend config and asset references (check all only for markup)
…recate getAdjustedElementClassName
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Mapbender Elements inheriting from Mapbender\CoreBundle\Component\Element will inherently be incompatible with Symfony 4.
This pull adds new infrastructure to allow writing Elements that will work on Symfony 4.
Conformant Element classes must implement Mapbender\Component\Element\ElementServiceInterface (alternatively extend Mapbender\Component\Element\AbstractElementService, which implements the interface already).
Conformant Element classes must be registered as a service and tagged with
mapbender.element. Use standard Symfony DI to pass services / global configuration parameters into the constructor. E.g.:NOTE: omitting the id is an error on Symfony 4.
NOTE: do not attempt injecting the full container as
service.container. This is an error on Symfony 4.Redundantly naming the class name of a tagged Element service in the return value of a MapbenderBundle::getElements method is discouraged.
API comparison
Element services retain some of the static API from legacy Component\Element. Namely the static methods
getClassTitle,getClassDescription,getDefaultConfiguration,getFormTemplate,getType(=backend form type FQCN).Non-static method
getWidgetNamenow receives the Element entity as the first argument (same name).Non-static method
getRequiredAssets(renamed for clarity / signature sanity) receives the Element entity as the first argument, and functionally replaces both Component\Element::getAssets and (super legacy) static listAssets.NOTE: Service-type Elements do not support legacy automatic bundle name amending ('file.js' => '@MagicallyInflectedBundle/Resources/public/file.js') for their asset requirements. References to required assets must be returned in properly qualified form. Magic bundle scope inflection of assets has been deprecated since Mapbender v3.0.8-beta1.
Non-static method
getClientConfiguration(renamed for clarity / signature sanity) receives the Element entity as the first argument, and functionally replaces Component\Element::getPublicConfigurationNon-static method
getViewreceives the Element entity as the first argument, and must return either a StaticView (empty or trivially prerendered content) or a TemplateView, or a falsy PHP value. This functionally replaces Component\Element'sgetFrontendTemplatePath,getFrontendTemplateVarsandrendermethods.There are no longer any "utility methods" (getTitle, getId, getEntity, getConfiguration, getMapEngineCode). The Element entity is universally available as an argument.
Frontend markup rendering changes
Service-type Elements are rendered by the system, according to what they return from
getView. Accessing the (twig) templating engine from inside the Element implementation is discouraged.Service-type Element frontend templates should drop wrapping
<div id="..." class="mb-element ..." ...tags. The outer tag is generated as appropriate for the enclosing region. E.g.<li id="..." class="mb-element toolBarItem">is generated in footers / headers; divs elsewhere.ElementView has a public
$attributesarray property that should be used to add any additional required attributes (e.g.titlefor tooltips,classto tie in extra CSS rules).NOTE that the
idattribute and class="mb-element" are added automatically, and should not be respecified.There is no longer any predetermined set of variables injected into templates. Any variables required to render the Element markup via (twig) template must be explicitly placed into the TemplateView's
$variables(public array property).The
getViewmethod may return false to suppress frontend markup entirely. This is useful for Elements that, after dynamically inspecting configuration / Application circumstances, cannot reasonably function and should not render at all (e.g. control buttons with disabled target Elements; ViewManager with grants settings that disallow any interaction for the current user).Http handling changes
Http request handling is frequently the most complex part of any Element, with many service / parameter dependencies. To reduce common initialization overhead, http handling is now inflected via the
getHttpHandlermethod.getHttpHandlershould return the (DI'ed) http handling service or a falsy PHP value if no requests are handled.The handler must implement
ElementHttpHandlerInterface, requiring ahandleRequestmethod.handleRequestreceives the Element entity and the (Symfony) Request object as arguments.NOTE that the passed Request object is the canonical current request passed down from the Symfony controller. Element services should not attempt accessing the
request_stackthemselves.NOTE that (in simple scenarios) an Element service may
return $this;fromgetHttpHandler, as long as it implements theElementHttpHandlerInterfaceitself (example: AboutDialog rewrite).There is no longer any default http handler implementation. AbstractElementService returns null from
getHttpHandler.This functionally replaces the
handleHttpRequestand (super legacy)httpActionmethods on Component\Element.Additional import processing
When cloning applications, or importing exported Applications, Elements that reference database objects in their configuration by id must adjust those ids (e.g. "layersets" are id references in the main map configuration; see main Map rewrite).
Affected Element services must implement the new ImportAware interface. This requires a method
onImport.onImportreceives the Element entity and a Mapper implementation as arguments.This functionally replaces Component\Element's
denormalizeConfigurationmethod.Declaring Element replacements
The
<tag name="mapbender.element" />allows areplacesproperty, which must, if present, contain (a comma-separated list of) previous Element class FQCN(s).This will indicate that the Element service will handle those other class names. This allows replacing Element legacy / undesired default, or even no longer existant Element implementations, that will only take effect if the defining configuration (=most likely the bundle containing it) is currently loaded.
E.g.
Explicitly declaring canonical class name
To maintain compatibility with existing db contents ("class" column in mb_core_element), a "canonical" class name is set when adding or editing Elements inside an Application. This avoids hard errors after deactivating a bundle with a reimplemented Element class that changes the handling class name.
By default, the canonical class name is the first entry in the
mapbender.elementtag'sreplacesattribute ifreplacesis specified, otherwise it is the FQCN of the handling service class itself.You may explicitly specify the canonical content of the mb_core_element table's "class" column. Canonical can be any string value (must not necessarily name an existing PHP class).
IOW, "replaces" maps the value in the mb_core_element "class" column to the PHP class implementing the Element logic, while "canonical" controls what is written into the mb_core_element "class" column.