Initial commit: CloudOps infrastructure platform
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\ApiBundle\Helper;
|
||||
|
||||
use Mautic\CoreBundle\Helper\CsvHelper;
|
||||
|
||||
class BatchIdToEntityHelper
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $ids = [];
|
||||
|
||||
private array $originalKeys = [];
|
||||
|
||||
private array $errors = [];
|
||||
|
||||
private bool $isAssociative = false;
|
||||
|
||||
/**
|
||||
* @param string $idKey
|
||||
*/
|
||||
public function __construct(
|
||||
array $parameters,
|
||||
private $idKey = 'id',
|
||||
) {
|
||||
$this->extractIds($parameters);
|
||||
}
|
||||
|
||||
public function hasIds(): bool
|
||||
{
|
||||
return !empty($this->ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getIds()
|
||||
{
|
||||
return $this->ids;
|
||||
}
|
||||
|
||||
public function hasErrors(): bool
|
||||
{
|
||||
return !empty($this->errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors()
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder the entities based on the original keys
|
||||
* BC allowed a request to have associative keys (don't ask why; yes it's terrible implementation but we're keeping BC here)
|
||||
* The issue this solves is the response should match the format given by the request. If the request had associative keys, the response
|
||||
* will return with associative keys (json object). If the request was a sequential numeric array starting with 0, the response will
|
||||
* be a simple array (json array).
|
||||
*/
|
||||
public function orderByOriginalKey(array $entities): array
|
||||
{
|
||||
if (!$this->isAssociative) {
|
||||
// The request was keyed by sequential numbers starting with 0
|
||||
return array_values($entities);
|
||||
}
|
||||
|
||||
// Ensure entities are keyed by ID in order to find the original keys assuming that some entities are missing if the ID was not found
|
||||
$entitiesKeyedById = [];
|
||||
foreach ($entities as $entity) {
|
||||
$entitiesKeyedById[$entity->getId()] = $entity;
|
||||
}
|
||||
|
||||
$orderedEntities = [];
|
||||
foreach ($this->ids as $key => $id) {
|
||||
if (!isset($entitiesKeyedById[$id])) {
|
||||
$hasPreviousId = array_filter(
|
||||
$entities,
|
||||
fn ($entity) => $id == $entity->getPreviousId()
|
||||
);
|
||||
|
||||
if ($hasPreviousId) {
|
||||
$orderedEntities[$key] = array_shift($hasPreviousId);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$originalKey = $this->originalKeys[$key];
|
||||
$orderedEntities[$originalKey] = $entitiesKeyedById[$id];
|
||||
}
|
||||
|
||||
return $orderedEntities;
|
||||
}
|
||||
|
||||
private function extractIds(array $parameters): void
|
||||
{
|
||||
$this->ids = [];
|
||||
|
||||
if (isset($parameters['ids'])) {
|
||||
$this->extractIdsFromIdKey($parameters['ids']);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->extractIdsFromParams($parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $ids
|
||||
*/
|
||||
private function extractIdsFromIdKey($ids): void
|
||||
{
|
||||
// ['ids' => [1,2,3]]
|
||||
if (is_array($ids)) {
|
||||
$this->isAssociative = $this->isAssociativeArray($ids);
|
||||
$this->ids = array_values($ids);
|
||||
$this->originalKeys = array_keys($ids);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ['ids' => '1,2,3'] OR ['ids' => '1']
|
||||
if (str_contains($ids, ',') || is_numeric($ids)) {
|
||||
$this->ids = CsvHelper::strGetCsv($ids);
|
||||
$this->originalKeys = array_keys($this->ids);
|
||||
$this->isAssociative = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Couldn't parse the 'ids' key; not throwing an exception in order to keep BC with
|
||||
// the old CommonApiController code and the use of a foreach in extractIdsFromParams
|
||||
$this->errors[] = 'mautic.api.call.id_missing';
|
||||
}
|
||||
|
||||
private function extractIdsFromParams(array $parameters): void
|
||||
{
|
||||
$this->isAssociative = $this->isAssociativeArray($parameters);
|
||||
$this->originalKeys = array_keys($parameters);
|
||||
|
||||
// [1,2,3]
|
||||
$firstKey = array_key_first($parameters);
|
||||
if (!is_array($parameters[$firstKey])) {
|
||||
$this->ids = array_values($parameters);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// [ ['id' => 1, 'foo' => 'bar'], ['id' => 2, 'bar' => 'foo'] ]
|
||||
foreach ($parameters as $key => $params) {
|
||||
// Missing id column key in the array; terrible but keep BC
|
||||
if (!isset($params[$this->idKey])) {
|
||||
$this->errors[$key] = 'mautic.api.call.id_missing';
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->ids[] = $params[$this->idKey];
|
||||
}
|
||||
}
|
||||
|
||||
private function isAssociativeArray(array $array): bool
|
||||
{
|
||||
if (empty($array)) {
|
||||
return false;
|
||||
}
|
||||
$firstKey = array_key_first($array);
|
||||
|
||||
return array_keys($array) !== range(0, count($array) - 1) && 0 !== $firstKey;
|
||||
}
|
||||
|
||||
public function setIsAssociative(bool $isAssociative): void
|
||||
{
|
||||
$this->isAssociative = $isAssociative;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\ApiBundle\Helper;
|
||||
|
||||
use Doctrine\ORM\Tools\Pagination\Paginator;
|
||||
|
||||
class EntityResultHelper
|
||||
{
|
||||
/**
|
||||
* @param array<mixed>|Paginator<mixed> $results
|
||||
* @param callable|null $callback
|
||||
*
|
||||
* @return array<mixed>|\ArrayObject<int,mixed>
|
||||
*/
|
||||
public function getArray($results, $callback = null)
|
||||
{
|
||||
$entities = [];
|
||||
|
||||
// we have to convert them from paginated proxy functions to entities in order for them to be
|
||||
// returned by the serializer/rest bundle
|
||||
foreach ($results as $key => $entityRow) {
|
||||
$entities[$key] = $this->getEntityData($entityRow);
|
||||
|
||||
if (is_callable($callback)) {
|
||||
$callback($entities[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// solving array/object discrepancy for empty values
|
||||
if ($this->isKeyedById($results) && empty($entities)) {
|
||||
$entities = new \ArrayObject();
|
||||
}
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $entityRow
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getEntityData($entityRow)
|
||||
{
|
||||
if (is_array($entityRow) && isset($entityRow[0])) {
|
||||
return $this->getDataForArray($entityRow);
|
||||
}
|
||||
|
||||
return $entityRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getDataForArray($array)
|
||||
{
|
||||
if (is_object($array[0])) {
|
||||
return $this->getDataForObject($array);
|
||||
}
|
||||
|
||||
return $array[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $object
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function getDataForObject($object)
|
||||
{
|
||||
foreach ($object as $key => $value) {
|
||||
if (0 === $key) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$object[0]->$key = $value;
|
||||
}
|
||||
|
||||
return $object[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed>|Paginator<mixed> $results
|
||||
*/
|
||||
private function isKeyedById($results): bool
|
||||
{
|
||||
return !$results instanceof Paginator;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Mautic\ApiBundle\Helper;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
class RequestHelper
|
||||
{
|
||||
public static function hasBasicAuth(Request $request): bool
|
||||
{
|
||||
return str_starts_with(strtolower((string) $request->headers->get('Authorization')), 'basic');
|
||||
}
|
||||
|
||||
public static function isApiRequest(Request $request): bool
|
||||
{
|
||||
$requestUrl = $request->getRequestUri();
|
||||
|
||||
// Check if /oauth or /api
|
||||
$isApiRequest = (str_contains($requestUrl, '/oauth') || str_contains($requestUrl, '/api'));
|
||||
|
||||
defined('MAUTIC_API_REQUEST') or define('MAUTIC_API_REQUEST', $isApiRequest);
|
||||
|
||||
return $isApiRequest;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user