Skip to content

Instantly share code, notes, and snippets.

@sgrossberndt
Last active August 30, 2017 11:46
Show Gist options
  • Save sgrossberndt/a4a0b365c3b51f4c2de76d2530dc8ed0 to your computer and use it in GitHub Desktop.
Save sgrossberndt/a4a0b365c3b51f4c2de76d2530dc8ed0 to your computer and use it in GitHub Desktop.
A JsonView extending ExtbaseJsonView to circumvent some of the performance problems
<?php
declare(strict_types=1);
namespace MyVendor\MyExtension\View;
use TYPO3\CMS\Extbase\Mvc\View\JsonView as ExtbaseJsonView;
use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;
class JsonView extends ExtbaseJsonView {
/**
* Always transform ObjectStorage to Array
*
* @param mixed $value
* @param array $configuration
* @return array
* @see https://usetypo3.com/json-view.html
*/
protected function transformValue($value, array $configuration) {
if ($value instanceof ObjectStorage) {
$value = $value->toArray();
}
return parent::transformValue($value, $configuration);
}
private $propertyNames = [];
/**
* Traverses the given object structure in order to transform it into an
* array structure.
*
* @param object $object Object to traverse
* @param array $configuration Configuration for transforming the given object or NULL
* @return array Object structure as an array
*/
protected function transformObject($object, array $configuration) {
$class = get_class($object);
// for objects from MyExtension
if (strpos($class, 'MyVendor\\MyExtension\\Domain\\Model\\') === 0) {
// fetch available properties only once per class instead of for each object, as all objects in our extension have the same properties available
if (!isset($this->propertyNames[$class])) {
$this->propertyNames[$class] = ObjectAccess::getGettablePropertyNames($object);
}
$propertiesToRender = [];
foreach ($this->propertyNames[$class] as $propertyName) {
if (isset($configuration['_only']) && is_array($configuration['_only']) && !in_array($propertyName, $configuration['_only'])) {
continue;
}
if (isset($configuration['_exclude']) && is_array($configuration['_exclude']) && in_array($propertyName, $configuration['_exclude'])) {
continue;
}
// do not fetch getters by reflection for each object, but call them directly, as all are available as 'get' . ucfirst($propertyName)
$propertyValue = $object->{'get' . ucfirst($propertyName)}();
if (!is_array($propertyValue) && !is_object($propertyValue)) {
$propertiesToRender[$propertyName] = $propertyValue;
} elseif (!isset($configuration['_descend']) || !array_key_exists($propertyName, $configuration['_descend'])) {
throw new \Exception('The following property was fetched but not used at all! ' . $class . '->get' . ucfirst($propertyName));
} elseif (isset($configuration['_descend']) && array_key_exists($propertyName, $configuration['_descend'])) {
$propertiesToRender[$propertyName] = $this->transformValue($propertyValue, $configuration['_descend'][$propertyName]);
}
}
} else {
$propertiesToRender = parent::transformObject($object, $configuration);
}
return $propertiesToRender;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment