<?php

namespace Ds\Component\Statistic\Service;

use Ds\Component\Statistic\Collection\StatCollection;
use Ds\Component\Statistic\Exception\InvalidAliasException;
use Ds\Component\Statistic\Model\Data;

/**
 * Class StatisticService
 *
 * @package Ds\Component\Statistic
 */
final class StatisticService
{
    /**
     * @var \Ds\Component\Statistic\Collection\StatCollection
     */
    private $statCollection;

    /**
     * Constructor
     *
     * @param \Ds\Component\Statistic\Collection\StatCollection $statCollection
     */
    public function __construct(StatCollection $statCollection)
    {
        $this->statCollection = $statCollection;
    }

    /**
     * Get all statistic data
     *
     * @return \Ds\Component\Statistic\Model\Data
     */
    public function getAll(): Data
    {
        $data = new Data;

        foreach ($this->statCollection as $stat) {
            $datum = $stat->get();
            $data->getCollection()->add($datum);
        }

        return $data;
    }

    /**
     * Get a statistic datum
     *
     * @param string $alias
     * @return \Ds\Component\Statistic\Model\Datum
     * @throws \Ds\Component\Statistic\Exception\InvalidAliasException
     */
    public function get(string $alias)
    {
        $stat = $this->statCollection->filter(function($element) use($alias) {
            return $element->getAlias() === $alias;
        })->first();

        if (!$stat) {
            throw new InvalidAliasException('Stat alias "'.$alias.'" does not exist.');
        }

        $datum = $stat->get();

        return $datum;
    }
}


<?php

namespace Ds\Component\Tenant;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Ds\Component\Tenant\DependencyInjection\Compiler;
use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
 * Class DsTenantBundle
 *
 * @package Ds\Component\Tenant
 */
final class DsTenantBundle extends Bundle
{
    /**
     * {@inheritdoc}
     */
    public function build(ContainerBuilder $container)
    {
        parent::build($container);
        $container->addCompilerPass(new Compiler\LoaderPass);
        $container->addCompilerPass(new Compiler\UnloaderPass);
    }
}


<?php

namespace Ds\Component\Camunda\Query\Attribute;

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

    /**
     * Set assignee like
     *
     * @param string $assigneeLike
     * @return object
     */
    public function setAssigneeLike(?string $assigneeLike)
    {
        $this->assigneeLike = $assigneeLike;
        $this->_assigneeLike = null !== $assigneeLike;

        return $this;
    }

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

    # endregion

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


<?php

namespace Ds\Component\Bpm\Resolver\Context;

use DomainException;
use Ds\Component\Api\Api\Api;
use Ds\Component\Camunda\Query\VariableParameters;
use Ds\Component\Resolver\Exception\UnresolvedException;
use Ds\Component\Resolver\Resolver\Resolver;
use Exception;
use Symfony\Component\PropertyAccess\PropertyAccess;

/**
 * Class BpmResolver
 *
 * @package Ds\Component\Bpm
 */
final class BpmResolver implements Resolver
{
    /**
     * @const string
     */
    const PATTERN = '/^ds\[bpm\]\.(.+)/';
    const PATTERN_TASK = '/^(task\.variable)\.([-_a-zA-Z0-9]+)(\.(.+))?/';

    /**
     * @const string
     */
    const CONTEXT_TASK = 'task';

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

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

    /**
     * Constructor
     *
     * @param \Ds\Component\Api\Api\Api $api
     */
    public function __construct(Api $api)
    {
        $this->api = $api;
        $this->contexts = [];
    }

    /**
     * {@inheritdoc}
     */
    public function isMatch(string $variable, array &$matches = []): bool
    {
        if (!preg_match(static::PATTERN, $variable, $matches)) {
            return false;
        }

        $variable = $matches[1];

        foreach (array_keys($this->contexts) as $context) {
            switch ($context) {
                case static::CONTEXT_TASK:
                    if (preg_match(static::PATTERN_TASK, $variable, $matches)) {
                        return true;
                    }

                    break;
            }
        }

        return false;
    }

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

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

        $value = null;
        $resource = $matches[1];

        switch ($resource) {
            case 'task.variable':
                $task = $this->contexts[static::CONTEXT_TASK];
                $variable = $matches[2];
                $property = array_key_exists(4, $matches) ? $matches[4] : null;
                $parameters = new VariableParameters;
                $parameters->setDeserializeValues(true);
                $variables = $this->api->get('camunda.task.variable')->getList($task, $parameters);

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

                $value = $variables[$variable]->getValue();

                if (null !== $property) {
                    $accessor = PropertyAccess::createPropertyAccessor();

                    try {
                        $value = $accessor->getValue($value, $property);
                    } catch (Exception $exception) {
                        throw new UnresolvedException('Variable pattern is not valid.', 0, $exception);
                    }
                }

                break;
        }

        return $value;
    }

    /**
     * Set context
     *
     * @param string $context
     * @param mixed $value
     * @return \Ds\Component\Bpm\Resolver\Context\BpmResolver
     * @throws \DomainException
     */
    public function setContext($context, $value)
    {
        if (!in_array($context, [static::CONTEXT_TASK], true)) {
            throw new DomainException('Context does not exist.');
        }

        $this->contexts[$context] = $value;

        return $this;
    }
}


<?php

namespace Ds\Component\Tenant\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use Ds\Component\Tenant\Doctrine\ORM\Filter\TenantFilter;
use Ds\Component\Tenant\Service\TenantService;

/**
 * Class ContextListener
 *
 * @package Ds\Component\Tenant
 */
final class ContextListener
{
    /**
     * @var \Doctrine\ORM\EntityManagerInterface
     */
    private $entityManager;

    /**
     * @var \Ds\Component\Tenant\Service\TenantService
     */
    private $tenantService;

    /**
     * Constructor
     *
     * @param \Doctrine\ORM\EntityManagerInterface $entityManager
     * @param \Ds\Component\Tenant\Service\TenantService $tenantService
     */
    public function __construct(EntityManagerInterface $entityManager, TenantService $tenantService)
    {
        $this->entityManager = $entityManager;
        $this->tenantService = $tenantService;
    }

    /**
     * Determine the contextual tenant
     */
    public function onPreAuthentication()
    {
        $this->entityManager->getConfiguration()->addFilter('tenant', TenantFilter::class);
        $filter = $this->entityManager->getFilters()->enable('tenant');
        $tenant = $this->tenantService->getContext();
        $filter->setParameter('tenant', (string) $tenant);
    }

    /**
     * Determine the contextual tenant
     */
    public function onPostAuthentication()
    {
        $filter = $this->entityManager->getFilters()->enable('tenant');
        $tenant = $this->tenantService->getContext();
        $filter->setParameter('tenant', (string) $tenant);
    }
}


<?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 PropertyVoter
 *
 * @package Ds\Component\Acl
 * @example Grant access if the user can browse the object's uuid property
 * <code>
 *     @Security("is_granted('BROWSE', [object, 'uuid'])")
 * </code>
 */
