<?php

namespace Ds\Component\Identity\Resolver\Context\Identity;

use DomainException;
use Ds\Component\Api\Api\Api;
use Ds\Component\Api\Query\AnonymousPersonaParameters;
use Ds\Component\Api\Query\IndividualPersonaParameters;
use Ds\Component\Api\Query\OrganizationPersonaParameters;
use Ds\Component\Api\Query\StaffPersonaParameters;
use Ds\Component\Security\Model\Identity;
use Ds\Component\Resolver\Exception\UnresolvedException;
use Ds\Component\Resolver\Resolver\Resolver;
use Exception;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

/**
 * Class PersonaResolver
 *
 * @package Ds\Component\Identity
 */
final class PersonaResolver implements Resolver
{
    /**
     * @const string
     */
    const PATTERN = '/^ds\[identity\]\.persona\.(.+)/';

    /**
     * @var \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface
     */
    private $tokenStorage;

    /**
     * @var \Ds\Component\Api\Api\Api
     */
    private $api;

    /**
     * Constructor
     *
     * @param \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface $tokenStorage
     * @param \Ds\Component\Api\Api\Api $api
     */
    public function __construct(TokenStorageInterface $tokenStorage, Api $api)
    {
        $this->tokenStorage = $tokenStorage;
        $this->api = $api;
    }

