Skip to content

Commit

Permalink
Introduced the "template" field option to define a custom template to…
Browse files Browse the repository at this point in the history
… render the field
  • Loading branch information
javiereguiluz committed Jul 18, 2015
1 parent 64f88cd commit fe745cc
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 57 deletions.
37 changes: 37 additions & 0 deletions Configuration/Configurator.php
Expand Up @@ -34,6 +34,7 @@ class Configurator
'dataType' => null, // Data type (text, date, integer, boolean, ...) of the Doctrine property associated with the field
'virtual' => false, // is a virtual field or a real Doctrine entity property?
'sortable' => true, // listings can be sorted according to the values of this field
'template' => null, // the path of the template used to render the field in 'show' and 'list' views
);

private $doctrineTypeToFormTypeMap = array(
Expand Down Expand Up @@ -104,6 +105,8 @@ public function getEntityConfiguration($entityName)

$entityConfiguration = $this->introspectGettersAndSetters($entityConfiguration);

$entityConfiguration = $this->processFieldTemplates($entityConfiguration);

$this->entitiesConfig[$entityName] = $entityConfiguration;

return $entityConfiguration;
Expand Down Expand Up @@ -458,6 +461,40 @@ private function introspectGettersAndSetters($entityConfiguration)
return $entityConfiguration;
}


/**
* Determines the template used to render each backend element. This is not
* trivial because templates can depend on the entity displayed and they
* define an advanced override mechanism.
*
* @param array $entityConfiguration
*
* @return array
*/
private function processFieldTemplates(array $entityConfiguration)
{
foreach (array('list', 'show') as $view) {

This comment has been minimized.

Copy link
@Pierstoval

Pierstoval Jul 18, 2015

Contributor

We could also resolve templates for edit and new views and handle them in Twig, by passing all needed arguments to render a form field, I still don't understand why ya'll want to restrict this great behavior to only list and show 😕

foreach ($entityConfiguration[$view]['fields'] as $fieldName => $fieldMetadata) {
if (null !== $fieldMetadata['template']) {
continue;
}

// this prevents the template from displaying the 'id' primary key formatted as a number
if ('id' === $fieldName) {
$template = $entityConfiguration['templates']['field_id'];
} elseif (array_key_exists('field_'.$fieldMetadata['type'], $entityConfiguration['templates'])) {
$template = $entityConfiguration['templates']['field_'.$fieldMetadata['type']];
} else {
$template = $entityConfiguration['templates']['label_undefined'];
}

$entityConfiguration[$view]['fields'][$fieldName]['template'] = $template;
}
}

return $entityConfiguration;
}