final class PropertyVoter 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_array($subject)) {
            return false;
        }

        if (2 !== count($subject)) {
            return false;
        }

        if (!array_key_exists(0, $subject)) {
            return false;
        }

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

        $class = get_class($subject[0]);

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

        if (!array_key_exists(1, $subject)) {
            return false;
        }

        if (!is_string($subject[1])) {
            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::PROPERTY !== $permission->getType()) {
                // Skip permissions that are not of type "property".
                continue;
            }

            if (!fnmatch($permission->getValue(), get_class($subject[0]).'.'.$subject[1], FNM_NOESCAPE)) {
                // Skip permissions that are not related to the subject entity property.
                // 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[0] instanceof Identitiable) {
                        // Skip permissions with scope "identity" if the subject entity is not identitiable.
                        continue;
                    }

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

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

                    break;

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

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

                    if (null !== $permission->getEntityUuid()) {
                        if ($permission->getEntityUuid() !== $subject[0]->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\Formio\Service;

use Ds\Component\Api\Service\Service;
use Ds\Component\Formio\Model\User;
use Ds\Component\Formio\Query\UserParameters;
use stdClass;
use DateTime;

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

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

    /**
     * @const string
     */
    const RESOURCE_LIST = '/user/submission';
    const RESOURCE_OBJECT = '/user/submission/{id}';
    const RESOURCE_OBJECT_EXISTS = '/user/exists';

    /**
     * @var array
     */
    private static $map = [
        'id' => '_id',
        'updated' => 'modified',
        'created',
        'form',
        'data',
        'externalIds',
        'access',
        'roles',
        'owner'
    ];

    /**
     * Get submissions list
     *
     * @param string $form
     * @return array
     */
    public function getList($form): array
    {
        $objects = $this->execute('GET', 'http://www.mocky.io/v2/592c3c86110000f8016df7de');
        $list = [];

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

        return $list;
    }

    /**
     * Get user
     *
     * @param string $form
     * @param string $id
     * @return \Ds\Component\Formio\Model\User
     */
    public function get(string $form, string $id)
    {
        $object = $this->execute('GET', 'http://www.mocky.io/v2/592c4353110000e3026df7f8');
        $model = static::toModel($object);

        return $model;
    }

    /**
     * Check if a user exists
     *
     * @param \Ds\Component\Formio\Query\UserParameters $parameters
     * @return boolean
     */
    public function exists(UserParameters $parameters = null)
    {
        $object = $this->execute('GET', 'http://www.mocky.io/v2/592c6f7311000029066df850');

        if ($object && property_exists($object, '_id') && $object->_id) {
            return true;
        }

        return false;
    }

    /**
     * Create user
     *
     * @param \Ds\Component\Formio\Model\User $user
     */
    public function create(User $user)
    {

    }

    /**
     * Update user
     *
     * @param \Ds\Component\Formio\Model\User $user
     */
    public function update(User $user)
    {

    }

    /**
     * Delete user
     *
     * @param string $id
     */
    public function delete($id)
    {

    }
}


<?php

namespace Ds\Component\Acl\Fixture;

use Doctrine\Common\Persistence\ObjectManager;
use Ds\Component\Acl\Entity\Access as AccessEntity;
use Ds\Component\Database\Fixture\Yaml;

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

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

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

        foreach ($objects as $object) {
            $access = new AccessEntity;
            $access
                ->setUuid($object->uuid)
                ->setOwner($object->owner)
                ->setOwnerUuid($object->owner_uuid)
                ->setAssignee($object->assignee)
                ->setAssigneeUuid($object->assignee_uuid)
                ->setTenant($object->tenant);
            $manager->persist($access);
        }

        $manager->flush();
    }
}


<?php

namespace Ds\Component\Security\EventListener\Token;

use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTDecodedEvent;
use OutOfRangeException;

/**
 * Class ModifierListener
 *
 * @package Ds\Component\Security
 */
final class ModifierListener
{
    /**
     * @var array
     */
    private $removed;

    /**
     * Constructor
     *
     * @param array $removed
     */
    public function __construct(array $removed = [])
    {
        $this->removed = $removed;
    }

    /**
     * Modify the jwt token
     *
     * @param \Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent $event
     * @throws \OutOfRangeException
     */
    public function created(JWTCreatedEvent $event)
    {
        $data = $event->getData();

        foreach ($this->removed as $property) {
            if (!array_key_exists($property, $data)) {
                throw new OutOfRangeException('Property does not exist.');
            }

            unset($data[$property]);
        }

        $event->setData($data);
    }

    /**
     * Mark the token as invalid if the token is not modified
     *
     * @param \Lexik\Bundle\JWTAuthenticationBundle\Event\JWTDecodedEvent $event
     */
    public function decoded(JWTDecodedEvent $event)
    {
        $payload = $event->getPayload();

        // Make property accessor paths compatible by converting payload to recursive associative array
        $payload = json_decode(json_encode($payload), true);

        foreach ($this->removed as $property) {
            if (array_key_exists($property, $payload)) {
                $event->markAsInvalid();
                break;
            }
        }
    }
}


<?php

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

use Doctrine\ORM\QueryBuilder;
use Doctrine\ORM\Query\Expr\Join;

/**
 * Trait Translation
 *
 * @package Ds\Component\Translation
 */
trait Translation
{
    /**
     * Join translation table
     *
     * @param \Doctrine\ORM\QueryBuilder $queryBuilder
     * @param string $resourceClass
     * @return string
     */
    protected function addJoinTranslation(QueryBuilder $queryBuilder, string $resourceClass)
    {
        $rootAlias = $queryBuilder->getRootAliases()[0];
        $translationAlias = $rootAlias.'_t';
        $translationClass = call_user_func($resourceClass.'::getTranslationEntityClass');
        $parts = $queryBuilder->getDQLParts()['join'];

        foreach ($parts as $joins) {
            foreach ($joins as $join) {
                if ($translationAlias === $join->getAlias()) {
                    return $translationAlias;
                }
            }
        }

        $queryBuilder->leftJoin(
            $translationClass,
            $translationAlias,
            Join::WITH,
            $rootAlias.'.id = '.$translationAlias.'.translatable'
        );

        return $translationAlias;
    }
}


<?php

namespace Ds\Component\Health\Collection;

use Doctrine\Common\Collections\ArrayCollection;
use Ds\Component\Health\Check\Check;
use InvalidArgumentException;

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

        parent::__construct($elements);
    }

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

        return parent::removeElement($element);
    }

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

        return parent::contains($element);
    }

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

        return parent::indexOf($element);
    }

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

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

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

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


<?php

namespace Ds\Component\Model\Attribute\Accessor;

use DomainException;
use ReflectionClass;

/**
 * Trait State
 *
 * @package Ds\Component\Model
 */
trait State
{
    /**
     * Set state
     *
     * @param integer $state
     * @return object
     * @throws \DomainException
     */
    public function setState(?int $state)
    {
        if (null !== $state && $this->getStates() && !in_array($state, $this->getStates(), true)) {
            throw new DomainException('State "'.$state.'" does not exist.');
        }

        $this->state = $state;

        return $this;
    }

    /**
     * Get state
     *
     * @return integer
     */
    public function getState(): ?int
    {
        return $this->state;
    }

    /**
     * Get states
     *
     * @return array
     */
    public function getStates(): array
    {
        static $states;

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

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

        return $states;
    }
}


<?php

namespace Ds\Component\Identity\Doctrine\ORM\QueryExtension;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
use Ds\Component\Security\Model\Identity;
use Ds\Component\Model\Type\Enableable;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

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

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

    /**
     * {@inheritdoc}
     */
    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
    {
        $this->apply($queryBuilder, $resourceClass);
    }

    /**
     * {@inheritdoc}
     */
    public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = [])
    {
        $this->apply($queryBuilder, $resourceClass);
    }

    /**
     * Apply condition
     *
     * @param \Doctrine\ORM\QueryBuilder $queryBuilder
     * @param string $resourceClass
     */
    protected function apply(QueryBuilder $queryBuilder, string $resourceClass)
    {
        if (!in_array(Enableable::class, class_implements($resourceClass), true)) {
            return;
        }

        $token = $this->tokenStorage->getToken();

        if ($token) {
            $user = $token->getUser();

            if (in_array($user->getIdentity()->getType(), [Identity::SYSTEM, Identity::STAFF], true)) {
                return;
            }
        }

        $rootAlias = $queryBuilder->getRootAliases()[0];
        $queryBuilder
            ->andWhere($rootAlias.'.enabled = :ds_security_enabled')
            ->setParameter('ds_security_enabled', 1);
    }
}


<?php

namespace Ds\Component\Parameter\DependencyInjection;

use Ds\Component\Parameter\Collection\ParameterCollection;
use LogicException;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader;

/**
 * Class DsParameterExtension
 *
 * @package Ds\Component\Parameter
 */
final class DsParameterExtension extends Extension
{
    /**
     * {@inheritdoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration;
        $config = $this->processConfiguration($configuration, $configs);

        $loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
        $loader->load('services.yaml');

        $elements = [];

        foreach ($config['parameters'] as $element) {
            if (!array_key_exists('key', $element)) {
                throw new LogicException('Config key is missing.');
            }

            if (!array_key_exists('encrypt', $element)) {
                $element['encrypt'] = false;
            }

            if (!array_key_exists('title', $element)) {
                $element['title'] = null;
            }

            $elements[$element['key']] = $element;
        }

        $definition = $container->findDefinition(ParameterCollection::class);
        $definition->setArguments([$elements]);
    }
}


<?php

namespace Ds\Component\Acl\Doctrine\ORM\QueryExtension;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
use Ds\Component\Acl\Collection\EntityCollection;
use Ds\Component\Acl\Service\AccessService;
use Ds\Component\Acl\Exception\NoPermissionsException;
use Ds\Component\Acl\Model\Permission;
use Ds\Component\Model\Type\Identitiable;
use Ds\Component\Model\Type\Ownable;
use Ds\Component\Model\Type\Uuidentifiable;
use LogicException;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

/**
 * Class EntityExtension
 *
 * @package Ds\Component\Acl
 */
final class EntityExtension implements QueryCollectionExtensionInterface
{
    /**
     * @var \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface
     */
    private $tokenStorage;