    /**
     * {@inheritdoc}
     */
    public function isMatch(string $variable, array &$matches = []): bool
    {
        $token = $this->tokenStorage->getToken();

        if (!$token) {
            return false;
        }

        if (!preg_match(static::PATTERN, $variable, $matches)) {
            return false;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function resolve(string $variable)
    {
        $matches = [];

        if (!$this->isMatch($variable, $matches)) {
            throw new UnresolvedException('Variable pattern "'.$variable.'" is not valid.');
        }

        $token = $this->tokenStorage->getToken();
        $user = $token->getUser();
        $identity = $user->getIdentity();

        switch ($identity->getType()) {
            case Identity::ANONYMOUS:
                $parameters = new AnonymousPersonaParameters;
                $parameters->setAnonymousUuid($identity->getUuid());
                $models = $this->api->get('identities.anonymous_persona')->getList($parameters);
                break;

            case Identity::INDIVIDUAL:
                $parameters = new IndividualPersonaParameters;
                $parameters->setIndividualUuid($identity->getUuid());
                $models = $this->api->get('identities.individual_persona')->getList($parameters);
                break;

            case Identity::ORGANIZATION:
                $parameters = new OrganizationPersonaParameters;
                $parameters->setOrganizationUuid($identity->getUuid());
                $models = $this->api->get('identities.organization_persona')->getList($parameters);
                break;

            case Identity::STAFF:
                $parameters = new StaffPersonaParameters;
                $parameters->setStaffUuid($identity->getUuid());
                $models = $this->api->get('identities.staff_persona')->getList($parameters);
                break;

            case Identity::SYSTEM:
            default:
                throw new DomainException('User identity "'.$identity->getType().'" is not valid.');
        }

        if (!$models) {
            throw new UnresolvedException('Variable pattern "'.$variable.'" did not resolve to data.');
        }

        $model = array_shift($models);
        $property = $matches[1];
        $accessor = PropertyAccess::createPropertyAccessor();

        // @todo look at removing this and standardizing arrays and objects globally
        if (preg_match('/^data\./', $property)) {
            $model = json_decode(json_encode($model->getData()), false);
            $property = substr($property, 5);
        }

        try {
            $value = $accessor->getValue($model, $property);
        } catch (Exception $exception) {
            throw new UnresolvedException('Variable pattern "'.$variable.'" did not resolve to data.', 0, $exception);
        }

        return $value;
    }
}


<?php

namespace Ds\Component\Identity\EventListener\Entity;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Ds\Component\Identity\Service\IdentityService;
use Ds\Component\Model\Type\Identitiable;

/**
 * Class IdentitiableListener
 *
 * @package Ds\Component\Identity
 */
final class IdentitiableListener
{
    /**
     * @var \Ds\Component\Identity\Service\IdentityService
     */
    private $identityService;

    /**
     * Constructor
     *
     * @param \Ds\Component\Identity\Service\IdentityService $identityService
     */
    public function __construct(IdentityService $identityService)
    {
        $this->identityService = $identityService;
    }

    /**
     * Assign the current session identity, if none provided
     *
     * @param \Doctrine\ORM\Event\LifecycleEventArgs $args
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if (!$entity instanceof Identitiable) {
            return;
        }

        $this->identityService->generateIdentity($entity);
    }
}


<?php

namespace Ds\Component\Formio\Fixture;

use Doctrine\Common\Persistence\ObjectManager;
use Ds\Component\Api\Api\Api;
use Ds\Component\Config\Service\ConfigService;
use Ds\Component\Formio\Exception\ValidationException;
use Ds\Component\Formio\Model\Form as FormModel;
use Ds\Component\Formio\Model\User as UserModel;
use Ds\Component\Database\Fixture\Yaml;

/**
 * Trait Form
 *
 * @package Ds\Component\Formio
 */
trait Form
{
    use Yaml;

    /**
     * @var string
     */
    private $path;

    /**
     * {@inheritdoc}
     */
    public function load(ObjectManager $manager)
    {
        $fixtures = array_key_exists('FIXTURES', $_ENV) ? $_ENV['FIXTURES'] : 'dev';
        $configService = $this->container->get(ConfigService::class);

        $api = $this->container->get(Api::class)->get('formio.authentication');
        $user = new UserModel;
        $user
            ->setEmail($configService->get('ds_api.user.username'))
            ->setPassword($configService->get('ds_api.user.password'));
        $token = $api->login($user);

        $api = $this->container->get(Api::class)->get('formio.role');
        $api->setHeader('x-jwt-token', $token);
        $roles = $api->getList();

        $api = $this->container->get(Api::class)->get('formio.form');
        $api->setHeader('x-jwt-token', $token);
        $objects = $this->parse($this->getResource());

        foreach ($objects as $object) {
            try {
                $api->delete($object->path);
            } catch (ValidationException $exception) {
                // @todo this is so first time fixtures dont cause an error, handle "Invalid alias" better
            }

            $form = new FormModel;
            $object->components = json_decode(file_get_contents(dirname(str_replace('{fixtures}', $fixtures, $this->path)).'/'.$object->components));
            $object->submission_access = json_decode(file_get_contents(dirname(str_replace('{fixtures}', $fixtures, $this->path)).'/'.$object->submission_access));
            $submissionAccess = [];

            foreach ($object->submission_access as $access) {
                foreach ($access->roles as $key => $value) {
                    foreach ($roles as $role) {
                        if ($role->getMachineName() === $value) {
                            $access->roles[$key] = $role->getId();
                            break;
                        }
                    }
                }

                $submissionAccess[] = $access;
            }

            $form
                ->setTitle($object->title)
                ->setDisplay($object->display)
                ->setType($object->type)
                ->setName($object->name)
                ->setPath($object->path)
                ->setTags($object->tags)
                ->setComponents($object->components)
                ->setSubmissionAccess($submissionAccess);
            $api->create($form);
        }
    }
}


<?php

namespace Ds\Component\Acl\Voter;

use Ds\Component\Acl\Collection\EntityCollection;
use Ds\Component\Acl\Model\Permission;
use Ds\Component\Acl\Service\AccessService;
use Ds\Component\Model\Type\Identitiable;
use Ds\Component\Model\Type\Ownable;
use Ds\Component\Model\Type\Uuidentifiable;
use Ds\Component\Security\Model\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

/**
 * Class EntityVoter
 *
 * @package Ds\Component\Acl
 * @example
 * <code>
 *     @Security("is_granted('BROWSE', object)")
 * </code>
 */
final class EntityVoter extends Voter
{
    /**
     * @var \Ds\Component\Acl\Service\AccessService
     */
    private $accessService;

    /**
     * @var \Ds\Component\Acl\Collection\EntityCollection
     */
    private $entityCollection;

    /**
     * Constructor
     *
     * @param \Ds\Component\Acl\Service\AccessService $accessService
     * @param \Ds\Component\Acl\Collection\EntityCollection $entityCollection
     */
    public function __construct(AccessService $accessService, EntityCollection $entityCollection)
    {
        $this->accessService = $accessService;
        $this->entityCollection = $entityCollection;
    }

    /**
     * {@inheritdoc}
     */
    protected function supports($attribute, $subject)
    {
        if (!in_array($attribute, [Permission::BROWSE, Permission::READ, Permission::EDIT, Permission::ADD, Permission::DELETE, Permission::EXECUTE], true)) {
            return false;
        }

        if (!is_object($subject)) {
            return false;
        }

        $class = get_class($subject);

        if (!$this->entityCollection->contains($class)) {
            return false;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        $user = $token->getUser();

        if (!$user instanceof User) {
            return false;
        }

        $permissions = $this->accessService->getPermissions($user);

        foreach ($permissions as $permission) {
            if (Permission::ENTITY !== $permission->getType()) {
                // Skip permissions that are not of type "entity".
                continue;
            }

            if (!fnmatch($permission->getValue(), get_class($subject), FNM_NOESCAPE)) {
                // Skip permissions that are not related to the subject entity.
                // The fnmatch function is used to match asterisk patterns.
                continue;
            }

            switch ($permission->getScope()) {
                case 'generic':
                    // Nothing to specifically validate.
                    break;

                case 'object':
                    if (!$subject instanceof Uuidentifiable) {
                        // Skip permissions with scope "object" if the subject entity is not uuidentitiable.
                        continue;
                    }

                    if ($permission->getEntityUuid() !== $subject->getUuid()) {
                        // Skip permissions that do not match the subject entity uuid.
                        continue;
                    }

                    break;

                case 'identity':
                    if (!$subject instanceof Identitiable) {
                        // Skip permissions with scope "identity" if the subject entity is not identitiable.
                        continue;
                    }

                    if (null !== $permission->getEntity()) {
                        if ($permission->getEntity() !== $subject->getIdentity()) {
                            // Skip permissions that do not match the subject entity identity.
                            continue;
                        }
                    }

                    if (null !== $permission->getEntityUuid()) {
                        if ($permission->getEntityUuid() !== $subject->getIdentityUuid()) {
                            // Skip permissions that do not match the subject entity identity uuid.
                            continue;
                        }
                    }

                    break;

                case 'owner':
                    if (!$subject instanceof Ownable) {
                        // Skip permissions with scope "owner" if the subject entity is not ownable.
                        continue;
                    }

                    if (null !== $permission->getEntity()) {
                        if ($permission->getEntity() !== $subject->getOwner()) {
                            // Skip permissions that do not match the subject entity owner.
                            continue;
                        }
                    }

                    if (null !== $permission->getEntityUuid()) {
                        if ($permission->getEntityUuid() !== $subject->getOwnerUuid()) {
                            // Skip permissions that do not match the subject entity owner uuid.
                            continue;
                        }
                    }

                    break;

                case 'session':
                    if (!$subject instanceof Identitiable) {
                        // Skip permissions with scope "session" if the subject entity is not identitiable.
                        continue;
                    }

                    if ($user->getIdentity()->getType() !== $subject->getIdentity()) {
                        // Skip permissions that do not match the subject entity identity.
                        continue;
                    }

                    if ($user->getIdentity()->getUuid() !== $subject->getIdentityUuid()) {
                        // Skip permissions that do not match the subject entity identity uuid.
                        continue;
                    }

                    break;

                default:
                    // Skip permissions with unknown scopes. In theory, this case should never
                    // be selected unless there are data integrity issues.
                    // @todo Add notice logs
                    continue;
            }

            if (in_array($attribute, $permission->getAttributes(), true)) {
                return true;
            }
        }

        return false;
    }
}


<?php

namespace Ds\Component\Acl\EventListener\Entity\Permission;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Ds\Component\Acl\Collection\PermissionCollection;
use Ds\Component\Acl\Entity\Permission;
use UnexpectedValueException;

/**
 * Class ValueListener
 *
 * @package Ds\Component\Acl
 */
final class ValueListener
{
    /**
     * @var \Ds\Component\Acl\Collection\PermissionCollection
     */
    private $permissionCollection;

    /**
     * Constructor
     *
     * @param \Ds\Component\Acl\Collection\PermissionCollection $permissionCollection
     */
    public function __construct(PermissionCollection $permissionCollection)
    {
        $this->permissionCollection = $permissionCollection;
    }

    /**
     * Hydrate the permission entity with permission configurations
     *
     * @param \Ds\Component\Acl\Entity\Permission $permission
     * @param \Doctrine\ORM\Event\LifecycleEventArgs $event
     * @throws \UnexpectedValueException
     */
    public function postLoad(Permission $permission, LifecycleEventArgs $event)
    {
        $item = $this->permissionCollection->get($permission->getKey());

        if (!$item) {
            throw new UnexpectedValueException('Permission "'.$permission->getKey().'" does not exist.');
        }

        $permission
            ->setType($item->getType())
            ->setValue($item->getValue());
    }
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

/**
 * Trait Cascade
 *
 * @package Ds\Component\Camunda
 */
trait Cascade
{
    /**
     * @var boolean
     */
    private $cascade; # region accessors

    /**
     * Set cascade
     *
     * @param boolean $cascade
     * @return object
     */
    public function setCascade(?bool $cascade)
    {
        $this->cascade = $cascade;
        $this->_cascade = null !== $cascade;

        return $this;
    }

    /**
     * Get cascade
     *
     * @return boolean
     */
    public function getCascade(): ?bool
    {
        return $this->cascade;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_cascade;
}


<?php

namespace CommerceGuys\Zone\Matcher;

use CommerceGuys\Addressing\AddressInterface;
use CommerceGuys\Zone\Repository\ZoneRepositoryInterface;

class ZoneMatcher implements ZoneMatcherInterface
{
    /**
     * Zone repository.
     *
     * @var ZoneRepositoryInterface
     */
    protected $repository;

    /**
     * Creates a ZoneMatcher instance.
     *
     * @param ZoneRepositoryInterface $repository
     */
    public function __construct(ZoneRepositoryInterface $repository)
    {
        $this->repository = $repository;
    }

    /**
     * {@inheritdoc}
     */
    public function match(AddressInterface $address, $scope = null)
    {
        $zones = $this->matchAll($address, $scope);

        return count($zones) ? $zones[0] : null;
    }

    /**
     * {@inheritdoc}
     */
    public function matchAll(AddressInterface $address, $scope = null)
    {
        // Find all matching zones.
        $results = [];
        foreach ($this->repository->getAll($scope) as $zone) {
            if ($zone->match($address)) {
                $results[] = [
                    'priority' => (int) $zone->getPriority(),
                    'zone' => $zone,
                ];
            }
        }
        // Sort the matched zones by priority.
        usort($results, function ($a, $b) {
            if ($a['priority'] == $b['priority']) {
                return 0;
            }

            return ($a['priority'] > $b['priority']) ? -1 : 1;
        });
        // Create the final zone array from the results.
        $zones = [];
        foreach ($results as $result) {
            $zones[] = $result['zone'];
        }

        return $zones;
    }
}


<?php

namespace Ds\Component\Parameter\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

/**
 * Class Configuration
 *
 * @package Ds\Component\Parameter
 */
final class Configuration implements ConfigurationInterface
{
    /**
     * {@inheritdoc}
     */
    public function getConfigTreeBuilder()
    {
        $builder = new TreeBuilder;
        $node = $builder->root('ds_parameter');
        $node
            ->children()
                ->arrayNode('parameters')
                    ->prototype('array')
                        ->children()
                            ->scalarNode('title')
                            ->end()
                            ->scalarNode('key')
                            ->end()
                            ->booleanNode('encrypt')
                                ->defaultFalse()
                            ->end()
                        ->end()
                    ->end()
                ->end()
            ->end();

        return $builder;
    }
}


<?php

namespace Ds\Component\Camunda\Model\Attribute;

use stdClass;

/**
 * Trait ValueInfo
 *
 * @package Ds\Component\Camunda
 */
trait ValueInfo
{
    /**
     * @var \stdClass
     */
    private $valueInfo; # region accessors

    /**
     * Set valueInfo
     *
     * @param \stdClass $valueInfo
     * @return object
     */
    public function setValueInfo(?stdClass $valueInfo)
    {
        if (null === $valueInfo) {
            $valueInfo = new stdClass;
        }

        $this->valueInfo = $valueInfo;

        return $this;
    }

    /**
     * Get valueInfo
     *
     * @return \stdClass
     */
    public function getValueInfo(): ?stdClass
    {
        return $this->valueInfo;
    }

    # endregion
}


<?php

namespace Ds\Component\Model\Attribute\Accessor;

use DateTime;

/**
 * Trait Enabled
 *
 * @package Ds\Component\Model
 */
trait Enabled
{
    /**
     * Set enabled
     *
     * @param boolean $enabled
     * @return object
     */
    public function setEnabled(?bool $enabled)
    {
        $this->enabled = $enabled;

        if (property_exists($this, 'enabledAt')) {
            $this->enabledAt = $enabled ? new DateTime : null;
        }

        return $this;
    }

    /**
     * Get enabled
     *
     * @return boolean
     */
    public function getEnabled(): ?bool
    {
        return $this->enabled;
    }

    /**
     * Check if enabled or not
     *
     * @return boolean
     */
    public function isEnabled(): bool
    {
        return (bool) $this->enabled;
    }
}


<?php

namespace Ds\Component\Formio\Service;

use Ds\Component\Formio\Exception\RequestException;
use Ds\Component\Formio\Exception\ResponseException;
use Ds\Component\Formio\Exception\ValidationException;
use Ds\Component\Formio\Model\Model;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use stdClass;
use DateTime;
use LogicException;
use InvalidArgumentException;

/**
 * Class AbstractService
 *
 * @package Ds\Component\Formio
 */
trait Base
{
    /**
     * Cast object to model
     *
     * @param \stdClass $object
     * @return \Ds\Component\Formio\Model\Model
     * @throws \LogicException
     */
    public static function toModel(stdClass $object)
    {
        if (null === static::MODEL) {
            throw new LogicException('Model class is not defined.');
        }

        $class = static::MODEL;
        $model = new $class;

        foreach (static::$map as $local => $remote) {
            if (is_int($local)) {
                $local = $remote;
            }

            if (property_exists($object, $remote)) {
                switch ($local) {
                    case 'created':
                    case 'updated':
                        if (null !== $object->$remote) {
                            $model->{'set' . ucfirst($local)}(new DateTime($object->$remote));
                        }

                        break;

                    default:
                        $model->{'set'.ucfirst($local)}($object->$remote);
                }
            }
        }

        return $model;
    }

    /**
     * Cast model to object
     *
     * @param \Ds\Component\Formio\Model\Model $model
     * @return stdClass
     * @throws \LogicException
     */
    public static function toObject(Model $model)
    {
        if (null === static::MODEL) {
            throw new LogicException('Model class is not defined.');
        }

        $object = new stdClass;

        foreach (static::$map as $local => $remote) {
            if (is_int($local)) {
                $local = $remote;
            }

            switch ($local) {
                case 'created':
                case 'updated':
                    $object->$remote = null;
                    $value = $model->{'get'.ucfirst($local)}();

                    if (null !== $value) {
                        $object->$remote = $value->format('Y-m-dTH:i:s');
                    }

                    break;

                default:
                    $object->$remote = $model->{'get'.ucfirst($local)}();
            }
        }

        return $object;
    }

    /**
     * @var \GuzzleHttp\ClientInterface
     */
    private $client;

    /**
     * @var string
     */
    private $host; # region accessors

    /**
     * {@inheritdoc}
     */
    public function setHost(string $host)
    {
        $this->host = $host;

        return $this;
    }

    # endregion

    /**
     * @var array
     */
    private $headers; # region accessors

    /**
     * {@inheritdoc}
     */
    public function setHeaders(array $headers)
    {
        $this->headers = $headers;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function setHeader(string $name, string $value)
    {
        $this->headers[$name] = $value;

        return $this;
    }

    # endregion

    /**
     * Constructor
     *
     * @param string $host
     * @param array $headers
     */
    public function __construct(?string $host = null, array $headers = [])
    {
        $this->client = new Client;
        $this->host = $host;
        $this->headers = $headers;
    }

    /**
     * Execute api request
     *
     * @param string $method
     * @param string $resource
     * @param array $options
     * @return mixed
     * @throws \Ds\Component\Formio\Exception\RequestException
     * @throws \Ds\Component\Formio\Exception\ResponseException
     * @throws \Ds\Component\Formio\Exception\ValidationException
     */
    protected function execute(string $method, string $resource, array $options = [])
    {
        $uri = $this->host.$resource;

        if ($this->headers) {
            if (!array_key_exists('headers', $options)) {
                $options['headers'] = [];
            }

            foreach ($this->headers as $key => $value) {
                if (!array_key_exists($key, $options['headers'])) {
                    $options['headers'][$key] = $value;
                }
            }
        }

        // @todo Remove this once we align formio and apip jwt tokens
        unset($options['headers']['Authorization']);

        try {
            $response = $this->client->request($method, $uri, $options);
        } catch (ClientException $exception) {
            $response = $exception->getResponse();

            switch ($response->getStatusCode()) {
                case 400:
                    $validation = new ValidationException('Request is not valid.', 0, $exception);
                    $data = (string) $response->getBody();

                    if ('' !== $data && false !== strpos($data, '{')) {
                        $data = \GuzzleHttp\json_decode($data);

                        if (property_exists($data, 'errors')) {
                            $validation->setErrors((array)$data->errors);
                        } else if (property_exists($data, 'details')) {
                            $validation->setErrors((array)$data->details);
                        }
                    }

                    throw $validation;
                    break;

                default:
                    throw new RequestException('Request failed.', 0, $exception);
            }
        }

        $data = null;

        // @todo Instead of this switch case, refactor execute() method to return header and body, instead of just body.
        switch ($resource) {
            case AuthenticationService::RESOURCE_LOGIN:
                $data = $response->getHeader('x-jwt-token')[0];
                break;

            default:
                $data = (string) $response->getBody();

                if ('' !== $data && false !== strpos($data, '{')) {
                    try {
                        $data = \GuzzleHttp\json_decode($response->getBody());
                    } catch (InvalidArgumentException $exception) {
                        throw new ResponseException('Service response is not valid.', 0, $exception);
                    }
                }
        }

        return $data;
    }
}


<?php

namespace Ds\Component\Filter\EventListener;

use Exception;
use function GuzzleHttp\json_decode;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

/**
 * Class ContentListener
 *
 * @package Ds\Component\Filter
 */
final class ContentListener
{
    /**
     * Transfer get request content to api filters in order to allow large api filters
     *
     * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
     */
    public function kernelRequest(GetResponseEvent $event)
    {
        $request = $event->getRequest();
        $content = $request->getContent();

        if ('' === $content) {
            return;
        }

        try {
            $filters = json_decode($content, true);
        } catch (Exception $exception) {
            throw new BadRequestHttpException('Request body should be an object.', $exception);
        }

        if (!is_array($filters)) {
            throw new BadRequestHttpException('Request body should be an object.');
        }

        $current = $request->attributes->get('_api_filters', []);
        $query = $request->query->all();
        $filters = array_merge($current, $query, $filters);
        $request->attributes->set('_api_filters', $filters);
    }
}


<?php

namespace Ds\Component\Model\Attribute\Accessor;

use InvalidArgumentException;

/**
 * Trait UserUuid
 *
 * @package Ds\Component\Model
 */
trait UserUuid
{
    /**
     * Set user uuid
     *
     * @param string $userUuid
     * @return object
     * @throws \InvalidArgumentException
     */
    public function setUserUuid(?string $userUuid)
    {
        if (null !== $userUuid) {
            if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', $userUuid)) {
                throw new InvalidArgumentException('Uuid is not valid.');
            }
        }

        $this->userUuid = $userUuid;

        return $this;
    }

    /**
     * Get user uuid
     *
     * @return string
     */
    public function getUserUuid(): ?string
    {
        return $this->userUuid;
    }
}


<?php

namespace Ds\Component\Model\Attribute\Accessor;

use DomainException;

/**
 * Trait Identity
 *
 * @package Ds\Component\Model
 */
trait Identity
{
    /**
     * Set identity
     *
     * @param string $identity
     * @return object
     * @throws \DomainException
     */
    public function setIdentity(?string $identity)
    {
        if (null !== $identity) {
            if (!preg_match('/^[a-z]+$/i', $identity)) {
                throw new DomainException('Identity is not valid.');
            }
        }

        $this->identity = $identity;

        return $this;
    }

    /**
     * Get identity
     *
     * @return string
     */
    public function getIdentity(): ?string
    {
        return $this->identity;
    }
}


<?php

namespace Ds\Component\Tenant\DependencyInjection\Compiler;

use Ds\Component\Tenant\Collection\LoaderCollection;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
 * Class LoaderPass
 *
 * @package Ds\Component\Tenant
 */
final class LoaderPass implements CompilerPassInterface
{
    /**
     * Add tagged tenant loader services to the loader collection
     *
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $definition = $container->findDefinition(LoaderCollection::class);
        $services = $container->findTaggedServiceIds('ds_tenant.loader');
        $items = [];

        foreach ($services as $id => $tags) {
            foreach ($tags as $tag) {
                $items[] = [
                    'id' => $id,
                    'priority' => array_key_exists('priority', $tag) ? $tag['priority'] : 0,
                    'alias' => array_key_exists('alias', $tag) ? $tag['alias'] : null
                ];
            }
        }

        usort($items, function($a, $b) {
            return
                $a['priority'] === $b['priority'] ? 0
                : $a['priority'] < $b['priority'] ? -1
                : 1;
        });

        foreach ($items as $item) {
            if (null !== $item['alias']) {
                $definition->addMethodCall('set', [$item['alias'], new Reference($item['id'])]);
            } else {
                $definition->addMethodCall('add', [new Reference($item['id'])]);
            }
        }
    }
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

/**
 * Trait FirstResult
 *
 * @package Ds\Component\Camunda
 */
trait FirstResult
{
    /**
     * @var integer
     */
    private $firstResult; # region accessors

    /**
     * Set first result
     *
     * @param integer $firstResult
     * @return object
     */
    public function setFirstResult(?int $firstResult)
    {
        $this->firstResult = $firstResult;
        $this->_firstResult = null !== $firstResult;

        return $this;
    }

    /**
     * Get first result
     *
     * @return integer
     */
    public function getFirstResult(): ?int
    {
        return $this->firstResult;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_firstResult;
}


<?php

namespace Ds\Component\Camunda\Service;

use Ds\Component\Api\Service\Service;
use Ds\Component\Camunda\Model\Variable;
use Ds\Component\Camunda\Query\VariableParameters as Parameters;
use stdClass;

/**
 * Class VariableService
 *
 * @package Ds\Component\Camunda
 */
abstract class VariableService implements Service
{
    use Base;

    /**
     * @const string
     */
    const MODEL = Variable::class;

    /**
     * @const string
     */
    const VARIABLE_LIST = null;

    /**
     * @var array
     */
    protected static $map = [
        'name',
        'value',
        'type',
        'valueInfo'
    ];

    /**
     * Get task list
     *
     * @parma string $task
     * @param \Ds\Component\Camunda\Query\VariableParameters $parameters
     * @return array
     */
    public function getList($task, Parameters $parameters = null)
    {
        $resource = str_replace('{id}', $task, static::VARIABLE_LIST);
        $options = [
            'headers' => [
                'Accept' => 'application/json'
            ],
            'query' => (array)  $parameters->toObject(true)
        ];
        $objects = $this->execute('GET', $resource, $options);
        $list = [];

        foreach ($objects as $name => $object) {
            $object->name = $name;
            $model = static::toModel($object);
            $list[$name] = $model;
        }

        return $list;
    }

    /**
     * {@inheritdoc}
     */
    public static function toModel(stdClass $object)
    {
        $model = Base::toModel($object);

        if (Variable::TYPE_JSON === $model->getType()) {
            $model->setValue(json_decode($model->getValue()));
        }

        return $model;
    }
}


<?php

namespace Ds\Component\Resolver\Collection;

use Doctrine\Common\Collections\ArrayCollection;
use Ds\Component\Resolver\Exception\UnmatchedException;

/**
 * Class ResolverCollection
 *
 * @package Ds\Component\Resolver
 */
final class ResolverCollection extends ArrayCollection
{
    /**
     * Get value
     *
     * @param string $variable
     * @return mixed
     * @throws \Ds\Component\Resolver\Exception\UnresolvedException
     */
    public function resolve(string $variable)
    {
        foreach ($this as $resolver) {
            if ($resolver->isMatch($variable)) {
                return $resolver->resolve($variable);
            }
        }

        throw new UnmatchedException('Variable pattern "'.$variable.'" is not matching any resolvers.');
    }
}


<?php

namespace Ds\Component\Model\Attribute\Accessor;

use DomainException;
use ReflectionClass;

/**
 * Trait Scope
 *
 * @package Ds\Component\Model
 */
trait Scope
{
    /**
     * Set scope
     *
     * @param string $scope
     * @return object
     * @throws \DomainException
     */
    public function setScope(?string $scope)
    {
        if (null !== $scope && $this->getScopes() && !in_array($scope, $this->getScopes(), true)) {
            throw new DomainException('Scope does not exist.');
        }

        $this->scope = $scope;

        return $this;
    }

    /**
     * Get scope
     *
     * @return string
     */
    public function getScope(): ?string
    {
        return $this->scope;
    }

    /**
     * Get scopes
     *
     * @return array
     */
    public function getScopes(): array
    {
        static $scopes;

        if (null === $scopes) {
            $scopes = [];
            $class = new ReflectionClass($this);

            foreach ($class->getConstants() as $constant => $value) {
                if ('SCOPE_' === substr($constant, 0, 6)) {
                    $scopes[] = $value;
                }
            }
        }

        return $scopes;
    }
}


<?php

namespace Ds\Component\Camunda\Service;

use Ds\Component\Api\Service\Service;
use Ds\Component\Camunda\Model\Deployment;
use Ds\Component\Camunda\Query\DeploymentParameters as Parameters;
use SimpleXMLElement;

/**
 * Class DeploymentService
 *
 * @package Ds\Component\Camunda
 */
final class DeploymentService implements Service
{
    use Base;

    /**
     * @const string
     */
    const MODEL = Deployment::class;

    /**
     * @const string
     */
    const RESOURCE_LIST = '/rest/deployment';
    const RESOURCE_COUNT = '/rest/deployment/count';
    const RESOURCE_OBJECT = '/rest/deployment/{id}';
    const RESOURCE_CREATE = '/rest/deployment/create';

    /**
     * @var array
     */
    private static $map = [
        'id',
        'name',
        'source',
        'deploymentTime',
        'tenantId'
    ];

    /**
     * Get list of deployments
     *
     * @param \Ds\Component\Camunda\Query\DeploymentParameters $parameters
     * @return array
     */
    public function getList(Parameters $parameters = null)
    {
        $options = [];

        if ($parameters) {
            $options['query'] = (array) $parameters->toObject(true);
        }

        $objects = $this->execute('GET', static::RESOURCE_LIST, $options);
        $list = [];

        foreach ($objects as $object) {
            $model = static::toModel($object);
            $list[] = $model;
        }

        return $list;
    }

    /**
     * Get count of deployments
     *
     * @param \Ds\Component\Camunda\Query\DeploymentParameters $parameters
     * @return integer
     */
    public function getCount(Parameters $parameters = null)
    {
        $result = $this->execute('GET', static::RESOURCE_COUNT);

        return $result->count;
    }

    /**
     * Get deployment
     *
     * @param string $id
     * @param \Ds\Component\Camunda\Query\DeploymentParameters $parameters
     * @return \Ds\Component\Camunda\Model\Deployment
     */
    public function get($id, Parameters $parameters = null)
    {
        $resource = str_replace('{id}', $id, static::RESOURCE_OBJECT);
        $object = $this->execute('GET', $resource);
        $model = static::toModel($object);

        return $model;
    }

    /**
     * Create deployment
     *
     * @param \Ds\Component\Camunda\Model\Deployment $deployment
     * @return \Ds\Component\Camunda\Model\Deployment
     */
    public function create(Deployment $deployment)
    {
        $options = [
            'multipart' => [
                [
                    'Content-Disposition' => 'form-data',
                    'name' => 'deployment-name',
                    'contents' => $deployment->getName()
                ],
                [
                    'Content-Disposition' => 'form-data',
                    'name' => 'deployment-source',
                    'contents' => $deployment->getSource()
                ],
                [
                    'Content-Disposition' => 'form-data',
                    'name' => 'tenant-id',
                    'contents' => $deployment->getTenantId()
                ]
            ]
        ];

        foreach ($deployment->getFiles() as $file) {
            $options['multipart'][] = [
                'Content-Disposition' => 'form-data',
                'name' => basename($file),
                'filename' => basename($file),
                'contents' => fopen($file, 'r')
            ];
        }

        $object = $this->execute('POST', static::RESOURCE_CREATE, $options);
        $model = static::toModel($object);

        return $model;
    }

    /**
     * Delete deployment
     *
     * @param string $id
     * @param \Ds\Component\Camunda\Query\DeploymentParameters $parameters
     */
    public function delete($id, Parameters $parameters = null)
    {
        $resource = str_replace('{id}', $id, static::RESOURCE_OBJECT);
        $options = [];

        if ($parameters) {
            $options['query'] = (array) $parameters->toObject(true);
        }

        $this->execute('DELETE', $resource, $options);
    }
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

/**
 * Trait CandidateGroup
 *
 * @package Ds\Component\Camunda
 */
trait CandidateGroup
{
    /**
     * @var string
     */
    private $candidateGroup; # region accessors

    /**
     * Set candidate group
     *
     * @param string $candidateGroup
     * @return object
     */
    public function setCandidateGroup(?string$candidateGroup)
    {
        $this->candidateGroup = $candidateGroup;
        $this->_candidateGroup = null !== $candidateGroup;

        return $this;
    }

    /**
     * Get candidateGroup
     *
     * @return string
     */
    public function getCandidateGroup(): ?string
    {
        return $this->candidateGroup;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_candidateGroup;
}


<?php

namespace Ds\Component\Api\Query\Attribute;

/**
 * Trait Assignee
 *
 * @package Ds\Component\Api
 */
trait Assignee
{
    /**
     * @var string
     */
    private $assignee; # region accessors

    /**
     * Set assignee
     *
     * @param string $assignee
     * @return object
     */
    public function setAssignee(?string $assignee)
    {
        $this->assignee = $assignee;
        $this->_assignee = true;

        return $this;
    }

    /**
     * Get assignee
     *
     * @return string
     */
    public function getAssignee(): ?string
    {
        return $this->assignee;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_assignee;
}


<?php

namespace Ds\Component\Model\Attribute\Accessor;

use InvalidArgumentException;

/**
 * Trait Tenant
 *
 * @package Ds\Component\Model
 */
trait Tenant
{
    /**
     * Set tenant
     *
     * @param string $tenant
     * @return object
     * @throws \InvalidArgumentException
     */
    public function setTenant(?string $tenant)
    {
        if (null !== $tenant) {
            if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i', $tenant)) {
                throw new InvalidArgumentException('Assignee uuid is not valid.');
            }
        }

        $this->tenant = $tenant;

        return $this;
    }

    /**
     * Get tenant
     *
     * @return string
     */
    public function getTenant(): ?string
    {
        return $this->tenant;
    }
}


<?php

namespace Ds\Component\Tenant\EventListener\Entity;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Ds\Component\Container\EventListener\ContainerListener;
use Ds\Component\Tenant\Model\Type\Tenantable;
use Ds\Component\Tenant\Service\TenantService;

/**
 * Class TenantableListener
 *
 * @package Ds\Component\Tenant
 */
final class TenantableListener extends ContainerListener
{
    /**
     * Assign the tenant uuid before persisting the entity, if none provided
     *
     * @param \Doctrine\ORM\Event\LifecycleEventArgs $args
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if (!$entity instanceof Tenantable) {
            return;
        }

        if (null !== $entity->getTenant()) {
            return;
        }

        $tenant = $this->container->get(TenantService::class)->getContext();
        $entity->setTenant($tenant);
    }
}


<?php

namespace Ds\Component\Metadata\Fixture;

use Doctrine\Common\Persistence\ObjectManager;
use Ds\Component\Database\Fixture\Yaml;
use Ds\Component\Metadata\Entity\Metadata as MetadataEntity;

/**
 * Trait Metadata
 *
 * @package Ds\Component\Metadata
 */
trait Metadata
{
    use Yaml;

    /**
     * @var string
     */
    private $path;

    /**
     * {@inheritdoc}
     */
    public function load(ObjectManager $manager)
    {
        $objects = $this->parse($this->path);

        foreach ($objects as $object) {
            $metadata = new MetadataEntity;
            $metadata
                ->setUuid($object->uuid)
                ->setOwner($object->owner)
                ->setOwnerUuid($object->owner_uuid)
                ->setTitle((array) $object->title)
                ->setSlug($object->slug)
                ->setType($object->type)
                ->setData((array) $object->data)
                ->setTenant($object->tenant);
            $manager->persist($metadata);
        }

        $manager->flush();
    }
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

/**
 * Trait Assignee
 *
 * @package Ds\Component\Camunda
 */
trait Assignee
{
    /**
     * @var string
     */
    private $assignee; # region accessors

    /**
     * Set assignee
     *
     * @param string $assignee
     * @return object
     */
    public function setAssignee(?string $assignee)
    {
        $this->assignee = $assignee;
        $this->_assignee = null !== $assignee;

        return $this;
    }

    /**
     * Get assignee
     *
     * @return string
     */
    public function getAssignee(): ?string
    {
        return $this->assignee;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_assignee;
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

/**
 * Trait TenantIdIn
 *
 * @package Ds\Component\Camunda
 */
trait TenantIdIn
{
    /**
     * @var array
     */
    private $tenantIdIn; # region accessors

    /**
     * Set tenant id in
     *
     * @param array $tenantIdIn
     * @return object
     */
    public function setTenantIdIn(array $tenantIdIn)
    {
        $this->tenantIdIn = $tenantIdIn;
        $this->_tenantIdIn = null !== $tenantIdIn;

        return $this;
    }

    /**
     * Get tenantIdIn
     *
     * @return array
     */
    public function getTenantIdIn(): array
    {
        return $this->tenantIdIn;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_tenantIdIn;
}


<?php

namespace Ds\Component\Encryption\EventListener\Entity\Encryptable;

use Doctrine\ORM\Event\PreUpdateEventArgs;
use Ds\Component\Encryption\Model\Type\Encryptable;

/**
 * Class PreUpdateListener
 *
 * @package Ds\Component\Encryption
 */
final class PreUpdateListener extends AbstractListener
{
    /**
     * Encrypt encryptable entity properties before saving in storage.
     *
     * @param \Doctrine\ORM\Event\PreUpdateEventArgs $args
     */
    public function preUpdate(PreUpdateEventArgs $args)
    {
        $entity = $args->getEntity();

        if (!$entity instanceof Encryptable) {
            return;
        }

        $this->encryptionService->encrypt($entity);
    }
}


<?php

namespace Ds\Component\Acl\Migration;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
use Ramsey\Uuid\Uuid;

/**
 * Class Version0_15_0
 *
 * @package Ds\Component\Acl
 */
final class Version0_15_0 extends AbstractMigration
{
    /**
     * Up migration
     *
     * @param \Doctrine\DBAL\Schema\Schema $schema
     * @param array $accesses
     */
    public function up(Schema $schema, array $accesses = [])
    {
        $sequences['ds_access_id_seq'] = 1 + count($accesses);
        $sequences['ds_access_permission_id_seq'] = 1;

        foreach ($accesses as $access) {
            $sequences['ds_access_permission_id_seq'] += count($access->permissions);
        }

        switch ($this->platform->getName()) {
            case 'postgresql':
                $this->addSql('CREATE SEQUENCE ds_access_id_seq INCREMENT BY 1 MINVALUE 1 START '.$sequences['ds_access_id_seq']);
                $this->addSql('CREATE SEQUENCE ds_access_permission_id_seq INCREMENT BY 1 MINVALUE 1 START '.$sequences['ds_access_permission_id_seq']);
                $this->addSql('CREATE TABLE ds_access (id INT NOT NULL, uuid UUID NOT NULL, "owner" VARCHAR(255) DEFAULT NULL, owner_uuid UUID DEFAULT NULL, assignee VARCHAR(255) DEFAULT NULL, assignee_uuid UUID DEFAULT NULL, version INT DEFAULT 1 NOT NULL, tenant UUID NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(id))');
                $this->addSql('CREATE UNIQUE INDEX UNIQ_A76F41DCD17F50A6 ON ds_access (uuid)');
                $this->addSql('CREATE TABLE ds_access_permission (id INT NOT NULL, access_id INT DEFAULT NULL, scope VARCHAR(255) DEFAULT NULL, entity VARCHAR(255) DEFAULT NULL, entity_uuid UUID DEFAULT NULL, "key" VARCHAR(255) NOT NULL, attributes JSON NOT NULL, tenant UUID NOT NULL, PRIMARY KEY(id))');
                $this->addSql('CREATE INDEX IDX_D46DD4D04FEA67CF ON ds_access_permission (access_id)');
                $this->addSql('COMMENT ON COLUMN ds_access_permission.attributes IS \'(DC2Type:json_array)\'');
                $this->addSql('ALTER TABLE ds_access_permission ADD CONSTRAINT FK_D46DD4D04FEA67CF FOREIGN KEY (access_id) REFERENCES ds_access (id) NOT DEFERRABLE INITIALLY IMMEDIATE');

                $i = 0;
                $j = 0;

                foreach ($accesses as $access) {
                    if (null === $access->uuid) {
                        $access->uuid = Uuid::uuid4()->toString();
                    }

                    $this->addSql(sprintf(
                        'INSERT INTO ds_access (id, uuid, owner, owner_uuid, assignee, assignee_uuid, version, tenant, created_at, updated_at) VALUES (%d, %s, %s, %s, %s, %s, %d, %s, %s, %s);',
                        ++$i,
                        $this->connection->quote($access->uuid),
                        $this->connection->quote($access->owner),
                        $this->connection->quote($access->owner_uuid),
                        $this->connection->quote($access->assignee),
                        $this->connection->quote($access->assignee_uuid),
                        $access->version,
                        $this->connection->quote($access->tenant),
                        'now()',
                        'now()'
                    ));

                    foreach ($access->permissions as $permission) {
                        $this->addSql(sprintf(
                            'INSERT INTO ds_access_permission (id, access_id, scope, entity, entity_uuid, key, attributes, tenant) VALUES (%d, %d, %s, %s, %s, %s, %s, %s);',
                            ++$j,
                            $i,
                            $this->connection->quote($permission->scope),
                            null === $permission->entity ? 'NULL' : $this->connection->quote($permission->entity),
                            null === $permission->entity_uuid ? 'NULL' : $this->connection->quote($permission->entity_uuid),
                            $this->connection->quote($permission->key),
                            $this->connection->quote(json_encode($permission->attributes)),
                            $this->connection->quote($access->tenant)
                        ));
                    }
                }

                break;

            default:
                $this->abortIf(true,'Migration cannot be executed on "'.$this->platform->getName().'".');
                break;
        }
    }

    /**
     * Down migration
     *
     * @param \Doctrine\DBAL\Schema\Schema $schema
     */
    public function down(Schema $schema)
    {
        switch ($this->platform->getName()) {
            case 'postgresql':
                $this->addSql('ALTER TABLE ds_access_permission DROP CONSTRAINT FK_D46DD4D04FEA67CF');
                $this->addSql('DROP SEQUENCE ds_access_id_seq CASCADE');
                $this->addSql('DROP SEQUENCE ds_access_permission_id_seq CASCADE');
                $this->addSql('DROP TABLE ds_access');
                $this->addSql('DROP TABLE ds_access_permission');
                break;

            default:
                $this->abortIf(true,'Migration cannot be executed on "'.$this->platform->getName().'".');
                break;
        }
    }
}


<?php

namespace Ds\Component\Query\Controller;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use UnexpectedValueException;

use Symfony\Component\Routing\Annotation\Route;

/**
 * Class QueryController
 */
final class QueryController
{
    /**
     * @var \GuzzleHttp\ClientInterface
     */
    private $client;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->client = new Client;
    }

    /**
     * Query endpoint
     *
     * @Route(path="/{entity}/query", methods={"POST"})
     * @param \Symfony\Component\HttpFoundation\Request $request
     * @param string $entity
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function post(Request $request, $entity)
    {
        try {
            $get = $this->client->get($request->getSchemeAndHttpHost().'/'.$entity, [
                'headers' => [
                    'accept' => $request->headers->get('accept'),
                    'content-type' => $request->headers->get('content-type'),
                    'authorization' => $request->headers->get('authorization')
                ],
                'query' => $request->query->all(),
                'body' => $request->getContent()
            ]);
        } catch (ClientException $exception) {
            throw new UnexpectedValueException('Query did not execute successfully.');
        }

        $response = new Response((string) $get->getBody());
        $response->headers->set('content-type', $request->headers->get('content-type'));

        return $response;
    }
}


<?php

namespace Ds\Component\Acl\Controller\Reference;

use Ds\Component\Acl\Collection\PermissionCollection;
use Ds\Component\Acl\Model\Permission;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\Routing\Annotation\Route;

/**
 * Class PermissionsController
 *
 * @package Ds\Component\Acl
 */
final class PermissionsController
{
    /**
     * @var \Ds\Component\Acl\Collection\PermissionCollection
     */
    private $permissionCollection;

    /**
     * Constructor
     *
     * @param \Ds\Component\Acl\Collection\PermissionCollection $permissionCollection
     */
    public function __construct(PermissionCollection $permissionCollection)
    {
        $this->permissionCollection = $permissionCollection;
    }

    /**
     * Action
     *
     * @Route(path="/reference/permissions", methods={"GET"})
     * @Security("is_granted('BROWSE', 'reference_permissions')")
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     */
    public function cget()
    {
        $permissions = [];

        foreach ($this->permissionCollection as $key => $element) {
            $permission = $element->toObject();

            switch ($permission->type) {
                case Permission::PROPERTY:
                    $parent = $this->permissionCollection->getParent($element);

                    if ($parent) {
                        $permission->parent = $parent->getKey();
                    }

                    break;
            }

            unset($permission->value);
            $permissions[] = $permission;
        }

        return new JsonResponse($permissions, Response::HTTP_OK, [
            'Content-Type' => 'application/json; charset=utf-8'
        ]);
    }
}


<?php

namespace Ds\Component\Security\Model;

use Symfony\Component\Security\Core\User\UserInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Security\User\JWTUserInterface;

/**
 * Class User
 *
 * @package Ds\Component\Security
 */
final class User implements UserInterface, JWTUserInterface
{
    /**
     * {@inheritdoc}
     */
    public static function createFromPayload($username, array $payload)
    {
        // @todo Populate security user model using callbacks from JWT token event listeners, instead of hard-coded here
        $uuid = $payload['uuid'] ?? null;
        $roles = $payload['roles'] ?? [];
        $identity = new Identity;
        $identity->setRoles($payload['identity']->roles ?? []);
        $identity->setType($payload['identity']->type ?? null);
        $identity->setUuid($payload['identity']->uuid ?? null);
        $tenant = $payload['tenant'] ?? null;

        return new static($username, $uuid, $roles, $identity, $tenant);
    }

    /**
     * @var string
     */
    private $username;

    /**
     * @var string
     */
    private $uuid;

    /**
     * @var array
     */
    private $roles;

    /**
     * @var \Ds\Component\Security\Model\Identity
     */
    private $identity;

    /**
     * @var string
     */
    private $tenant;

    /**
     * Constructor
     *
     * @param string $username
     * @param string $uuid
     * @param array $roles
     * @param \Ds\Component\Security\Model\Identity $identity
     * @param string $tenant
     */
    public function __construct(string $username, string $uuid = null, array $roles = [], Identity $identity = null, string $tenant = null)
    {
        $this->username = $username;
        $this->uuid = $uuid;
        $this->roles = $roles;
        $this->identity = $identity;
        $this->tenant = $tenant;
    }

    /**
     * {@inheritdoc}
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * {@inheritdoc}
     */
    public function getUuid()
    {
        return $this->uuid;
    }

    /**
     * {@inheritdoc}
     */
    public function getRoles()
    {
        return $this->roles;
    }

    /**
     * {@inheritdoc}
     */
    public function getIdentity()
    {
        return $this->identity;
    }

    /**
     * {@inheritdoc}
     */
    public function getTenant()
    {
        return $this->tenant;
    }

    /**
     * {@inheritdoc}
     */
    public function getPassword()
    {
    }

    /**
     * {@inheritdoc}
     */
    public function getSalt()
    {
    }

    /**
     * {@inheritdoc}
     */
    public function eraseCredentials()
    {
    }
}


<?php

namespace Ds\Component\Api\Service;

use Ds\Component\Api\Model\Organization;
use Ds\Component\Api\Query\OrganizationParameters as Parameters;

/**
 * Class OrganizationService
 *
 * @package Ds\Component\Api
 */
final class OrganizationService implements Service
{
    use Base;

    /**
     * @const string
     */
    const MODEL = Organization::class;

    /**
     * @const string
     */
    const RESOURCE_LIST = '/organizations';
    const RESOURCE_OBJECT = '/organizations/{id}';

    /**
     * @var array
     */
    private static $map = [
        'id',
        'uuid',
        'createdAt',
        'updatedAt',
        'owner',
        'ownerUuid',
        'roles',
        'version',
        'tenant'
    ];

    /**
     * Get organization list
     *
     * @param \Ds\Component\Api\Query\OrganizationParameters $parameters
     * @return array
     */
    public function getList(Parameters $parameters = null): array
    {
        $objects = $this->execute('GET', static::RESOURCE_LIST);
        $list = [];

        foreach ($objects as $object) {
            $model = static::toModel($object);
            $list[] = $model;
        }

        return $list;
    }

    /**
     * Get organization
     *
     * @param string $id
     * @param \Ds\Component\Api\Query\OrganizationParameters $parameters
     * @return \Ds\Component\Api\Model\Organization
     */
    public function get($id, Parameters $parameters = null): Organization
    {
        $resource = str_replace('{id}', $id, static::RESOURCE_OBJECT);
        $object = $this->execute('GET', $resource);
        /** @var \Ds\Component\Api\Model\Organization $model */
        $model = static::toModel($object);

        return $model;
    }

    /**
     * Create organization
     *
     * @param \Ds\Component\Api\Model\Organization $organization
     * @param \Ds\Component\Api\Query\OrganizationParameters $parameters
     * @return \Ds\Component\Api\Model\Organization
     */
    public function create(Organization $organization, Parameters $parameters = null): Organization
    {
        $options = [];
        $options['json'] = (array) static::toObject($organization);

        if ($parameters) {
            $options['query'] = (array) $parameters->toObject(true);
        }

        $object = $this->execute('POST', static::RESOURCE_LIST, $options);
        /** @var \Ds\Component\Api\Model\Organization $organization */
        $organization = static::toModel($object);

        return $organization;
    }
}


<?php

namespace Ds\Component\Config\Migration;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
use Ds\Component\Container\Attribute;
use Ds\Component\Encryption\Service\CipherService;
use Ramsey\Uuid\Uuid;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;

/**
 * Class Version0_15_0
 *
 * @package Ds\Component\Config
 */
final class Version0_15_0 extends AbstractMigration implements ContainerAwareInterface
{
    use Attribute\Container;

    /**
     * Up migration
     *
     * @param \Doctrine\DBAL\Schema\Schema $schema
     * @param array $configs
     */
    public function up(Schema $schema, array $configs = [])
    {
        $cipherService = $this->container->get(CipherService::class);
        $encrypted = ['ds_api.user.password'];
        $sequences['ds_config_id_seq'] = 1 + count($configs);

        switch ($this->platform->getName()) {
            case 'postgresql':
                $this->addSql('CREATE SEQUENCE ds_config_id_seq INCREMENT BY 1 MINVALUE 1 START '.$sequences['ds_config_id_seq']);
                $this->addSql('CREATE TABLE ds_config (id INT NOT NULL, uuid UUID NOT NULL, "owner" VARCHAR(255) DEFAULT NULL, owner_uuid UUID DEFAULT NULL, "key" VARCHAR(255) NOT NULL, value TEXT DEFAULT NULL, version INT DEFAULT 1 NOT NULL, tenant UUID NOT NULL, created_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updated_at TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, PRIMARY KEY(id))');
                $this->addSql('CREATE UNIQUE INDEX UNIQ_758C45F4D17F50A6 ON ds_config (uuid)');
                $this->addSql('CREATE UNIQUE INDEX UNIQ_758C45F48A90ABA94E59C462 ON ds_config (key, tenant)');

                $i = 0;

                foreach ($configs as $config) {
                    if (null === $config->uuid) {
                        $config->uuid = Uuid::uuid4()->toString();
                    }

                    $config->value = serialize($config->value);

                    if (in_array($config->key, $encrypted)) {
                        $config->value = $cipherService->encrypt($config->value);
                    }

                    $this->addSql(sprintf(
                        'INSERT INTO ds_config (id, uuid, owner, owner_uuid, key, value, version, tenant, created_at, updated_at) VALUES (%d, %s, %s, %s, %s, %s, %d, %s, %s, %s);',
                        ++$i,
                        $this->connection->quote($config->uuid),
                        $this->connection->quote($config->owner),
                        $this->connection->quote($config->owner_uuid),
                        $this->connection->quote($config->key),
                        $this->connection->quote($config->value),
                        $config->version,
                        $this->connection->quote($config->tenant),
                        'now()',
                        'now()'
                    ));
                }

                break;

            default:
                $this->abortIf(true,'Migration cannot be executed on "'.$this->platform->getName().'".');
                break;
        }
    }

    /**
     * Down migration
     *
     * @param \Doctrine\DBAL\Schema\Schema $schema
     */
    public function down(Schema $schema)
    {
        switch ($this->platform->getName()) {
            case 'postgresql':
                $this->addSql('DROP SEQUENCE ds_config_id_seq CASCADE');
                $this->addSql('DROP TABLE ds_config');
                break;

            default:
                $this->abortIf(true,'Migration cannot be executed on "'.$this->platform->getName().'".');
                break;
        }
    }
}


<?php

namespace Ds\Component\Entity\EventListener;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Ds\Component\Entity\Service\IdService;
use Ds\Component\Model\Type\Uuidentifiable;

/**
 * Class UuidentifiableListener
 *
 * @package Ds\Component\Entity
 */
final class UuidentifiableListener
{
    /**
     * @var \Ds\Component\Entity\Service\IdService
     */
    private $idService;

    /**
     * Constructor
     *
     * @param \Ds\Component\Entity\Service\IdService $idService
     */
    public function __construct(IdService $idService)
    {
        $this->idService = $idService;
    }

    /**
     * Generate an uuid before persisting the entity, if none provided
     *
     * @param \Doctrine\ORM\Event\LifecycleEventArgs $args
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if (!$entity instanceof Uuidentifiable) {
            return;
        }

        $this->idService->generateUuid($entity);
    }
}


<?php

namespace Ds\Component\Identity\Resolver\Context;

use DomainException;
use Ds\Component\Api\Api\Api;
use Ds\Component\Security\Model\Identity;
use Ds\Component\Resolver\Exception\UnresolvedException;
use Ds\Component\Resolver\Resolver\Resolver;
use Exception;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

/**
 * Class IdentityResolver
 *
 * @package Ds\Component\Identity
 */
final class IdentityResolver implements Resolver
{
    /**
     * @const string
     */
    const PATTERN = '/^ds\[identity\]\.(.+)/';

    /**
     * @var \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface
     */
    private $tokenStorage;

    /**
     * @var \Ds\Component\Api\Api\Api
     */
    private $api;

    /**
     * Constructor
     *
     * @param \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface $tokenStorage
     * @param \Ds\Component\Api\Api\Api $api
     */
    public function __construct(TokenStorageInterface $tokenStorage, Api $api)
    {
        $this->tokenStorage = $tokenStorage;
        $this->api = $api;
    }

    /**
     * {@inheritdoc}
     */
    public function isMatch(string $variable, array &$matches = []): bool
    {
        $token = $this->tokenStorage->getToken();

        if (!$token) {
            return false;
        }

        if (!preg_match(static::PATTERN, $variable, $matches)) {
            return false;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function resolve(string $variable)
    {
        $matches = [];

        if (!$this->isMatch($variable, $matches)) {
            throw new UnresolvedException('Variable pattern "'.$variable.'" is not valid.');
        }

        $token = $this->tokenStorage->getToken();
        $user = $token->getUser();
        $identity = $user->getIdentity();

        switch ($identity->getType()) {
            case Identity::ANONYMOUS:
                $model = $this->api->get('identities.anonymous')->get($identity->getUuid());
                break;

            case Identity::INDIVIDUAL:
                $model = $this->api->get('identities.individual')->get($identity->getUuid());
                break;

            case Identity::ORGANIZATION:
                $model = $this->api->get('identities.organization')->get($identity->getUuid());
                break;

            case Identity::STAFF:
                $model = $this->api->get('identities.staff')->get($identity->getyUuid());
                break;

            case Identity::SYSTEM:
                $model = $this->api->get('identities.system')->get($identity->getUuid());
                break;

            default:
                throw new DomainException('User identity "'.$identity->getType().'" is not valid.');
        }

        if (!$model) {
            throw new UnresolvedException('Variable pattern "'.$variable.'" did not resolve to data.');
        }

        $property = $matches[1];
        $accessor = PropertyAccess::createPropertyAccessor();

        try {
            $value = $accessor->getValue($model, $property);
        } catch (Exception $exception) {
            throw new UnresolvedException('Variable pattern "'.$variable.'" did not resolve to data.', 0, $exception);
        }

        return $value;
    }
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

/**
 * Trait TenantId
 *
 * @package Ds\Component\Camunda
 */
trait TenantId
{
    /**
     * @var string
     */
    private $tenantId; # region accessors

    /**
     * Set tenant id
     *
     * @param string $tenantId
     * @return object
     */
    public function setTenantId(?string $tenantId)
    {
        $this->tenantId = $tenantId;
        $this->_tenantId = null !== $tenantId;

        return $this;
    }

    /**
     * Get tenantId
     *
     * @return string
     */
    public function getTenantId(): ?string
    {
        return $this->tenantId;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_tenantId;
}


<?php

namespace Ds\Component\Statistic\Collection;

use Doctrine\Common\Collections\ArrayCollection;
use Ds\Component\Statistic\Stat\Stat;
use InvalidArgumentException;

/**
 * Class StatCollection
 *
 * @package Ds\Component\Statistic
 */
final class StatCollection extends ArrayCollection
{
    /**
     * {@inheritdoc}
     */
    public function __construct(array $elements = [])
    {
        foreach ($elements as $element) {
            if (!$element instanceof Stat) {
                throw new InvalidArgumentException('Element is not a stat object.');
            }
        }

        parent::__construct($elements);
    }

    /**
     * {@inheritdoc}
     */
    public function removeElement($element)
    {
        if (!$element instanceof Stat) {
            throw new InvalidArgumentException('Element is not a stat object.');
        }

        return parent::removeElement($element);
    }

    /**
     * {@inheritDoc}
     */
    public function contains($element)
    {
        if (!$element instanceof Stat) {
            throw new InvalidArgumentException('Element is not a stat object.');
        }

        return parent::contains($element);
    }

    /**
     * {@inheritDoc}
     */
    public function indexOf($element)
    {
        if (!$element instanceof Stat) {
            throw new InvalidArgumentException('Element is not a stat object.');
        }

        return parent::indexOf($element);
    }

    /**
     * {@inheritDoc}
     */
    public function set($key, $value)
    {
        if (!$value instanceof Stat) {
            throw new InvalidArgumentException('Element is not a stat object.');
        }

        return parent::set($key, $value);
    }

    /**
     * {@inheritDoc}
     */
    public function add($element)
    {
        if (!$element instanceof Stat) {
            throw new InvalidArgumentException('Element is not a stat object.');
        }

        return parent::add($element);
    }
}


<?php

namespace Ds\Component\Acl\Voter;

use Ds\Component\Acl\Collection\PermissionCollection;
use Ds\Component\Acl\Model\Permission;
use Ds\Component\Acl\Service\AccessService;
use Ds\Component\Security\Model\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

/**
 * Class GenericVoter
 *
 * @package Ds\Component\Acl
 * @example Grant access if the user can execute the cache_clear permission
 * <code>
 *     @Security("is_granted('EXECUTE', 'cache_clear')")
 * </code>
 */
final class GenericVoter extends Voter
{
    /**
     * @var \Ds\Component\Acl\Service\AccessService
     */
    private $accessService;

    /**
     * @var \Ds\Component\Acl\Collection\PermissionCollection
     */
    private $permissionCollection;

    /**
     * Constructor
     *
     * @param \Ds\Component\Acl\Service\AccessService $accessService
     * @param \Ds\Component\Acl\Collection\PermissionCollection $permissionCollection
     */
    public function __construct(AccessService $accessService, PermissionCollection $permissionCollection)
    {
        $this->accessService = $accessService;
        $this->permissionCollection = $permissionCollection;
    }

    /**
     * {@inheritdoc}
     */
    protected function supports($attribute, $subject)
    {
        if (!in_array($attribute, [Permission::BROWSE, Permission::READ, Permission::EDIT, Permission::ADD, Permission::DELETE, Permission::EXECUTE], true)) {
            return false;
        }

        if (!is_string($subject)) {
            return false;
        }

        $permission = $this->permissionCollection->get($subject);

        if (!$permission) {
            return false;
        }

        if (Permission::GENERIC !== $permission->getType()) {
            return false;
        }

        return true;
    }

    /**
     * {@inheritdoc}
     */
    protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
    {
        $user = $token->getUser();

        if (!$user instanceof User) {
            return false;
        }

        $subject = $this->permissionCollection->get($subject);
        $permissions = $this->accessService->getPermissions($user);

        foreach ($permissions as $permission) {
            if (Permission::GENERIC !== $permission->getType()) {
                // Skip permissions that are not of type "generic".
                continue;
            }

            if (!fnmatch($permission->getValue(), $subject->getValue(), FNM_NOESCAPE)) {
                // Skip permissions that are not related to the subject.
                // The fnmatch function is used to match asterisk patterns.
                continue;
            }

            if (in_array($attribute, $permission->getAttributes(), true)) {
                return true;
            }
        }

        return false;
    }
}


<?php

namespace Ds\Component\Entity\Repository;

use Doctrine\ORM\EntityRepository as BaseEntityRepository;

/**
 * Class EntityRepository
 *
 * @package Ds\Component\Entity
 */
class EntityRepository extends BaseEntityRepository
{
    /**
     * Get count
     *
     * @param array $criteria
     * @return integer
     */
    public function getCount(array $criteria)
    {
        $persister = $this->_em->getUnitOfWork()->getEntityPersister($this->_entityName);

        return $persister->count($criteria);
    }
}


<?php

namespace Ds\Component\Model\Attribute\Accessor;

use DomainException;

/**
 * Trait Entity
 *
 * @package Ds\Component\Model
 */
trait Entity
{
    /**
     * Set entity
     *
     * @param string $entity
     * @return object
     * @throws \DomainException
     */
    public function setEntity(?string $entity)
    {
        if (null !== $entity) {
            if (!preg_match('/^[a-z]+$/i', $entity)) {
                throw new DomainException('Entity is not valid.');
            }
        }

        $this->entity = $entity;

        return $this;
    }

    /**
     * Get entity
     *
     * @return string
     */
    public function getEntity(): ?string
    {
        return $this->entity;
    }
}


<?php

namespace Ds\Component\Api\Query\Attribute;

/**
 * Trait IndividualUuid
 *
 * @package Ds\Component\Api
 */
trait IndividualUuid
{
    /**
     * @var string
     */
    private $individualUuid; # region accessors

    /**
     * Set individual uuid
     *
     * @param string $individualUuid
     * @return object
     */
    public function setIndividualUuid(?string $individualUuid)
    {
        $this->individualUuid = $individualUuid;
        $this->_individualUuid = true;

        return $this;
    }

    /**
     * Get individual uuid
     *
     * @return string
     */
    public function getIndividualUuid(): ?string
    {
        return $this->individualUuid;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_individualUuid;
}


<?php

namespace Ds\Component\Encryption\EventListener\Entity\Encryptable;

use Doctrine\ORM\Event\PreFlushEventArgs;
use Ds\Component\Encryption\Model\Type\Encryptable;

/**
 * Class PreFlushListener
 *
 * @package Ds\Component\Encryption
 */
final class PreFlushListener extends AbstractListener
{
    /**
     * Encrypt encryptable entity properties before saving in storage.
     *
     * @param \Doctrine\ORM\Event\PreFlushEventArgs $args
     */
    public function preFlush(PreFlushEventArgs $args)
    {
        $entities = $args->getEntityManager()->getUnitOfWork()->getScheduledEntityInsertions();

        foreach ($entities as $entity) {
            if (!$entity instanceof Encryptable) {
                continue;
            }

            $this->encryptionService->encrypt($entity);
        }
    }
}


<?php

namespace Ds\Component\Config\Service;

use Doctrine\ORM\EntityManagerInterface;
use Ds\Component\Config\Collection\ConfigCollection;
use Ds\Component\Config\Entity\Config;
use Ds\Component\Entity\Service\EntityService;
use OutOfRangeException;

/**
 * Class ConfigService
 *
 * @package Ds\Component\Config
 */
final class ConfigService extends EntityService
{
    /**
     * @var \Ds\Component\Config\Collection\ConfigCollection
     */
    private $collection;

    /**
     * Constructor
     *
     * @param \Doctrine\ORM\EntityManagerInterface $manager
     * @param \Ds\Component\Config\Collection\ConfigCollection $collection
     * @param string $entity
     */
    public function __construct(EntityManagerInterface $manager, ConfigCollection $collection, $entity = Config::class)
    {
        parent::__construct($manager, $entity);
        $this->collection = $collection;
    }

    /**
     * Get config value
     *
     * @param string $key
     * @return mixed
     * @throws \OutOfRangeException
     */
    public function get(string $key)
    {
        $config = $this->repository->findOneBy(['key' => $key]);

        if (!$config) {
            throw new OutOfRangeException('Config "'.$key.'" does not exist.');
        }

        $this->manager->detach($config);

        return $config->getValue();
    }

    /**
     * Set config value
     *
     * @param string $key
     * @param mixed $value
     */
    public function set(string $key, $value)
    {
        $config = $this->repository->findOneBy(['key' => $key]);

        if (!$config) {
            throw new OutOfRangeException('Config "'.$key.'" does not exist.');
        }

        $config
            ->setKey($key)
            ->setValue($value);
        $this->manager->persist($config);
        $this->manager->flush();
        $this->manager->detach($config);
    }
}


<?php

namespace Ds\Component\Acl\Tenant\Loader;

use Ds\Component\Database\Util\Objects;
use Ds\Component\Tenant\Entity\Tenant;

/**
 * Trait Acl
 *
 * @package Ds\Component\Acl
 */
trait Acl
{
    /**
     * @var \Ds\Component\Acl\Service\AccessService
     */
    private $accessService;

    /**
     * @var \Ds\Component\Acl\Service\PermissionService
     */
    private $permissionService;

    /**
     * @var string
     */
    private $path;

    /**
     * {@inheritdoc}
     */
    public function load(Tenant $tenant)
    {
        $data = (array) json_decode(json_encode($tenant->getData()));
        $objects = Objects::parseFile($this->path, $data);
        $manager = $this->accessService->getManager();

        foreach ($objects as $object) {
            $access = $this->accessService->createInstance();
            $access
                ->setOwner($object->owner)
                ->setOwnerUuid($object->owner_uuid)
                ->setAssignee($object->assignee)
                ->setAssigneeUuid($object->assignee_uuid)
                ->setTenant($object->tenant);

            foreach ($object->permissions as $subObject) {
                $permission = $this->permissionService->createInstance();
                $permission
                    ->setScope($subObject->scope)
                    ->setEntity($subObject->entity)
                    ->setEntityUuid($subObject->entity_uuid)
                    ->setKey($subObject->key)
                    ->setAttributes($subObject->attributes)
                    ->setTenant($object->tenant);
                $access->addPermission($permission);
            }

            $manager->persist($access);
            $manager->flush();
            $manager->detach($access);

            foreach ($access->getPermissions() as $permission) {
                $manager->detach($permission);
            }
        }
    }
}


<?php

namespace Ds\Component\Parameter\EventListener\Entity\Parameter\Serializer;

use Doctrine\ORM\Event\PostFlushEventArgs;
use Ds\Component\Parameter\Entity\Parameter;

/**
 * Class PostFlushListener
 *
 * @package Ds\Component\Parameter
 */
final class PostFlushListener
{
    /**
     * Unserialize parameter entity value property after saving from storage.
     *
     * @param \Doctrine\ORM\Event\PostFlushEventArgs $args
     */
    public function postFlush(PostFlushEventArgs $args)
    {
        $maps = $args->getEntityManager()->getUnitOfWork()->getIdentityMap();

        foreach ($maps as $entities) {
            foreach ($entities as $entity) {
                if (!$entity instanceof Parameter) {
                    continue;
                }

                $entity->setValue(unserialize($entity->getValue()));
            }
        }
    }
}


<?php

namespace Ds\Component\Tenant\Doctrine\ORM\Filter;

use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Filter\SQLFilter;
use Ds\Component\Tenant\Model\Type\Tenantable;

/**
 * Class TenantFilter
 *
 * @package Ds\Component\Tenant
 */
final class TenantFilter extends SQLFilter
{
    /**
     * Add a tenant sql condition if the entity is tenantable
     *
     * @param \Doctrine\ORM\Mapping\ClassMetadata $targetEntity
     * @param string $targetTableAlias
     * @return string
     */
    public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
    {
        if (!$targetEntity->reflClass->implementsInterface(Tenantable::class)) {
            return '';
        }

        $tenant = trim($this->getParameter('tenant'), '\'');

        if ('' === $tenant) {
            $constraint = sprintf('%s.tenant is NULL', $targetTableAlias);
        } else {
            $constraint = sprintf('%s.tenant = \'%s\'', $targetTableAlias, $tenant);
        }

        return $constraint;
    }
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

use Ds\Component\Camunda\Model\Variable;

/**
 * Trait Variables
 *
 * @package Ds\Component\Camunda
 */
trait Variables
{
    /**
     * @var array
     */
    private $variables; # region accessors

    /**
     * Set variables
     *
     * @param array $variables
     * @return object
     */
    public function setVariables(array $variables)
    {
        $this->variables = [];

        foreach ($variables as $variable) {
            $this->addVariable($variable);
        }

        return $this;
    }

    /**
     * Add variable
     *
     * @param \Ds\Component\Camunda\Model\Variable $variable
     * @return object
     */
    public function addVariable(Variable $variable)
    {
        $this->variables[] = $variable;
        $this->_variables = true;

        return $this;
    }

    /**
     * Get variables
     *
     * @return array
     */
    public function getVariables(): array
    {
        return $this->variables;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_variables;
}


<?php

namespace Ds\Component\Exception\EventListener;

use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpException;

/**
 * Class ExceptionListener
 *
 * @package Ds\Component\Exception
 */
final class ExceptionListener
{
    /**
     * @var string
     */
    private $environment;

    /**
     * Constructor
     *
     * @param string $environment
     */
    public function __construct(string $environment)
    {
        $this->environment = $environment;
    }

    /**
     * Format uncaught exceptions into the proper format based on request
     *
     * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
     */
    public function kernelException(GetResponseForExceptionEvent $event)
    {
        $exception = $event->getException();

        if ($exception instanceof ValidationException) {
            return;
        }

        $data = [
            'type' => 'https://tools.ietf.org/html/rfc2616#section-10',
            'title' =>'An error occurred'
        ];

        if (in_array($this->environment, ['dev', 'test'], true)) {
            $data['detail'] = $exception->getMessage();
            $data['trace'] = $exception->getTrace();
        }

        $request = $event->getRequest();
        $contentTypes = $request->getAcceptableContentTypes();
        $accept = array_shift($contentTypes);

        switch ($accept) {
            case 'application/json':
            case 'application/ld+json':
                $code = Response::HTTP_INTERNAL_SERVER_ERROR;

                if ($exception instanceof HttpException) {
                    $code = $exception->getStatusCode();
                }

                $response = new JsonResponse($data, $code);
                $event->setResponse($response);
                break;
        }
    }
}


<?php

namespace Ds\Component\Identity\EventListener;

use ApiPlatform\Core\DataProvider\PaginatorInterface as Paginator;
use Ds\Component\Model\Type\Enableable;
use LogicException;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

/**
 * Class EnabledListener
 *
 * @package Ds\Component\Identity
 */
final class EnabledListener
{
    /**
     * @var \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface
     */
    private $tokenStorage;

    /**
     * @var \Symfony\Component\Security\Core\Authorization\Voter\VoterInterface
     */
    private $voter;

    /**
     * Constructor
     *
     * @param \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface $tokenStorage
     * @param \Symfony\Component\Security\Core\Authorization\Voter\VoterInterface $voter
     */
    public function __construct(TokenStorageInterface $tokenStorage, VoterInterface $voter)
    {
        $this->tokenStorage = $tokenStorage;
        $this->voter = $voter;
    }

    /**
     * Deny access if the user does not have proper permissions
     *
     * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
     */
    public function kernelRequest(GetResponseEvent $event)
    {
        $request = $event->getRequest();
        $entity = $request->attributes->get('_api_resource_class');

        if (null === $entity) {
            return;
        }

        if (!in_array(Enableable::class, class_implements($entity), true)) {
            return;
        }

        $token = $this->tokenStorage->getToken();
        $data = $request->attributes->get('data');

        if ($data instanceof Paginator || is_array($data)) {
            foreach ($data as $item) {
                $vote = $this->voter->vote($token, $item, ['*']);

                if (VoterInterface::ACCESS_ABSTAIN === $vote) {
                    throw new LogicException('Voter cannot abstain from voting.');
                }

                if (VoterInterface::ACCESS_GRANTED !== $vote) {
                    throw new AccessDeniedException('Access denied.');
                }
            }
        } else {
            $vote = $this->voter->vote($token, $data, ['*']);

            if (VoterInterface::ACCESS_ABSTAIN === $vote) {
                throw new LogicException('Voter cannot abstain from voting.');
            }

            if (VoterInterface::ACCESS_GRANTED !== $vote) {
                throw new AccessDeniedException('Access denied.');
            }
        }
    }
}


<?php

namespace Ds\Component\Tenant\Fixture;

use Doctrine\Common\Persistence\ObjectManager;
use Ds\Component\Database\Fixture\Yaml;
use Ds\Component\Tenant\Entity\Tenant as TenantEntity;
use Ds\Component\Tenant\EventListener\LoaderListener;

/**
 * Class TenantFixture
 *
 * @package Ds\Component\Tenant
 */
trait Tenant
{
    use Yaml;

    /**
     * @var string
     */
    private $path;

    /**
     * {@inheritdoc}
     */
    public function load(ObjectManager $manager)
    {
        // Disable the event listener in charge of loading tenant data
        $metadata = $manager->getClassMetadata(TenantEntity::class);

        foreach ($metadata->entityListeners as $event => $listeners) {
            foreach ($listeners as $key => $listener) {
                if (LoaderListener::class === $listener['class']) {
                    unset($metadata->entityListeners[$event][$key]);
                }
            }
        }

        $objects = $this->parse($this->path);

        foreach ($objects as $object) {
            $tenant = new TenantEntity;
            $tenant
                ->setUuid($object->uuid)
                ->setData((array) $object->data);
            $manager->persist($tenant);
        }

        $manager->flush();
    }
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

/**
 * Trait SortBy
 *
 * @package Ds\Component\Camunda
 */
trait SortBy
{
    /**
     * @var string
     */
    private $sortBy; # region accessors

    /**
     * Set sort by
     *
     * @param string $sortBy
     * @return object
     */
    public function setSortBy(?string $sortBy)
    {
        $this->sortBy = $sortBy;
        $this->_sortBy = null !== $sortBy;

        return $this;
    }

    /**
     * Get sort by
     *
     * @return string
     */
    public function getSortBy(): ?string
    {
        return $this->sortBy;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_sortBy;
}


<?php

namespace Ds\Component\Form\Model\Attribute\Accessor;

use DomainException;
use ReflectionClass;

/**
 * Trait Type
 *
 * @package Ds\Component\Form
 */
trait Type
{
    /**
     * Set type
     *
     * @param string $type
     * @return object
     */
    public function setType(?string $type)
    {
        if (null !== $type && $this->getTypes() && !in_array($type, $this->getTypes(), true)) {
            throw new DomainException('Type does not exist.');
        }

        $this->type = $type;

        return $this;
    }

    /**
     * Get type
     *
     * @return string
     */
    public function getType(): ?string
    {
        return $this->type;
    }

    /**
     * Get types
     *
     * @return array
     */
    public function getTypes(): array
    {
        static $types;

        if (null === $types) {
            $types = [];
            $class = new ReflectionClass($this);

            foreach ($class->getConstants() as $constant => $value) {
                if ('TYPE_' === substr($constant, 0, 5)) {
                    $types[] = $value;
                }
            }
        }

        return $types;
    }
}


<?php

namespace Ds\Component\Api\Api;

use Ds\Component\Api\Collection\ServiceCollection;
use Ds\Component\Api\Service\Service;
use Ds\Component\Config\Service\ConfigService;
use Ds\Component\Discovery\Repository\ServiceRepository;
use Ds\Component\Security\Model\User;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use OutOfRangeException;

/**
 * Class Api
 *
 * @package Ds\Component\Api
 */
final class Api
{
    /**
     * @var \Ds\Component\Api\Collection\ServiceCollection
     */
    private $serviceCollection;

    /**
     * @var \Ds\Component\Discovery\Repository\ServiceRepository
     */
    private $serviceRepository;

    /**
     * @var \Ds\Component\Config\Service\ConfigService
     */
    private $configService;

    /**
     * @var string
     */
    private $namespace;

    /**
     * @var string
     */
    private $environment;

    /**
     * @var \Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface
     */
    private $tokenManager;

    /**
     * @var string
     */
    private $token;

    /**
     * Constructor
     *
     * @param \Ds\Component\Api\Collection\ServiceCollection $serviceCollection
     * @param \Ds\Component\Discovery\Repository\ServiceRepository $serviceRepository
     * @param \Ds\Component\Config\Service\ConfigService $configService
     * @param string $namespace
     * @param string $environment
     * @param \Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface $tokenManager
     */
    public function __construct(ServiceCollection $serviceCollection, ServiceRepository $serviceRepository, ConfigService $configService, string $namespace = 'ds', string $environment = 'prod', JWTTokenManagerInterface $tokenManager)
    {
        $this->serviceCollection = $serviceCollection;
        $this->serviceRepository = $serviceRepository;
        $this->configService = $configService;
        $this->namespace = $namespace;
        $this->environment = $environment;
        $this->tokenManager = $tokenManager;
    }

    /**
     * Get service
     *
     * @param string $alias
     * @return \Ds\Component\Api\Service\Service
     * @throws \OutOfRangeException
     */
    public function get(string $alias): Service
    {
        if (!$this->serviceCollection->containsKey($alias)) {
            throw new OutOfRangeException('Service "'.$alias.'" does not exist.');
        }

        $service = $this->serviceCollection->get($alias);
        $entry = $this->serviceRepository->find($this->namespace.'_'.explode('.', $alias)[0].'_api_http');

        if ($entry) {
            foreach ($entry->getTags() as $tag) {
                if (substr($tag, 0, 25) === 'proxy.frontend.rule=Host:') {
                    $host = substr($tag, 25);
                    $service->setHost($host);
                }
            }
        }

        $credentials = 'Bearer '.$this->getToken();
        $service->setHeader('Authorization', $credentials);

        return $service;
    }

    /**
     * Get token
     *
     * @return string
     */
    protected function getToken(): string
    {
        if (!$this->token) {
            $username = $this->configService->get('ds_api.user.username');
            $payload = [
                'uuid' => $this->configService->get('ds_api.user.uuid'),
                'roles' => $this->configService->get('ds_api.user.roles'),
                'identity' => (object) [
                    'roles' => $this->configService->get('ds_api.user.identity.roles'),
                    'type' => $this->configService->get('ds_api.user.identity.type'),
                    'uuid' => $this->configService->get('ds_api.user.identity.uuid')
                ],
                'tenant' => $this->configService->get('ds_api.user.tenant')
            ];
            $user = User::createFromPayload($username, $payload);
            $this->token = $this->tokenManager->create($user);
        }

        return $this->token;
    }
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

/**
 * Trait IncludeAssignedTasks
 *
 * @package Ds\Component\Camunda
 */
trait IncludeAssignedTasks
{
    /**
     * @var boolean
     */
    private $includeAssignedTasks; # region accessors

    /**
     * Set include assigned tasks
     *
     * @param boolean $includeAssignedTasks
     * @return object
     */
    public function setIncludeAssignedTasks(?bool $includeAssignedTasks)
    {
        $this->includeAssignedTasks = $includeAssignedTasks;
        $this->_includeAssignedTasks = null !== $includeAssignedTasks;

        return $this;
    }

    /**
     * Get includeAssignedTasks
     *
     * @return boolean
     */
    public function getIncludeAssignedTasks(): ?bool
    {
        return $this->includeAssignedTasks;
    }

    # endregion

    /**
     * @var boolean
     */
    private $_includeAssignedTasks;
}


<?php

namespace Ds\Component\Health\Service;

use Ds\Component\Health\Collection\CheckCollection;
use Ds\Component\Health\Exception\InvalidAliasException;
use Ds\Component\Health\Model\Statuses;

/**
 * Class HealthService
 *
 * @package Ds\Component\Health
 */
final class HealthService
{
    /**
     * @var \Ds\Component\Health\Collection\CheckCollection
     */
    private $checkCollection;

    /**
     * Constructor
     *
     * @param \Ds\Component\Health\Collection\CheckCollection $checkCollection
     */
    public function __construct(CheckCollection $checkCollection)
    {
        $this->checkCollection = $checkCollection;
    }

    /**
     * Run health checks
     *
     * @param string $alias
     * @return \Ds\Component\Health\Model\Statuses|\Ds\Component\Health\Model\Status
     * @throws \Ds\Component\Health\Exception\InvalidAliasException
     */
    public function check($alias = null)
    {
        if (null === $alias) {
            $statuses = new Statuses;
            $statuses->setHealthy(true);

            foreach ($this->checkCollection as $check) {
                $status = $check->execute();
                $statuses->getCollection()->add($status);

                if (!$status->getHealthy()) {
                    $statuses->setHealthy(false);
                }
            }

            return $statuses;
        } else {
            $check = $this->checkCollection->filter(function($element) use($alias) {
                return $element->getAlias() === $alias;
            })->first();

            if (!$check) {
                throw new InvalidAliasException('Check alias does not exist.');
            }

            $status = $check->execute();

            return $status;
        }
    }
}