Skip to content

Commit

Permalink
Merge pull request #275 from aksm/ISSUE-274
Browse files Browse the repository at this point in the history
ISSUE-274: Report render array output error in Metadata Display preview
  • Loading branch information
DiegoPino authored Mar 29, 2023
2 parents 09f5141 + ddc4893 commit 859cea7
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 5 deletions.
28 changes: 28 additions & 0 deletions format_strawberryfield.module
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,31 @@ function format_strawberryfield_cron() {

}

/**
* Provides custom PHP error handling when processing ajax previews.
*
* Converts trigger_error() to WARNING so that an exceptions can be thrown
* and caught by
* \Drupal\format_strawberryfield\MetadataDisplayForm::ajaxPreview().
*
* @param int $error_level
* The level of the error raised.
* @param string $message
* The error message.
* @param string $filename
* (optional) The filename that the error was raised in.
* @param string $line
* (optional) The line number the error was raised at.
* @param array $context
* (optional) An array that points to the active symbol table at the point the
* error occurred.
*
* @throws \ErrorException
* Throw ErrorException for all errors passed from trigger_error().
*
* @see \Drupal\format_strawberryfield\MetadataDisplayForm::ajaxPreview()
*/
function _format_strawberryfield_metadata_preview_error_handler($error_level, $message, $filename = NULL, $line = NULL, $context = NULL) {
_drupal_error_handler(E_WARNING, $message, $filename, $line, $context);
throw new ErrorException($message, $error_level, 0, $filename, $line);
}
19 changes: 14 additions & 5 deletions src/Entity/MetadataDisplayEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use Drupal\Core\Cache\Cache;
use Twig\Node\ModuleNode;
use Twig\Node\BodyNode;
use Twig\Node\Node;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\ContentEntityBase;
Expand Down Expand Up @@ -402,6 +404,7 @@ public function renderNative(array $context) {
$twigtemplate,
$context
);

return $rendered;
}

Expand Down Expand Up @@ -429,29 +432,35 @@ public function getTwigVariablesUsed() {
* @param \Twig\Node\ModuleNode $nodes
* A Twig Module Nodes object.
*
* @param \Twig\Node\BodyNode $nodes
* A Twig Module Nodes object.
*
* @param \Twig\Node\Node $nodes
* A Twig Module Nodes object.
*
* @return array
* A list of used $variables by this template.
*/
private function getTwigVariableNames(ModuleNode $nodes): array {
private function getTwigVariableNames(ModuleNode|Node|BodyNode $nodes): array {
$variables = [];
foreach ($nodes as $node) {
if ($node instanceof \Twig_Node_Expression_Name) {
if ($node instanceof \Twig\Node\Expression\NameExpression) {
$name = $node->getAttribute('name');
$variables[$name] = $name;
}
elseif ($node instanceof \Twig_Node_Expression_Constant && $nodes instanceof \Twig_Node_Expression_GetAttr) {
elseif ($node instanceof \Twig\Node\Expression\ConstantExpression && $nodes instanceof \Twig\Node\Expression\GetAttrExpression) {
$value = $node->getAttribute('value');
if (!empty($value) && is_string($value)) {
$variables[$value] = $value;
}
}
elseif ($node instanceof \Twig_Node_Expression_GetAttr) {
elseif ($node instanceof \Twig\Node\Expression\GetAttrExpression) {
$path = implode('.', $this->getTwigVariableNames($node));
if (!empty($path)) {
$variables[$path] = $path;
}
}
elseif ($node instanceof \Twig_Node) {
elseif ($node instanceof \Twig\Node\Node) {
$variables += $this->getTwigVariableNames($node);
}
}
Expand Down
61 changes: 61 additions & 0 deletions src/Form/MetadataDisplayForm.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,13 @@ public function save(array $form, FormStateInterface $form_state) {
* AJAX callback.
*/
public static function ajaxPreview($form, FormStateInterface $form_state) {
set_error_handler('_format_strawberryfield_metadata_preview_error_handler');
$response = new AjaxResponse();

/** @var \Drupal\format_strawberryfield\MetadataDisplayInterface $entity */
$entity = $form_state->getFormObject()->getEntity();

$used_vars = $entity->getTwigVariablesUsed();
// Attach the library necessary for using the OpenOffCanvasDialogCommand and
// set the attachments for this Ajax response.
$form['#attached']['library'][] = 'core/drupal.dialog.off_canvas';
Expand Down Expand Up @@ -252,6 +254,31 @@ public static function ajaxPreview($form, FormStateInterface $form_state) {
'mode' => 'application/json',
],
];
sort($used_vars);
$json_keys = array_keys($jsondata);
$data_json = array_map(function($key) {
return 'data.' . $key;
}, $json_keys);
$unused_vars = array_diff($data_json,$used_vars);
sort($unused_vars);
$used_rows = array_map(function($used) {
return [$used];
}, $used_vars);
$unused_rows = array_map(function($unused) {
return [$unused];
}, $unused_vars);
$var_table = [
'#type' => 'table',
'#header' => [t('Used Variables')],
'#rows' => $used_rows,
'#empty' => t('No content has been found.'),
];
$json_table = [
'#type' => 'table',
'#header' => [t('Unused JSON keys')],
'#rows' => $unused_rows,
'#empty' => t('No content has been found.'),
];

// Try to Ensure we're using the twig from user's input instead of the entity's
// default.
Expand Down Expand Up @@ -337,6 +364,22 @@ public static function ajaxPreview($form, FormStateInterface $form_state) {
],
];
}
$output['twig_vars'] = [
'#type' => 'details',
'#open' => FALSE,
'#title' => 'Twig Variables',
'render' => [
'table' => $var_table
],
];
$output['json_unused'] = [
'#type' => 'details',
'#open' => FALSE,
'#title' => 'Unused JSON keys',
'render' => [
'table' => $json_table
],
];
} catch (\Exception $exception) {
// Make the Message easier to read for the end user
if ($exception instanceof TwigError) {
Expand All @@ -354,7 +397,25 @@ public static function ajaxPreview($form, FormStateInterface $form_state) {
'#markup' => $message,
]
];
$output['twig_vars'] = [
'#type' => 'details',
'#open' => FALSE,
'#title' => 'Twig Variables',
'render' => [
'table' => $var_table
],
];
$output['json_unused'] = [
'#type' => 'details',
'#open' => FALSE,
'#title' => 'Unused JSON keys',
'render' => [
'table' => $json_table
],
];
}
restore_error_handler();
restore_exception_handler();
$response->addCommand(new OpenOffCanvasDialogCommand(t('Preview'), $output, ['width' => '50%']));
}
// Always refresh the Preview Element too.
Expand Down

0 comments on commit 859cea7

Please sign in to comment.