    /**
     * @var \Ds\Component\Acl\Service\AccessService
     */
    private $accessService;

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

    /**
     * Constructor
     *
     * @param \Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface $tokenStorage
     * @param \Ds\Component\Acl\Service\AccessService $accessService
     * @param \Ds\Component\Acl\Collection\EntityCollection $entityCollection
     */
    public function __construct(TokenStorageInterface $tokenStorage, AccessService $accessService, EntityCollection $entityCollection)
    {
        $this->tokenStorage = $tokenStorage;
        $this->accessService = $accessService;
        $this->entityCollection = $entityCollection;
    }

    /**
     * {@inheritdoc}
     */
    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
    {
        if (!$this->entityCollection->contains($resourceClass)) {
            return;
        }

        $token = $this->tokenStorage->getToken();

        if (!$token) {
            throw new LogicException('Token is not defined.');
        }

        $user = $token->getUser();
        $permissions = $this->accessService->getPermissions($user);
        $rootAlias = $queryBuilder->getRootAliases()[0];
        $conditions = [];
        $parameters = [];
        $i = 0;

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

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

            if (!in_array(Permission::BROWSE, $permission->getAttributes(), true)) {
                // Skip permissions that do not have the required attribute.
                continue;
            }

            switch ($permission->getScope()) {
                case 'generic':
                    // This permission grants access to all entities of the class, no conditions need to be applied.
                    return;

                case 'object':
                    if (!in_array(Uuidentifiable::class, class_implements($resourceClass), true)) {
                        // Skip permissions with scope "object" if the entity is not uuidentifiable.
                        continue;
                    }

                    $conditions[] = $queryBuilder->expr()->eq($rootAlias.'.uuid', ':ds_security_uuid_'.$i);
                    $parameters['ds_security_uuid_'.$i] = $permission->getEntityUuid();
                    $i++;

                    break;

                case 'identity':
                    if (!in_array(Identitiable::class, class_implements($resourceClass), true)) {
                        // Skip permissions with scope "identity" if the entity is not identitiable.
                        continue;
                    }

                    if (in_array($resourceClass, [
                        'App\\Entity\\Anonymous',
                        'App\\Entity\\Individual',
                        'App\\Entity\\Organization',
                        'App\\Entity\\Staff'
                    ])) {
                        $conditions[] = $queryBuilder->expr()->eq($rootAlias.'.uuid', ':ds_security_identity_'.$i);
                        $parameters['ds_security_identity_'.$i] = $permission->getEntity();
                    } else if (in_array($resourceClass, [
                        'App\\Entity\\AnonymousPersona',
                        'App\\Entity\\IndividualPersona',
                        'App\\Entity\\OrganizationPersona',
                        'App\\Entity\\StaffPersona'
                    ])) {
                        $identity = substr($resourceClass, 0, -7);
                        $alias = strtolower(substr($resourceClass, 17, -7));
                        $subQueryBuilder = new QueryBuilder($queryBuilder->getEntityManager());
                        $conditions[] = $queryBuilder->expr()->in(
                            $rootAlias.'.'.$alias,
                            $subQueryBuilder
                                ->select($alias)
                                ->from($identity, $alias)
                                ->where($alias.'.uuid = :ds_security_identity_uuid_'.$i)
                                ->getDQL()
                        );
                        $parameters['ds_security_identity_uuid_'.$i] = $permission->getEntityUuid();
                    } else {
                        $conditions[] = $queryBuilder->expr()->andX(
                            $queryBuilder->expr()->eq($rootAlias.'.identity', ':ds_security_identity_'.$i),
                            $queryBuilder->expr()->eq($rootAlias.'.identityUuid', ':ds_security_identity_uuid_'.$i)
                        );
                        $parameters['ds_security_identity_'.$i] = $permission->getEntity();
                        $parameters['ds_security_identity_uuid_'.$i] = $permission->getEntityUuid();
                    }

                    $i++;

                    break;

                case 'owner':
                    if (!in_array(Ownable::class, class_implements($resourceClass), true)) {
                        // Skip permissions with scope "owner" if the entity is not ownable.
                        continue;
                    }

                    if (null === $permission->getEntityUuid()) {
                        $conditions[] = $queryBuilder->expr()->eq($rootAlias.'.owner', ':ds_security_owner_'.$i);
                        $parameters['ds_security_owner_'.$i] = $permission->getEntity();
                    } else {
                        $conditions[] = $queryBuilder->expr()->andX(
                            $queryBuilder->expr()->eq($rootAlias.'.owner', ':ds_security_owner_'.$i),
                            $queryBuilder->expr()->eq($rootAlias.'.ownerUuid', ':ds_security_owner_uuid_'.$i)
                        );
                        $parameters['ds_security_owner_'.$i] = $permission->getEntity();
                        $parameters['ds_security_owner_uuid_'.$i] = $permission->getEntityUuid();
                    }

                    $i++;

                    break;

                case 'session':
                    if (!in_array(Identitiable::class, class_implements($resourceClass), true)) {
                        // Skip permissions with scope "session" if the entity is not identitiable.
                        continue;
                    }

                    // @todo Refactor this exception handling at the entity level with metadata, the core should not know about these details.
                    if (in_array($resourceClass, [
                        'App\\Entity\\Anonymous',
                        'App\\Entity\\Individual',
                        'App\\Entity\\Organization',
                        'App\\Entity\\Staff'
                    ])) {
                        $conditions[] = $queryBuilder->expr()->eq($rootAlias.'.uuid', ':ds_security_identity_uuid_'.$i);
                        $parameters['ds_security_identity_uuid_'.$i] = $user->getIdentity()->getUuid();
                    } else if (in_array($resourceClass, [
                        'App\\Entity\\AnonymousPersona',
                        'App\\Entity\\IndividualPersona',
                        'App\\Entity\\OrganizationPersona',
                        'App\\Entity\\StaffPersona'
                    ])) {
                        $identity = substr($resourceClass, 0, -7);
                        $alias = strtolower(substr($resourceClass, 17, -7));
                        $subQueryBuilder = new QueryBuilder($queryBuilder->getEntityManager());
                        $conditions[] = $queryBuilder->expr()->in(
                            $rootAlias.'.'.$alias,
                            $subQueryBuilder
                                ->select($alias)
                                ->from($identity, $alias)
                                ->where($alias.'.uuid = :ds_security_identity_uuid_'.$i)
                                ->getDQL()
                        );
                        $parameters['ds_security_identity_uuid_'.$i] = $user->getIdentity()->getUuid();
                    } else {
                        $conditions[] = $queryBuilder->expr()->andX(
                            $queryBuilder->expr()->eq($rootAlias.'.identity', ':ds_security_identity_'.$i),
                            $queryBuilder->expr()->eq($rootAlias.'.identityUuid', ':ds_security_identity_uuid_'.$i)
                        );
                        $parameters['ds_security_identity_'.$i] = $user->getIdentity()->getType();
                        $parameters['ds_security_identity_uuid_'.$i] = $user->getIdentity()->getUuid();
                    }

                    $i++;

                    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 (!$conditions) {
            throw new NoPermissionsException;
        }

        $queryBuilder->andWhere(call_user_func_array([$queryBuilder->expr(), 'orX'], $conditions));

        foreach ($parameters as $key => $value) {
            $queryBuilder->setParameter($key, $value);
        }
    }
}


<?php

namespace Ds\Component\System\Service;

use DateTime;
use Ds\Component\System\Model\Model;
use GuzzleHttp\Client;
use InvalidArgumentException;
use LogicException;
use stdClass;
use UnexpectedValueException;

/**
 * Trait Base
 *
 * @package Ds\Component\System
 */
trait Base
{
    /**
     * Cast object to model
     *
     * @param \stdClass $object
     * @return \Ds\Component\Api\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 'createdAt':
                    case 'updatedAt':
                        $model->{'set'.ucfirst($local)}(new DateTime($object->$remote));
                        break;

                    case 'data':
                        $model->{'set'.ucfirst($local)}((array) $object->$remote);
                        break;

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

        return $model;
    }

    /**
     * Cast model to object
     *
     * @param \Ds\Component\System\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;
            }

            $value = $model->{'get'.ucfirst($local)}();

            switch ($local) {
                case 'createdAt':
                case 'updatedAt':
                    if ($value) {
                        $object->$remote = $value->format('Y-m-d\TH:i:sP');
                    }

                    break;

                default:
                    $object->$remote = $value;
            }
        }

        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($host = null, array $headers = [])
    {
        $this->client = new Client;
        $this->host = $host;

        if (!isset($headers['Content-Type'])) {
            $headers['Content-Type'] = 'application/json';
        }

        if (!isset($headers['Accept'])) {
            $headers['Accept'] = 'application/json';
        }

        $this->headers = $headers;
    }

    /**
     * Execute api request
     *
     * @param string $method
     * @param string $resource
     * @param array $options
     * @return mixed
     */
    protected function execute($method, $resource, array $options = [])
    {
        $uri = $this->host.$resource;

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

        $response = $this->client->request($method, $uri, $options);
        $data = (string) $response->getBody();

        if ('' !== $data) {
            try {
                $data = \GuzzleHttp\json_decode($data);
            } catch (InvalidArgumentException $exception) {
                throw new UnexpectedValueException('Service response is not valid.', 0, $exception);
            }
        }

        return $data;
    }
}


<?php

namespace Ds\Component\Api\Query\Attribute;

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