/**
* Returns the most appropriate Symfony Form type for the given Doctrine type.
*
Expand Down
70 changes: 33 additions & 37 deletions DependencyInjection/EasyAdminExtension.php
Expand Up @@ -18,6 +18,8 @@

class EasyAdminExtension extends Extension
{
private $views = array('edit', 'list', 'new', 'show');

private $defaultActionConfiguration = array(
'name' => null, // either the name of a controller method or an application route (it depends on the 'type' option)
'type' => 'method', // 'method' if the action is a controller method; 'route' if it's an application route
Expand Down Expand Up @@ -201,7 +203,7 @@ public function processEntityActions(array $backendConfiguration)
$entityConfiguration['disabled_actions'] = $disabledActions;

// second, define the actions of each entity view
foreach (array('edit', 'list', 'new', 'show') as $view) {
foreach ($this->views as $view) {
$defaultActions = $this->getDefaultActions($view);
$backendActions = isset($backendConfiguration[$view]['actions']) ? $backendConfiguration[$view]['actions'] : array();
$backendActions = $this->normalizeActionsConfiguration($backendActions, $defaultActions);
Expand Down Expand Up @@ -392,31 +394,25 @@ private function filterRemovedActions(array $actionsConfiguration)
*/
private function processEntityTemplates(array $backendConfiguration)
{
$applicationTemplatesDir = $this->kernelRootDir.'/Resources/views';

$customFieldTypesTemplates = $this->getCustomFieldTypesTemplates($backendConfiguration);
$templates = array_merge($this->defaultBackendTemplates, $customFieldTypesTemplates);
$templatesDir = $this->kernelRootDir.'/Resources/views';

// first, resolve the general template overriding mechanism
foreach ($backendConfiguration['entities'] as $entityName => $entityConfiguration) {
foreach ($templates as $templateName => $defaultTemplatePath) {
foreach ($this->defaultBackendTemplates as $templateName => $defaultTemplatePath) {
// 1st level priority: easy_admin.entities.<entityName>.templates.<templateName> config option
if (isset($entityConfiguration['templates'][$templateName])) {
$template = $entityConfiguration['templates'][$templateName];
// 2nd level priority: easy_admin.design.templates.<templateName> config option
} elseif (isset($backendConfiguration['design']['templates'][$templateName])) {
$template = $backendConfiguration['design']['templates'][$templateName];
// 3rd level priority: app/Resources/views/easy_admin/<entityName>/<templateName>.html.twig
} elseif (file_exists($applicationTemplatesDir.'/easy_admin/'.$entityName.'/'.$templateName.'.html.twig')) {
} elseif (file_exists($templatesDir.'/easy_admin/'.$entityName.'/'.$templateName.'.html.twig')) {
$template = 'easy_admin/'.$entityName.'/'.$templateName.'.html.twig';
// 4th level priority: app/Resources/views/easy_admin/<templateName>.html.twig
} elseif (file_exists($applicationTemplatesDir.'/easy_admin/'.$templateName.'.html.twig')) {
} elseif (file_exists($templatesDir.'/easy_admin/'.$templateName.'.html.twig')) {
$template = 'easy_admin/'.$templateName.'.html.twig';
// 5th level priority: @EasyAdmin/default/<templateName>.html.twig
} else {
if (array_key_exists($templateName, $customFieldTypesTemplates)) {
throw new \RuntimeException(sprintf('The "%s" entity uses a custom data type called "%s" but its associated template is not defined in "app/resources/views/easy_admin/"', $entityName, str_replace('field_', '', $templateName)));
}

$template = $defaultTemplatePath;
}

Expand All @@ -426,37 +422,37 @@ private function processEntityTemplates(array $backendConfiguration)
$backendConfiguration['entities'][$entityName] = $entityConfiguration;
}

return $backendConfiguration;
}

/**
* Returns the template names and paths for the custom field types defined
* on-the-fly by the entity for the 'show' and 'list' actions.
*
* @param array $backendConfiguration
*
* @return array
*/
private function getCustomFieldTypesTemplates(array $backendConfiguration)
{
$customTemplates = array();

// this 'array_flip()' nonsense is needed to apply 'array_filter()' on the keys instead of the values
$defaultFieldTypesTemplates = array_flip(array_filter(array_flip($this->defaultBackendTemplates), function ($key) {
return 'field_' === substr($key, 0, 6);
}));

// second, walk through all entity fields to determine their specific template
foreach ($backendConfiguration['entities'] as $entityName => $entityConfiguration) {
foreach (array('show', 'list') as $action) {
foreach ($entityConfiguration[$action]['fields'] as $fieldName => $fieldConfiguration) {
if (isset($fieldConfiguration['type']) && !array_key_exists($fieldTemplateName = 'field_'.$fieldConfiguration['type'], $defaultFieldTypesTemplates)) {
$customTemplates[$fieldTemplateName] = '@EasyAdmin/default/'.$fieldTemplateName.'.html.twig';
foreach (array('list', 'show') as $view) {
foreach ($entityConfiguration[$view]['fields'] as $fieldName => $fieldMetadata) {
// if the field defines its own template, resolve its location
if (isset($fieldMetadata['template'])) {
$templateName = $fieldMetadata['template'];

// 1st level priority: app/Resources/views/easy_admin/<entityName>/<templateName>.html.twig
if (file_exists($applicationTemplatesDir.'/easy_admin/'.$entityName.'/'.$templateName.'.html.twig')) {
$templatePath = 'easy_admin/'.$entityName.'/'.$templateName.'.html.twig';
// 2nd level priority: app/Resources/views/easy_admin/<templateName>.html.twig
} elseif (file_exists($applicationTemplatesDir.'/easy_admin/'.$templateName.'.html.twig')) {
$templatePath = 'easy_admin/'.$templateName.'.html.twig';
} else {
throw new \RuntimeException(sprintf('The "%s" field of the "%s" entity uses a custom template called "%s" which doesn\'t exist in "app/resources/views/easy_admin/" directory.', $fieldName, $entityName, $templateName));
}
} else {
// At this point, we don't know the exact data type associated with each field.
// The template is initialized to null and it will be resolved at runtime in the Configurator class
$templatePath = null;
}

$entityConfiguration[$view]['fields'][$fieldName]['template'] = $templatePath;
}
}

$backendConfiguration['entities'][$entityName] = $entityConfiguration;
}

return array_unique($customTemplates);
return $backendConfiguration;
}

/**
Expand Down
Expand Up @@ -38,8 +38,10 @@ easy_admin:
fields:
field5:
property: field5
template: null
field6:
property: field6
template: null
actions:
show:
name: show
Expand Down Expand Up @@ -75,8 +77,10 @@ easy_admin:
fields:
field7:
property: field7
template: null
field8:
property: field8
template: null
actions:
delete:
name: delete
Expand Down
Expand Up @@ -8,6 +8,7 @@ easy_admin:
property: field1
type: image
base_path: /field_img/
template: null
actions:
show:
name: show
Expand Down
Expand Up @@ -9,6 +9,7 @@ easy_admin:
property: field1
type: image
base_path: /entity_img/
template: null
actions:
show:
name: show
Expand Down
Expand Up @@ -9,6 +9,7 @@ easy_admin:
property: field1
type: image
base_path: /field_img/
template: null
actions:
show:
name: show
Expand Down
23 changes: 3 additions & 20 deletions Twig/EasyAdminTwigExtension.php
Expand Up @@ -127,16 +127,6 @@ public function renderEntityField(\Twig_Environment $twig, $view, $entityName, $
// when a virtual field doesn't define it's type, consider it a string
if (true === $fieldMetadata['virtual'] && null === $fieldType) {
$templateParameters['value'] = strval($value);

return $twig->render($entityConfiguration['templates']['field_text'], $templateParameters);
}

if ('id' === $fieldName) {
return $twig->render($entityConfiguration['templates']['field_id'], $templateParameters);
}

if (in_array($fieldType, array('date', 'datetime', 'datetimetz', 'time', 'bigint', 'integer', 'smallint', 'decimal', 'float'))) {
return $twig->render($entityConfiguration['templates']['field_'.$fieldType], $templateParameters);
}

if (in_array($fieldType, array('image'))) {
Expand All @@ -149,16 +139,10 @@ public function renderEntityField(\Twig_Environment $twig, $view, $entityName, $
: '/'.ltrim($value, '/');
}
$templateParameters['value'] = $imageUrl;

return $twig->render($entityConfiguration['templates']['field_image'], $templateParameters);
}

if (in_array($fieldType, array('array', 'simple_array'))) {
if (empty($value)) {
return $twig->render($entityConfiguration['templates']['label_empty'], $templateParameters);
}

return $twig->render($entityConfiguration['templates']['field_'.$fieldType], $templateParameters);
if (in_array($fieldType, array('array', 'simple_array')) && empty($value)) {
return $twig->render($entityConfiguration['templates']['label_empty'], $templateParameters);
}

if (in_array($fieldType, array('association'))) {
Expand Down Expand Up @@ -188,8 +172,7 @@ public function renderEntityField(\Twig_Environment $twig, $view, $entityName, $
return $twig->render($entityConfiguration['templates']['field_association'], $templateParameters);
}

// all the other data types: boolean, string, text, toggle
return $twig->render($entityConfiguration['templates']['field_'.$fieldType], $templateParameters);
return $twig->render($fieldMetadata['template'], $templateParameters);
} catch (\Exception $e) {
if ($this->debug) {
throw $e;
Expand Down

0 comments on commit fe745cc

Please sign in to comment.