Select Git revision
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
AxiosExtractor.php 4.58 KiB
<?php
namespace UnicaenVue\Axios;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Query;
class AxiosExtractor
{
public static $loopControl = 50;
const DATETIME_FORMAT = 'Y-m-d\TH:i:s.u\Z'; // timestamp ISO 8601 pour HTML5
protected array $triggers = [];
public static function extract($data, array $properties = [], array $triggers = [])
{
$axios = new self;
$axios->triggers = $triggers;
return $axios->extractData($data, $properties);
}
protected function extractData($data, array $properties = [], string $path = '')
{
$triggerPath = $path ? $path : '/';
if ($data instanceof Query) {
$result = $this->extractData($data->getResult(), $properties, '');
} elseif ($this->isList($data)) {
$result = $this->extractList($data, $properties, $path);
$triggerPath .= '[]';
} elseif (is_array($data)) {
$result = $this->extractArray($data, $properties, $path);
} elseif ($data instanceof \DateTime) {
$result = $data->format(self::DATETIME_FORMAT);
} elseif (is_object($data)) {
$result = $this->extractObject($data, $properties, $path);
} else {
$result = $data;
}
if (array_key_exists($triggerPath, $this->triggers) && !$data instanceof Query) {
// trigger est un callable qui accepte deux arguments : le premier les la donnée originale, le second la donnée extraite
// il doit retourner une donnée qui remplacera la donnée extraite
$result = $this->triggers[$triggerPath]($data, $result);
}
return $result;
}
protected function extractObject($data, array $properties, string $path = ''): array
{
// contrôle de boucle récursive, afin de ne pas saturer la mémoire...
if (substr_count($path, '/') >= self::$loopControl) {
//return [];
throw new \Exception("AxiosExtractor has detected a possible infinite loop, and aborted your script with a stack depth of '" . self::$loopControl . "' frames");
}
$result = [];
if (empty($properties) && $data instanceof AxiosExtractorInterface) {
$properties = $data->axiosDefinition();
}
foreach ($properties as $property) {
if (is_array($property)) {
$subProperties = $property[1];
$property = $property[0];
} else {
$subProperties = [];
}
$methods = [
$property,
'get' . ucfirst($property),
'is' . ucfirst($property),
'has' . ucfirst($property),
];
foreach ($methods as $method) {
if (method_exists($data, $method)) {
$value = $data->$method();
$result[$property] = $this->extractData($value, $subProperties, $path . '/' . $property);
break;
}
}
}
return $result;
}
protected function extractArray(array $data, array $properties, string $path = ''): array
{
$result = [];
if (empty($properties)) {
$properties = array_keys($data);
}
foreach ($properties as $property) {
if (is_array($property)) {
$subProperties = $property[1];
$property = $property[0];
} else {
$subProperties = [];
}
if (array_key_exists($property, $data)) {
$result[$property] = $this->extractData($data[$property], $subProperties, $path . '/' . $property);
}
}
return $result;
}
protected function extractList($list, array $properties = [], string $path = ''): array
{
$result = [];
foreach ($list as $index => $sobj) {
$result[$index] = $this->extractData($sobj, $properties, $path);
}
return $result;
}
protected function isList($data): bool
{
if ($data instanceof Collection) {
return true;
}
if (!is_array($data)) {
return false;
}
foreach ($data as $k => $v) {
if (!is_numeric($k)) {
// une clé non numérique est rejetée
return false;
}
if (!(is_array($v) || is_object($v))) {
// une liste doit être une liste d'objets ou bien une liste de tableaux
return false;
}
}
return true;
}
}