    /**
     * Set organization uuid
     *
     * @param string $organizationUuid
     * @return object
     */
    public function setOrganizationUuid(?string $organizationUuid)
    {
        $this->organizationUuid = $organizationUuid;
        $this->_organizationUuid = true;

        return $this;
    }

    /**
     * Get organization uuid
     *
     * @return string
     */
    public function getOrganizationUuid(): ?string
    {
        return $this->organizationUuid;
    }

    # endregion

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


<?php

namespace Ds\Component\Entity\Service;

use Ds\Component\Model\Type\CustomIdentifiable;
use Ds\Component\Model\Type\Uuidentifiable;
use Ramsey\Uuid\Uuid;

/**
 * Class IdService
 *
 * @package Ds\Component\Entity
 */
class IdService
{
    /**
     * Constructor
     */
    public function __construct()
    {

    }

    /**
     * Generate entity custom id, if none present
     *
     * @param \Ds\Component\Model\Type\CustomIdentifiable $entity
     * @param boolean $overwrite
     * @return \Ds\Component\Entity\Service\IdService
     */
    public function generateCustomId(CustomIdentifiable $entity, bool $overwrite = false)
    {
        if (null === $entity->getCustomId() || $overwrite) {
            $customId = uniqid();
            $entity->setCustomId($customId);
        }

        return $this;
    }

    /**
     * Generate entity uuid, if none present
     *
     * @param \Ds\Component\Model\Type\Uuidentifiable $entity
     * @param boolean $overwrite
     * @return \Ds\Component\Entity\Service\IdService
     */
    public function generateUuid(Uuidentifiable $entity, bool $overwrite = false)
    {
        if (null === $entity->getUuid() || $overwrite) {
            $uuid = Uuid::uuid4()->toString();
            $entity->setUuid($uuid);
        }

        return $this;
    }
}


<?php

namespace Ds\Component\Audit\EventListener;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Ds\Component\Audit\Entity\Audit;
use Ds\Component\Audit\Model\Type\Auditable;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Class EntityListener
 *
 * @package Ds\Component\Audit
 */
final class EntityListener
{
    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private $container;

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

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

    /**
     * @var \Ds\Component\Audit\Service\AuditService
     */
    private $auditService;

    /**
     * Constructor
     *
     * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
     */
    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    /**
     * Generate an audit entry after persisting an entity
     *
     * @param \Doctrine\ORM\Event\LifecycleEventArgs $args
     */
    public function postPersist(LifecycleEventArgs $args)
    {
        $this->execute($args, Audit::ACTION_ADD);
    }

    /**
     * Generate an audit entry after updating an entity
     *
     * @param \Doctrine\ORM\Event\LifecycleEventArgs $args
     */
    public function postUpdate(LifecycleEventArgs $args)
    {
        $this->execute($args, Audit::ACTION_EDIT);
    }

    /**
     * Generate an audit entry after persisting an entity
     *
     * @param \Doctrine\ORM\Event\LifecycleEventArgs $args
     * @param string $action
     */
    protected function execute(LifecycleEventArgs $args, $action)
    {
        // Circular reference error workaround
        // @todo Look into fixing this
        $this->tokenStorage = $this->container->get('security.token_storage');
        $this->configService = $this->container->get('ds_config.service.config');
        $this->auditService = $this->container->get('ds_audit.service.audit');
        //

        $entity = $args->getEntity();

        if ($entity instanceof Audit) {
            return;
        }

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

        $token = $this->tokenStorage->getToken();

        if (!$token) {
            return;
        }

        $user = $token->getUser();
        $edits = $args->getEntityManager()->getUnitOfWork()->getEntityChangeSet($entity);
        $properties = $this->auditService->getProperties($entity);

        foreach (array_keys($edits) as $key) {
            if (!in_array($key, $properties)) {
                unset($edits[$key]);
            }
        }

        $audit = $this->auditService->createInstance();
        $audit
            ->setOwner($this->configService->get('ds_audit.audit.owner'))
            ->setOwnerUuid($this->configService->get('ds_audit.audit.owner_uuid'))
            ->setUserUuid($user->getUuid())
            ->setIdentity($user->getIdentity()->getType())
            ->setIdentityUuid($user->getIdentity()->getUuid())
            ->setAction($action)
            ->setData([
                'entity' => basename(str_replace('\\', '/', get_class($entity))),
                'entityUuid' => $entity->getUuid(),
                'edits' => $edits
            ]);

        $manager = $this->auditService->getManager();
        $manager->persist($audit);
        $manager->flush();
    }
}


<?php

namespace Ds\Component\Resolver;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Ds\Component\Resolver\DependencyInjection\Compiler;
use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
 * Class DsResolverBundle
 *
 * @package Ds\Component\Resolver
 */
final class DsResolverBundle extends Bundle
{
    /**
     * {@inheritdoc}
     */
    public function build(ContainerBuilder $container)
    {
        parent::build($container);
        $container->addCompilerPass(new Compiler\ResolverPass);
    }
}


<?php

namespace Ds\Component\Health\Check;

use Ds\Component\Health\Model\Status;
use Ds\Component\Model\Attribute;

/**
 * Class PingCheck
 *
 * @package Ds\Component\Health
 */
final class PingCheck implements Check
{
    use Attribute\Alias;

    /**
     * {@inheritdoc}
     */
    public function execute(): Status
    {
        $status = new Status;
        $status
            ->setAlias($this->alias)
            ->setHealthy(true);

        return $status;
    }
}


<?php

namespace Ds\Component\Formio\Service;

use Ds\Component\Api\Service\Service;
use Ds\Component\Formio\Model\User;

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

    /**
     * @const
     */
    const RESOURCE_LOGIN = '/user/login';
    const RESOURCE_LOGOUT = '/logout';

    /**
     * @var array
     */
    private static $map = [
    ];

    /**
     * Login
     *
     * @param \Ds\Component\Formio\Model\User $user
     * @return string
     */
    public function login(User $user): string
    {
        $options = [
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json'
            ],
            'json' => [
                'data' => [
                    'email' => $user->getEmail(),
                    'password' => $user->getPassword()
                ]
            ]
        ];
        $token = $this->execute('POST', static::RESOURCE_LOGIN, $options);

        return $token;
    }

    /**
     * Logout
     */
    public function logout()
    {
        $this->execute('GET', static::RESOURCE_LOGOUT);
    }
}


<?php

namespace Ds\Component\Identity\Voter;

use Ds\Component\Security\Model\Identity;
use Ds\Component\Model\Type\Enableable;
use Ds\Component\Security\Model\User;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;

/**
 * Class EnabledVoter
 *
 * @package Ds\Component\Identity
 */
final class EnabledVoter extends Voter
{
    /**
     * {@inheritdoc}
     */
    protected function supports($attribute, $subject)
    {
        if (!$subject instanceof Enableable) {
            return false;
        }

        return true;
    }

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

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

        if (in_array($user->getIdentity()->getType(), [Identity::SYSTEM, Identity::STAFF], true)) {
            return true;
        }

        if ($subject->getEnabled()) {
            return true;
        }

        return false;
    }
}


<?php

namespace Ds\Component\Translation\Service;

use Doctrine\Common\Annotations\Reader;
use Ds\Component\Translation\Model\Annotation\Translate;
use Ds\Component\Translation\Model\Type\Translatable;
use Ds\Component\Translation\Model\Type\Translation;
use ReflectionClass;

/**
 * Class TranslationService
 *
 * @package Ds\Component\Translation
 */
final class TranslationService
{
    /**
     * @var \Doctrine\Common\Annotations\Reader
     */
    private $annotationReader;

    /**
     * Constructor
     *
     * @param \Doctrine\Common\Annotations\Reader $annotationReader
     */
    public function __construct(Reader $annotationReader)
    {
        $this->annotationReader = $annotationReader;
    }

    /**
     * Translate translatable properties
     *
     * @param \Ds\Component\Translation\Model\Type\Translatable $model
     */
    public function translate(Translatable $model)
    {
        $properties = $this->getProperties($model);

        foreach ($properties as $property) {
            $get = 'get'.$property->getName();
            $set = 'set'.$property->getName();
            $values = [];

            foreach ($model->getTranslations() as $translation) {
                $values[$translation->getLocale()] = $translation->$get();
            }

            $model->$set($values);
        }
    }

    public function aggregate(Translation $model)
    {
        $translatable = $model->getTranslatable();
        $properties = $this->getProperties($translatable);

        foreach ($properties as $property) {
            $get = 'get'.$property->getName();
            $set = 'set'.$property->getName();
            $values = $translatable->$get();
            $values[$model->getLocale()] = $model->$get();
            $translatable->$set($values);
        }
    }

    /**
     * Transfer translatable properties to translations
     *
     * @param \Ds\Component\Translation\Model\Type\Translatable $model
     */
    public function transfer(Translatable $model)
    {
        $properties = $this->getProperties($model);

        foreach ($properties as $property) {
            $get = 'get'.$property->getName();
            $set = 'set'.$property->getName();
            $values = $model->$get();

            if (null !== $values) {
                foreach ($values as $locale => $value) {
                    $model->translate($locale, false)->$set($value);
                }
            }
        }

        $model->mergeNewTranslations();
    }

    /**
     * Get properties with Translate annotation
     *
     * @param \Ds\Component\Translation\Model\Type\Translatable $model
     * @return array
     */
    public function getProperties(Translatable $model): array
    {
        $class = get_class($model);

        if (substr($class, 0, 15) === 'Proxies\\__CG__\\') {
            $class = substr($class, 15);
        }

        $properties = [];
        $reflection = new ReflectionClass($class);

        foreach ($reflection->getProperties() as $property) {
            $annotation = $this->annotationReader->getPropertyAnnotation($property, Translate::class);

            if (!$annotation) {
                continue;
            }

            $properties[] = $property;
        }

        return $properties;
    }
}


<?php

namespace Ds\Component\Health;

use Ds\Component\Health\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
 * Class DsHealthBundle
 *
 * @package Ds\Component\Health
 */
final class DsHealthBundle extends Bundle
{
    /**
     * {@inheritdoc}
     */
    public function build(ContainerBuilder $container)
    {
        parent::build($container);
        $container->addCompilerPass(new Compiler\CheckPass);
    }
}


<?php

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

use InvalidArgumentException;

/**
 * Trait Uuid
 *
 * @package Ds\Component\Security
 */
trait Uuid
{
    /**
     * Set uuid
     *
     * @param string $uuid
     * @return object
     * @throws \InvalidArgumentException
     */
    public function setUuid(?string $uuid)
    {
        if (null !== $uuid) {
            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', $uuid)) {
                throw new InvalidArgumentException('Uuid is not valid.');
            }
        }

        $this->uuid = $uuid;

        return $this;
    }

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


<?php

namespace Ds\Component\Parameter\Command\Parameter;

use Ds\Component\Parameter\Service\ParameterService;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Class SetCommand
 *
 * @package Ds\Component\Parameter
 */
final class SetCommand extends Command
{
    /**
     * @var \Ds\Component\Parameter\Service\ParameterService
     */
    private $parameterService;

    /**
     * Constructor.
     *
     * @param \Ds\Component\Parameter\Service\ParameterService $parameterService
     * @param string $name
     */
    public function __construct(ParameterService $parameterService, $name = null)
    {
        parent::__construct($name);
        $this->parameterService = $parameterService;
    }

    /**
     * {@inheritdoc}
     */
    protected function configure()
    {
        $this
            ->setName('ds:parameter:set')
            ->addArgument('key', InputArgument::REQUIRED, 'The parameter key.')
            ->addArgument('value', InputArgument::REQUIRED, 'The parameter value.')
            ->setDescription('Sets a parameter value.')
            ->setHelp('This command allows you to set a parameter value.');
    }

    /**
     * {@inheritdoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $key = $input->getArgument('key');
        $value = $input->getArgument('value');
        $this->parameterService->set($key, $value);
    }
}


<?php

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

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

/**
 * Class PreUpdateListener
 *
 * @package Ds\Component\Parameter
 */
final class PreUpdateListener
{
    /**
     * Serialize parameter entity value property before saving in storage.
     *
     * @param \Doctrine\ORM\Event\PreUpdateEventArgs $args
     */
    public function preUpdate(PreUpdateEventArgs $args)
    {
        $entity = $args->getEntity();

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

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


<?php

namespace Ds\Component\Acl\Fixture;

use Doctrine\Common\Persistence\ObjectManager;
use Ds\Component\Acl\Entity\Access;
use Ds\Component\Acl\Entity\Permission as PermissionEntity;
use Ds\Component\Database\Fixture\Yaml;
use LogicException;

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

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

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

        foreach ($objects as $object) {
            if (!is_array($object->key)) {
                $object->key = [$object->key];
            }

            foreach ($object->key as $key) {
                $access = $manager->getRepository(Access::class)->findOneBy(['uuid' => $object->access]);

                if (!$access) {
                    throw new LogicException('Access "'.$object->access.'" does not exist.');
                }

                $permission = new PermissionEntity;
                $permission
                    ->setAccess($access)
                    ->setScope($object->scope)
                    ->setEntity($object->entity)
                    ->setEntityUuid($object->entity_uuid)
                    ->setKey($key)
                    ->setAttributes($object->attributes)
                    ->setTenant($object->tenant);
                $manager->persist($permission);
            }
        }

        $manager->flush();
    }
}


<?php

namespace Ds\Component\Acl\DependencyInjection;

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

/**
 * Class Configuration
 *
 * @package Ds\Component\Acl
 */
final class Configuration implements ConfigurationInterface
{
    /**
     * {@inheritdoc}
     */
    public function getConfigTreeBuilder()
    {
        $builder = new TreeBuilder;
        $node = $builder->root('ds_acl');
        $node
            ->children()
                ->booleanNode('enabled')
                    ->defaultTrue()
                ->end()
                ->arrayNode('entities')
                    ->scalarPrototype()
                    ->end()
                ->end()
                ->arrayNode('permissions')
                    ->useAttributeAsKey('name')
                    ->prototype('array')
                        ->children()
                            ->scalarNode('title')
                            ->end()
                            ->enumNode('type')
                                ->values(['generic', 'entity', 'property'])
                            ->end()
                            ->scalarNode('value')
                            ->end()
                            ->arrayNode('attributes')
                                ->prototype('enum')
                                ->values(['BROWSE', 'READ', 'EDIT', 'ADD', 'DELETE', 'EXECUTE'])
                                ->end()
                            ->end()
                            ->scalarNode('generic')
                            ->end()
                            ->scalarNode('entity')
                            ->end()
                            ->scalarNode('property')
                            ->end()
                        ->end()
                    ->end()
                ->end()
            ->end();

        return $builder;
    }
}


<?php

namespace Ds\Component\Camunda\Query;

use GuzzleHttp;
use Ds\Component\Camunda\Model\Variable;
use stdClass;

/**
 * Trait Base
 *
 * @package Ds\Component\Camunda
 */
trait Base
{
    /**
     * {@inheritdoc}
     */
    public function toObject(bool $minimal = false)
    {
        $object = new stdClass;

        foreach ($this as $key => $value) {
            if ('_' === substr($key, 0, 1)) {
                continue;
            }

            if ($minimal && !$this->{'_'.$key}) {
                continue;
            }

            switch ($key) {
                case 'variables':
                    $object->$key = [];

                    foreach ($value as $name => $variable) {
                        $object->$key[$variable->getName()] = (object) [
                            'name' => $variable->getName(),
                            'value' => $variable->getValue(),
                            'type' => $variable->getType(),
                            'valueInfo' => $variable->getValueInfo()
                        ];
                    }

                    break;

                case 'cascade':
                    $object->$key = $value ? 'true' : 'false';
                    break;

                case 'tenantIdIn':
                    $object->$key = implode(',', $value);
                    break;

                default:
                    $object->$key = $value;
            }
        }

        return $object;
    }
}


<?php

namespace Ds\Component\Acl\EventListener;

use Ds\Component\Acl\Exception\NoPermissionsException;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;

/**
 * Class ExceptionListener
 *
 * @package Ds\Component\Acl
 */
final class ExceptionListener
{
    /**
     * Convert NoPermissionsException into empty collections
     *
     * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
     * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
     */
    public function kernelException(GetResponseForExceptionEvent $event)
    {
        $exception = $event->getException();

        if (!$exception instanceof NoPermissionsException) {
            return;
        }

        // In the event a user requests a list of entities and has no permissions,
        // an empty list is returned.
        $response = new JsonResponse([]);
        $event->setResponse($response);
    }
}


<?php

namespace Ds\Component\Security\EventListener\Token\Identity;

use DomainException;
use Ds\Component\Api\Api\Api;
use Ds\Component\Security\Model\Identity;
use Ds\Component\Security\Model\User;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent;
use Lexik\Bundle\JWTAuthenticationBundle\Event\JWTDecodedEvent;
use Symfony\Component\PropertyAccess\PropertyAccess;

/**
 * Class RolesListener
 *
 * @package Ds\Component\Security
 */
final class RolesListener
{
    /**
     * @var \Ds\Component\Api\Api\Api
     */
    private $api;

    /**
     * @var \Symfony\Component\PropertyAccess\PropertyAccessor
     */
    private $accessor;

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

    /**
     * Constructor
     *
     * @param \Ds\Component\Api\Api\Api $api
     * @param string $property
     */
    public function __construct(Api $api, string $property = '[identity][roles]')
    {
        $this->api = $api;
        $this->accessor = PropertyAccess::createPropertyAccessor();
        $this->property = $property;
    }

    /**
     * Add the identity roles to the token
     *
     * @param \Lexik\Bundle\JWTAuthenticationBundle\Event\JWTCreatedEvent $event
     * @throws \Ds\Component\Security\Exception\InvalidUserTypeException
     */
    public function created(JWTCreatedEvent $event)
    {
        $data = $event->getData();
        $user = $event->getUser();
        $roles = [];

        // @todo remove condition when both user types are homogenized
        if ($user instanceof User) {
            $roles = $user->getIdentity()->getRoles();
        } else {
            if (null !== $user->getIdentityUuid()) {
                switch ($user->getIdentity()) {
                    case Identity::ANONYMOUS:
                        $identity = $this->api->get('identities.anonymous')->get($user->getIdentityUuid());
                        break;

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

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

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

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

                    default:
                        throw new DomainException('User identity is not valid.');
                }

                foreach ($identity->getRoles() as $role) {
                    // @todo Remove substr once we remove iri-based api foreign keys
                    $roles[] = substr($role, -36);
                }
            }
        }

        $this->accessor->setValue($data, $this->property, $roles);
        $event->setData($data);
    }

    /**
     * Mark the token as invalid if the identity roles is missing
     *
     * @param \Lexik\Bundle\JWTAuthenticationBundle\Event\JWTDecodedEvent $event
     */
    public function decoded(JWTDecodedEvent $event)
    {
        $payload = $event->getPayload();

        // Make property accessor paths compatible by converting payload to recursive associative array
        $payload = json_decode(json_encode($payload), true);

        if (!$this->accessor->isReadable($payload, $this->property)) {
            $event->markAsInvalid();
        }
    }
}


<?php

namespace Ds\Component\Form\Service;

use DomainException;
use Ds\Component\Api\Api\Api;
use Ds\Component\Form\Model\Form;
use Ds\Component\Formio\Query\FormParameters;
use Ds\Component\Resolver\Exception\UnmatchedException;
use Ds\Component\Resolver\Exception\UnresolvedException;
use Ds\Component\Resolver\Collection\ResolverCollection;
use Ds\Component\Tenant\Service\TenantService;
use InvalidArgumentException;

/**
 * Class FormService
 *
 * @package Ds\Component\Form
 */
final class FormService
{
    /**
     * @var \Ds\Component\Api\Api\Api
     */
    private $api;

    /**
     * @var \Ds\Component\Resolver\Collection\ResolverCollection
     */
    private $resolverCollection;

    /**
     * @var \Ds\Component\Tenant\Service\TenantService
     */
    private $tenantService;

    /**
     * Constructor
     *
     * @param \Ds\Component\Api\Api\Api $api
     * @param \Ds\Component\Resolver\Collection\ResolverCollection $resolverCollection
     * @param \Ds\Component\Tenant\Service\TenantService $tenantService
     * #param \Ds\Component\Tenant\Service\TenantService $tenantService
     */
    public function __construct(Api $api, ResolverCollection $resolverCollection, TenantService $tenantService)
    {
        $this->api = $api;
        $this->resolverCollection = $resolverCollection;
        $this->tenantService = $tenantService;
    }

    /**
     * Get form
     *
     * @param string $id
     * @return \Ds\Component\Form\Model\Form
     * @throws \InvalidArgumentException
     * @throws \DomainException
     */
    public function getForm($id)
    {
        if (!preg_match('/^([a-z]+):([-_a-z0-9]+)$/i', $id, $matches)) {
            throw new InvalidArgumentException('Form id is not valid.');
        }

        $form = new Form;
        $form
            ->setType($matches[1])
            ->setId($this->tenantService->getContext().'-'.$matches[2]);

        switch ($form->getType()) {
            case Form::TYPE_FORMIO:
                $parameters = new FormParameters;
                $parameters->setPath($form->getId());
                $formio = $this->api->get('formio.form')->get(null, $parameters);
                $form
                    ->setDisplay($formio->getDisplay())
                    ->setSchema($formio->getComponents());

                break;

            case Form::TYPE_SYMFONY:
                break;

            default:
                throw new DomainException('Form type does not exist.');
        }

        return $form;
    }

    /**
     * Get form, including subforms
     *
     * @param string $id
     * @return array
     */
    public function getForms($id)
    {
        $forms = [];
        $form = $this->getForm($id);
        $form
            ->setMethod('POST')
            ->setPrimary(true);
        $forms[] = $form;

        switch ($form->getType()) {
            case Form::TYPE_FORMIO:
                $components = $form->getSchema();
                $resolverCollection = $this->resolverCollection;
                $extract = function(&$container, $key, &$component) use (&$extract, &$forms, $resolverCollection) {
                    switch (true) {
                        case property_exists($component, 'components'):
                            foreach ($component->components as $key => &$subComponent) {
                                $extract($component->components, $key, $subComponent);
                            }

                            break;

                        case property_exists($component, 'columns'):
                            foreach ($component->columns as &$column) {
                                foreach ($column->components as $key => &$subComponent) {
                                    $extract($column->components, $key, $subComponent);
                                }
                            }

                            break;

                        case property_exists($component, 'properties')
                            && is_object($component->properties)
                            && property_exists($component->properties, 'ds_form'):
                            $form = $this->getForm($component->properties->ds_form);
                            $data = [];

                            if (property_exists($component, 'defaultValue')) {
                                try {
                                    $data = $resolverCollection->resolve($component->defaultValue);
                                } catch (UnresolvedException $exception) {
                                    $data = [];
                                } catch (UnmatchedException $exception) {
                                    // Leave default value as-is
                                }
                            }

                            $form->setData($data);
                            $forms[] = $form;
                            unset($container[$key]);
                            break;
                    }
                };

                foreach ($components as $key => &$component) {
                    $extract($components, $key, $component);
                }

                $form->setSchema(array_values($components));

                break;

            case Form::TYPE_SYMFONY:
                break;

            default:
                throw new DomainException('Form type does not exist.');
        }

        return $forms;
    }

    /**
     * Resolve a form
     *
     * @param \Ds\Component\Form\Model\Form $form
     * @return \Ds\Component\Form\Model\Form
     */
    public function resolve(Form $form)
    {
        switch ($form->getType()) {
            case Form::TYPE_FORMIO:
                $components = $form->getSchema();
                $resolverCollection = $this->resolverCollection;
                $resolve = function(&$component) use (&$resolve, $resolverCollection) {
                    switch (true) {
                        case property_exists($component, 'components'):
                            foreach ($component->components as &$subComponent) {
                                $resolve($subComponent);
                            }

                            break;

                        case property_exists($component, 'columns'):
                            foreach ($component->columns as &$column) {
                                foreach ($column->components as &$subComponent) {
                                    $resolve($subComponent);
                                }
                            }

                            break;

                        case property_exists($component, 'defaultValue'):
                            if (null !== $component->defaultValue) {
                                try {
                                    $component->defaultValue = $resolverCollection->resolve($component->defaultValue);
                                } catch (UnresolvedException $exception) {
                                    $component->defaultValue = null;
                                } catch (UnmatchedException $exception) {
                                    // Leave default value as-is
                                }
                            }

                            break;
                    }
                };

                foreach ($components as &$component) {
                    $resolve($component);
                }

                $form->setSchema($components);

                break;

            case Form::TYPE_SYMFONY:
                break;

            default:
                throw new DomainException('Form type does not exist.');
        }

        return $form;
    }
}


<?php

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

use Ds\Component\Api\Model\Permission;
use OutOfRangeException;

/**
 * Trait Permissions
 *
 * @package Ds\Component\Api
 */
trait Permissions
{
    /**
     * Set permissions
     *
     * @param array $permissions
     * @return object
     */
    public function setPermissions(array $permissions = [])
    {
        $this->permissions = $permissions;

        return $this;
    }

    /**
     * Add permission
     *
     * @param $permission
     * @return $this
     */
    public function addPermission(Permission $permission)
    {
        $this->permissions[] = $permission;

        return $this;
    }

    /**
     * Get permissions
     *
     * @param string $property
     * @return array
     * @throws \OutOfRangeException
     */
    public function getPermissions($property = null)
    {
        if (null === $property) {
            return $this->permissions;
        }

        if (!array_key_exists($property, $this->permissions)) {
            throw new OutOfRangeException('Array property does not exist.');
        }

        return $this->permissions[$property];
    }
}


<?php

namespace Ds\Component\Acl\Collection;

use Doctrine\Common\Collections\ArrayCollection;
use Ds\Component\Acl\Model\Permission;
use InvalidArgumentException;

/**
 * Class PermissionCollection
 *
 * @package Ds\Component\Acl
 */
final class PermissionCollection extends ArrayCollection
{
    /**
     * {@inheritdoc}
     */
    public function __construct(array $permissions = [])
    {
        foreach ($permissions as $key => $permission) {
            $permissions[$key] = $this->cast($permission);
        }

        parent::__construct($permissions);
    }

    /**
     * {@inheritdoc}
     */
    public function removeElement($permission)
    {
        $permission = $this->cast($permission);

        return parent::removeElement($permission);
    }

    /**
     * {@inheritDoc}
     */
    public function contains($permission)
    {
        $permission = $this->cast($permission);

        return parent::contains($permission);
    }

    /**
     * {@inheritDoc}
     */
    public function indexOf($permission)
    {
        $permission = $this->cast($permission);

        return parent::indexOf($permission);
    }

    /**
     * {@inheritDoc}
     */
    public function set($key, $permission)
    {
        $permission = $this->cast($permission);

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

    /**
     * {@inheritDoc}
     */
    public function add($permission)
    {
        $permission = $this->cast($permission);

        return parent::add($permission);
    }

    /**
     * Get parent permission
     *
     * @param \Ds\Component\Acl\Model\Permission $permission
     * @return \Ds\Component\Acl\Model\Permission
     */
    public function getParent($permission) {
        $permission = $this->cast($permission);

        foreach ($this->toArray() as $element) {
            if (Permission::ENTITY === $element->getType() && 0 === strpos($permission->getValue(), $element->getValue())) {
                return $element;
            }
        }
    }

    /**
     * Cast element to permission object
     *
     * @param mixed $element
     * @return \Ds\Component\Acl\Model\Permission
     * @throws \InvalidArgumentException
     */
    protected function cast($element) {
        if ($element instanceof Permission) {
            return $element;
        }

        if (!is_array($element)) {
            throw new InvalidArgumentException('Element is not an array.');
        }

        foreach (['attributes', 'type', 'value', 'title'] as $key) {
            if (!array_key_exists($key, $element)) {
                throw new InvalidArgumentException('Element is missing key "'.$key.'".');
            }
        }

        $permission = new Permission($element['key'], $element['attributes'], $element['type'], $element['value'], $element['title']);

        return $permission;
    }
}


<?php

namespace Ds\Component\Identity\Doctrine\ORM\QueryExtension;

use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryCollectionExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Extension\QueryItemExtensionInterface;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use Doctrine\ORM\QueryBuilder;
use Ds\Component\Security\Model\Identity;
use Ds\Component\Model\Type\Deletable;
use Ds\Component\Security\Model\User;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

/**
 * Class DeletedExtension
 *
 * @package Ds\Component\Identity
 */
final class DeletedExtension implements QueryCollectionExtensionInterface, QueryItemExtensionInterface
{
    /**
     * @var \Symfony\Component\HttpFoundation\RequestStack
     */
    private $requestStack;

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

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

    /**
     * {@inheritdoc}
     */
    public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, string $operationName = null)
    {
        $this->apply($queryBuilder, $resourceClass);
    }

    /**
     * {@inheritdoc}
     */
    public function applyToItem(QueryBuilder $queryBuilder, QueryNameGeneratorInterface $queryNameGenerator, string $resourceClass, array $identifiers, string $operationName = null, array $context = [])
    {
        $this->apply($queryBuilder, $resourceClass);
    }

    /**
     * Apply condition
     *
     * @param \Doctrine\ORM\QueryBuilder $queryBuilder
     * @param string $resourceClass
     */
    protected function apply(QueryBuilder $queryBuilder, string $resourceClass)
    {
        if (!in_array(Deletable::class, class_implements($resourceClass), true)) {
            return;
        }

        $token = $this->tokenStorage->getToken();

        if ($token) {
            $user = $token->getUser();

            if ($user instanceof User) {
                if (in_array($user->getIdentity()->getType(), [Identity::SYSTEM, Identity::STAFF], true)) {
                    $request = $this->requestStack->getCurrentRequest();
                    $deleted = $request->query->get('deleted', 'false');
                    $rootAlias = $queryBuilder->getRootAliases()[0];

                    switch ($deleted) {
                        case 'true':
                            $queryBuilder->andWhere($rootAlias . '.deletedAt IS NOT NULL');
                            break;

                        case 'false':
                            $queryBuilder->andWhere($rootAlias . '.deletedAt IS NULL');
                            break;

                        case 'null':
                            break;
                    }

                    return;
                }
            }
        }

        $rootAlias = $queryBuilder->getRootAliases()[0];
        $queryBuilder->andWhere($rootAlias.'.deletedAt IS NULL');
    }
}


<?php

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

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

/**
 * Class PostLoadListener
 *
 * @package Ds\Component\Encryption
 */
final class PostLoadListener extends AbstractListener
{
    /**
     * Decrypt encryptable entity properties after retrieving them from storage.
     *
     * @param \Doctrine\ORM\Event\LifecycleEventArgs $args
     */
    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

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

        $entity->setEncrypted(true);
        $this->encryptionService->decrypt($entity);
    }
}


<?php

namespace Ds\Component\Health\Controller;

use Ds\Component\Health\Exception\InvalidAliasException;
use Ds\Component\Health\Service\HealthService;
use stdClass;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

use Symfony\Component\Routing\Annotation\Route;

/**
 * Class HealthController
 *
 * @package Ds\Component\Health
 */
final class HealthController
{
    /**
     * @const string
     */
    const TIMESTAMP_FORMAT = 'Y-m-d\TH:i:sP';

    /**
     * @var \Ds\Component\Health\Service\HealthService
     */
    private $healthService;

    /**
     * Constructor
     *
     * @param \Ds\Component\Health\Service\HealthService $healthService
     */
    public function __construct(HealthService $healthService)
    {
        $this->healthService = $healthService;
    }

    /**
     * Action
     *
     * @Route(path="/health", methods={"GET"})
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     */
    public function cget(): JsonResponse
    {
        $statuses = $this->healthService->check();
        $data = $statuses->toObject();
        $data->timestamp = $data->timestamp->format(static::TIMESTAMP_FORMAT);
        $data->statuses = new stdClass;

        foreach ($data->collection as $status) {
            $status->timestamp = $status->timestamp->format(static::TIMESTAMP_FORMAT);
            $alias = $status->alias;
            unset($status->alias);
            $data->statuses->{$alias} = $status;
        }

        unset($data->collection);

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

    /**
     * Action
     *
     * @Route(path="/health/{alias}", requirements={"alias"=".+"}, methods={"GET"})
     * @param string $alias
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     */
    public function get($alias): JsonResponse
    {
        $alias = str_replace('/', '.', $alias);

        try {
            $status = $this->healthService->check($alias);
        } catch (InvalidAliasException $exception) {
            throw new NotFoundHttpException('Health alias not found.', $exception);
        }

        $data = $status->toObject();
        $data->timestamp = $data->timestamp->format(static::TIMESTAMP_FORMAT);
        unset($data->alias);

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


<?php

namespace Ds\Component\Api\Query\Attribute;

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

    /**
     * Set anonymous uuid
     *
     * @param string $anonymousUuid
     * @return object
     */
    public function setAnonymousUuid(?string $anonymousUuid)
    {
        $this->anonymousUuid = $anonymousUuid;
        $this->_anonymousUuid = true;

        return $this;
    }

    /**
     * Get anonymous uuid
     *
     * @return string
     */
    public function getAnonymousUuid(): ?string
    {
        return $this->anonymousUuid;
    }

    # endregion

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


<?php

namespace Ds\Component\Model\Attribute\Accessor;

use InvalidArgumentException;

/**
 * Trait IdentityUuid
 *
 * @package Ds\Component\Model
 */
trait IdentityUuid
{
    /**
     * Set identity uuid
     *
     * @param string $identityUuid
     * @return object
     * @throws \InvalidArgumentException
     */
    public function setIdentityUuid(?string $identityUuid)
    {
        if (null !== $identityUuid) {
            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', $identityUuid)) {
                throw new InvalidArgumentException('Identity uuid is not valid.');
            }
        }

        $this->identityUuid = $identityUuid;

        return $this;
    }

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


<?php

namespace CommerceGuys\Zone\Model;

use CommerceGuys\Addressing\AddressInterface;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;

/**
 * Default zone implementation.
 *
 * Can be mapped and used by Doctrine.
 */
class Zone implements ZoneEntityInterface
{
    /**
     * Zone id.
     *
     * @var string
     */
    protected $id;

    /**
     * Zone name.
     *
     * @var string
     */
    protected $name;

    /**
     * Zone scope.
     *
     * @var string
     */
    protected $scope;

    /**
     * Zone priority.
     *
     * @var int
     */
    protected $priority;

    /**
     * Zone members.
     *
     * @var ZoneMemberEntityInterface[]
     */
    protected $members;

    /**
     * Creates a Zone instance.
     */
    public function __construct()
    {
        $this->members = new ArrayCollection();
    }

    /**
     * Returns the string representation of the zone.
     *
     * @return string
     */
    public function __toString()
    {
        return $this->name;
    }

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

    /**
     * {@inheritdoc}
     */
    public function setId($id)
    {
        $this->id = $id;

        return $this;
    }

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

    /**
     * {@inheritdoc}
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

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

    /**
     * {@inheritdoc}
     */
    public function setScope($scope)
    {
        $this->scope = $scope;

        return $this;
    }

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

    /**
     * {@inheritdoc}
     */
    public function setPriority($priority)
    {
        $this->priority = $priority;

        return $this;
    }

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

    /**
     * {@inheritdoc}
     */
    public function setMembers(Collection $members)
    {
        $this->members = $members;

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function hasMembers()
    {
        return !$this->members->isEmpty();
    }

    /**
     * {@inheritdoc}
     */
    public function addMember(ZoneMemberEntityInterface $member)
    {
        if (!$this->hasMember($member)) {
            $member->setParentZone($this);
            $this->members->add($member);
        }

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function removeMember(ZoneMemberEntityInterface $member)
    {
        if ($this->hasMember($member)) {
            $member->setParentZone(null);
            $this->members->removeElement($member);
        }

        return $this;
    }

    /**
     * {@inheritdoc}
     */
    public function hasMember(ZoneMemberEntityInterface $member)
    {
        return $this->members->contains($member);
    }

    /**
     * {@inheritdoc}
     */
    public function match(AddressInterface $address)
    {
        foreach ($this->members as $member) {
            if ($member->match($address)) {
                return true;
            }
        }

        return false;
    }
}


<?php

namespace Ds\Component\Statistic\Controller;

use Ds\Component\Statistic\Exception\InvalidAliasException;
use Ds\Component\Statistic\Service\StatisticService;
use stdClass;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

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

/**
 * Class StatisticController
 *
 * @package Ds\Component\Statistic
 */
class StatisticController
{
    /**
     * @const string
     */
    const TIMESTAMP_FORMAT = 'Y-m-d\TH:i:sP';

    /**
     * @var \Ds\Component\Statistic\Service\StatisticService
     */
    private $statisticService;

    /**
     * Constructor
     *
     * @param \Ds\Component\Statistic\Service\StatisticService $statisticService
     */
    public function __construct(StatisticService $statisticService)
    {
        $this->statisticService = $statisticService;
    }

    /**
     * Action
     *
     * @Route(path="/statistics", methods={"GET"})
     * @Security("is_granted('BROWSE', 'statistic')")
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     */
    public function cget()
    {
        $data = $this->statisticService->getAll();
        $data = $data->toObject();
        $data->timestamp = $data->timestamp->format(static::TIMESTAMP_FORMAT);
        $data->statistics = new stdClass;

        foreach ($data->collection as $datum) {
            $datum->timestamp = $datum->timestamp->format(static::TIMESTAMP_FORMAT);
            $alias = $datum->alias;
            unset($datum->alias);
            $data->statistics->{$alias} = $datum;
        }

        unset($data->collection);

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

    /**
     * Action
     *
     * @Route(path="/statistics/{alias}", requirements={"alias"=".+"}, methods={"GET"})
     * @Security("is_granted('READ', 'statistic')")
     * @param string $alias
     * @return \Symfony\Component\HttpFoundation\JsonResponse
     */
    public function get($alias)
    {
        $alias = str_replace('/', '.', $alias);

        try {
            $datum = $this->statisticService->get($alias);
        } catch (InvalidAliasException $exception) {
            throw new NotFoundHttpException('Statistic alias not found.', $exception);
        }

        $data = $datum->toObject();
        $data->timestamp = $data->timestamp->format(static::TIMESTAMP_FORMAT);
        unset($data->alias);

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


<?php

namespace Ds\Component\Camunda\Fixture\Camunda;

use Doctrine\Common\Persistence\ObjectManager;
use Ds\Component\Api\Api\Api;
use Ds\Component\Camunda\Model\Deployment as DeploymentModel;
use Ds\Component\Camunda\Query\DeploymentParameters;
use Ds\Component\Database\Fixture\Yaml;

/**
 * Trait Access
 *
 * @package Ds\Component\Camunda
 */
trait Deployment
{
    use Yaml;

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

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

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

    /**
     * {@inheritdoc}
     */
    public function load(ObjectManager $manager)
    {
        $fixtures = array_key_exists('FIXTURES', $_ENV) ? $_ENV['FIXTURES'] : 'dev';
        $source = $this->namespace.'.'.$this->app.'.fixtures.'.$fixtures;
        $api = $this->container->get(Api::class)->get('workflow.deployment');
        $parameters = new DeploymentParameters;
        $parameters->setSource($source);
        $deployments = $api->getList($parameters);

        foreach ($deployments as $deployment) {
            $parameters = new DeploymentParameters;
            $parameters->setCascade(true);
            $api->delete($deployment->getId(), $parameters);
        }

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

        foreach ($objects as $object) {
            $deployment = new DeploymentModel;
            $deployment
                ->setName($object->name)
                ->setSource($source)
                ->setTenantId($object->tenant_id);
            $files = [];

            foreach ($object->files as $file) {
                $files[] = dirname(str_replace('{fixtures}', $fixtures, $this->path)).'/'.$file;
            }

            $deployment->setFiles($files);
            $api->create($deployment);
        }
    }
}


<?php

namespace Ds\Component\Audit\Service;

use Doctrine\Common\Annotations\Reader;
use Doctrine\ORM\EntityManagerInterface;
use Ds\Component\Audit\Entity\Audit;
use Ds\Component\Audit\Model\Annotation\Audit as AuditAnnotation;
use Ds\Component\Audit\Model\Type\Auditable;
use Ds\Component\Entity\Service\EntityService;
use ReflectionObject;

/**
 * Class AuditService
 *
 * @package Ds\Component\Audit
 */
final class AuditService extends EntityService
{
    /**
     * @var \Doctrine\Common\Annotations\Reader
     */
    private $annotationReader;

    /**
     * Constructor
     *
     * @param \Doctrine\ORM\EntityManagerInterface $manager
     * @param \Doctrine\Common\Annotations\Reader $annotationReader
     * @param string $entity
     */
    public function __construct(EntityManagerInterface $manager, Reader $annotationReader, $entity = Audit::class)
    {
        parent::__construct($manager, $entity);

        $this->annotationReader = $annotationReader;
    }

    /**
     * Get properties with Audit annotation
     *
     * @param \Ds\Component\Audit\Model\Type\Auditable $entity
     * @return array
     */
    public function getProperties(Auditable $entity)
    {
        $reflection = new ReflectionObject($entity);
        $properties = [];

        foreach ($reflection->getProperties() as $key => $property) {
            if (!$this->annotationReader->getPropertyAnnotation($property, AuditAnnotation::class)) {
                continue;
            }

            $properties[] = $property->name;
        }

        return $properties;
    }
}