<?php

/*
 * This file is part of the Dektrium project.
 *
 * (c) Dektrium project <http://github.com/dektrium/>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace jarrus90\User\models;

use jarrus90\User\UserFinder;
use jarrus90\User\helpers\Password;
use jarrus90\User\Mailer;
use jarrus90\User\Module;
use jarrus90\User\traits\ModuleTrait;
use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\db\Query;
use yii\web\Application as WebApplication;
use yii\web\IdentityInterface;
use yii\helpers\ArrayHelper;

/**
 * User ActiveRecord model.
 *
 * @property bool    $isAdmin
 * @property bool    $isBlocked
 * @property bool    $isConfirmed
 *
 * Database fields:
 * @property integer $id
 * @property string  $username
 * @property string  $email
 * @property string  $unconfirmed_email
 * @property string  $password_hash
 * @property string  $auth_key
 * @property integer $registration_ip
 * @property integer $confirmed_at
 * @property integer $blocked_at
 * @property integer $created_at
 * @property integer $updated_at
 * @property integer $flags
 *
 * Defined relations:
 * @property Account[] $accounts
 * @property Profile   $profile
 *
 * Dependencies:
 * @property-read UserFinder $finder
 * @property-read Module $module
 * @property-read Mailer $mailer
 *
 * @author Dmitry Erofeev <dmeroff@gmail.com>
 */
class User extends ActiveRecord implements IdentityInterface {

    use ModuleTrait;

    const BEFORE_CREATE = 'beforeCreate';
    const AFTER_CREATE = 'afterCreate';
    const BEFORE_REGISTER = 'beforeRegister';
    const AFTER_REGISTER = 'afterRegister';
    // following constants are used on secured email changing process
    const OLD_EMAIL_CONFIRMED = 0b1;
    const NEW_EMAIL_CONFIRMED = 0b10;

    /** @var string Plain password. Used for model validation. */
    public $password;

    /** @var Profile|null */
    private $_profile;

    /** @var string Default username regexp */
    public static $usernameRegexp = '/^[-a-zA-Z0-9_\.@]+$/';

    /**
     * @return UserFinder
     * @throws \yii\base\InvalidConfigException
     */
    protected function getUserFinder() {
        return Yii::$container->get(UserFinder::className());
    }

    /**
     * @return Mailer
     * @throws \yii\base\InvalidConfigException
     */
    protected function getMailer() {
        return Yii::$container->get(Mailer::className());
    }

    /**
     * @return bool Whether the user is confirmed or not.
     */
    public function getIsConfirmed() {
        return $this->confirmed_at != null;
    }

    /**
     * @return bool Whether the user is blocked or not.
     */
    public function getIsBlocked() {
        return $this->blocked_at != null;
    }

    /**
     * @return bool Whether the user is an admin or not.
     */
    public function getIsAdmin() {
        return (\Yii::$app->getAuthManager() && $this->module->adminPermission ? \Yii::$app->user->can($this->module->adminPermission) : false) || in_array($this->username, $this->module->admins);
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getProfile() {
        return $this->hasOne(Profile::className(), ['user_id' => 'id']);
    }

    /**
     * @param Profile $profile
     */
    public function setProfile(Profile $profile) {
        $this->_profile = $profile;
    }

    /**
     * @return Account[] Connected accounts ($provider => $account)
     */
    public function getAccounts() {
        $connected = [];
        $accounts = $this->hasMany(Account::className(), ['user_id' => 'id'])->all();

        /** @var Account $account */
        foreach ($accounts as $account) {
            $connected[$account->provider] = $account;
        }

        return $connected;
    }

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

    /** @inheritdoc */
    public function getAuthKey() {
        return $this->getAttribute('auth_key');
    }

    /** @inheritdoc */
    public function attributeLabels() {
        return [
            'username' => Yii::t('user', 'Username'),
            'email' => Yii::t('user', 'Email'),
            'registration_ip' => Yii::t('user', 'Registration ip'),
            'unconfirmed_email' => Yii::t('user', 'New email'),
            'password' => Yii::t('user', 'Password'),
            'created_at' => Yii::t('user', 'Registration time'),
            'confirmed_at' => Yii::t('user', 'Confirmation time'),
        ];
    }

    /** @inheritdoc */
    public function behaviors() {
        return [
            TimestampBehavior::className(),
        ];
    }

    /** @inheritdoc */
    public function scenarios() {
        $scenarios = parent::scenarios();
        return ArrayHelper::merge($scenarios, [
                    'register' => ['username', 'email', 'password'],
                    'connect' => ['username', 'email'],
                    'create' => ['username', 'email', 'password'],
                    'update' => ['username', 'email', 'password'],
                    'settings' => ['username', 'email', 'password'],
                    'language' => ['lang'],
        ]);
    }

    /** @inheritdoc */
    public function rules() {
        return [
            // username rules
            'usernameRequired' => ['username', 'required', 'on' => ['register', 'create', 'connect', 'update']],
            'usernameMatch' => ['username', 'match', 'pattern' => static::$usernameRegexp],
            'usernameLength' => ['username', 'string', 'min' => 3, 'max' => 255],
            'usernameUnique' => ['username', 'unique', 'message' => Yii::t('user', 'This username has already been taken')],
            'usernameTrim' => ['username', 'trim'],
            // email rules
            'emailRequired' => ['email', 'required', 'on' => ['register', 'connect', 'create', 'update']],
            'emailPattern' => ['email', 'email'],
            'emailLength' => ['email', 'string', 'max' => 255],
            'emailUnique' => ['email', 'unique', 'message' => Yii::t('user', 'This email address has already been taken')],
            'emailTrim' => ['email', 'trim'],
            // password rules
            'passwordRequired' => ['password', 'required', 'on' => ['register']],
            'passwordLength' => ['password', 'string', 'min' => 6, 'on' => ['register', 'create']],

            'langExists' => ['lang', 'exist', 'targetClass' => \jarrus90\Multilang\Models\Language::className(), 'targetAttribute' => 'code']
        ];
    }

    /** @inheritdoc */
    public function validateAuthKey($authKey) {
        return $this->getAttribute('auth_key') === $authKey;
    }

    /**
     * Creates new user account. It generates password if it is not provided by user.
     *
     * @return bool
     */
    public function create($sendWelcome = true) {
        if ($this->getIsNewRecord() == false) {
            throw new \RuntimeException('Calling "' . __CLASS__ . '::' . __METHOD__ . '" on existing user');
        }

        $this->confirmed_at = time();
        $this->password = $this->password == null ? Password::generate(8) : $this->password;

        $this->trigger(self::BEFORE_CREATE);

        if (!$this->save()) {
            return false;
        }
        if($sendWelcome) {
            $this->mailer->sendWelcomeMessage($this, null, true);
        }
        $this->trigger(self::AFTER_CREATE);

        return true;
    }

    /**
     * This method is used to register new user account. If Module::enableConfirmation is set true, this method
     * will generate new confirmation token and use mailer to send it to the user.
     *
     * @return bool
     */
    public function register() {
        if ($this->getIsNewRecord() == false) {
            throw new \RuntimeException('Calling "' . __CLASS__ . '::' . __METHOD__ . '" on existing user');
        }

        $this->confirmed_at = $this->module->enableConfirmation ? null : time();
        $this->password = $this->module->enableGeneratingPassword ? Password::generate(8) : $this->password;

        $this->trigger(self::BEFORE_REGISTER);

        if (!$this->save()) {
            return false;
        }

        if ($this->module->enableConfirmation) {
            /** @var Token $token */
            $token = Yii::createObject(['class' => Token::className(), 'type' => Token::TYPE_CONFIRMATION]);
            $token->link('user', $this);
        }
        if ($this->module->enableUnconfirmedLogin) {
            Yii::$app->user->login($this);
        }

        $this->mailer->sendWelcomeMessage($this, isset($token) ? $token : null);
        $this->trigger(self::AFTER_REGISTER);

        return true;
    }

    /**
     * Attempts user confirmation.
     *
     * @param string $code Confirmation code.
     *
     * @return boolean
     */
    public function attemptConfirmation($code) {
        $token = $this->finder->findTokenByParams($this->id, $code, Token::TYPE_CONFIRMATION);

        if ($token instanceof Token && !$token->isExpired) {
            $token->delete();
            if (($success = $this->confirm())) {
                Yii::$app->user->login($this, $this->module->rememberFor);
                $message = Yii::t('user', 'Thank you, registration is now complete.');
            } else {
                $message = Yii::t('user', 'Something went wrong and your account has not been confirmed.');
            }
        } else {
            $success = false;
            $message = Yii::t('user', 'The confirmation link is invalid or expired. Please try requesting a new one.');
        }

        Yii::$app->session->setFlash($success ? 'success' : 'danger', $message);

        return $success;
    }

    /**
     * This method attempts changing user email. If user's "unconfirmed_email" field is empty is returns false, else if
     * somebody already has email that equals user's "unconfirmed_email" it returns false, otherwise returns true and
     * updates user's password.
     *
     * @param string $code
     *
     * @return bool
     * @throws \Exception
     */
    public function attemptEmailChange($code) {
        // TODO refactor method

        /** @var Token $token */
        $token = $this->finder->findToken([
                    'user_id' => $this->id,
                    'code' => $code,
                ])->andWhere(['in', 'type', [Token::TYPE_CONFIRM_NEW_EMAIL, Token::TYPE_CONFIRM_OLD_EMAIL]])->one();

        if (empty($this->unconfirmed_email) || $token === null || $token->isExpired) {
            Yii::$app->session->setFlash('danger', Yii::t('user', 'Your confirmation token is invalid or expired'));
        } else {
            $token->delete();

            if (empty($this->unconfirmed_email)) {
                Yii::$app->session->setFlash('danger', Yii::t('user', 'An error occurred processing your request'));
            } elseif ($this->finder->findUser(['email' => $this->unconfirmed_email])->exists() == false) {
                if ($this->module->emailChangeStrategy == Module::STRATEGY_SECURE) {
                    switch ($token->type) {
                        case Token::TYPE_CONFIRM_NEW_EMAIL:
                            $this->flags |= self::NEW_EMAIL_CONFIRMED;
                            Yii::$app->session->setFlash('success', Yii::t('user', 'Awesome, almost there. Now you need to click the confirmation link sent to your old email address'));
                            break;
                        case Token::TYPE_CONFIRM_OLD_EMAIL:
                            $this->flags |= self::OLD_EMAIL_CONFIRMED;
                            Yii::$app->session->setFlash('success', Yii::t('user', 'Awesome, almost there. Now you need to click the confirmation link sent to your new email address'));
                            break;
                    }
                }
                if ($this->module->emailChangeStrategy == Module::STRATEGY_DEFAULT || ($this->flags & self::NEW_EMAIL_CONFIRMED && $this->flags & self::OLD_EMAIL_CONFIRMED)) {
                    $this->email = $this->unconfirmed_email;
                    $this->unconfirmed_email = null;
                    Yii::$app->session->setFlash('success', Yii::t('user', 'Your email address has been changed'));
                }
                $this->save(false);
            }
        }
    }

    /**
     * Confirms the user by setting 'confirmed_at' field to current time.
     */
    public function confirm() {
        return (bool) $this->updateAttributes(['confirmed_at' => time()]);
    }

    /**
     * Resets password.
     *
     * @param string $password
     *
     * @return bool
     */
    public function resetPassword($password) {
        return (bool) $this->updateAttributes(['password_hash' => Password::hash($password)]);
    }

    /**
     * Blocks the user by setting 'blocked_at' field to current time and regenerates auth_key.
     */
    public function block() {
        return (bool) $this->updateAttributes([
                    'blocked_at' => time(),
                    'auth_key' => Yii::$app->security->generateRandomString(),
        ]);
    }

    /**
     * UnBlocks the user by setting 'blocked_at' field to null.
     */
    public function unblock() {
        return (bool) $this->updateAttributes(['blocked_at' => null]);
    }

    /**
     * Generates new username based on email address, or creates new username
     * like "user1".
     */
    public function generateUsername() {
        // try to use name part of email
        $this->username = explode('@', $this->email)[0];
        if ($this->validate(['username'])) {
            return $this->username;
        }

        // generate username like "user1", "user2", etc...
        while (!$this->validate(['username'])) {
            $row = (new Query())
                    ->from('{{%user}}')
                    ->select('MAX(id) as id')
                    ->one();

            $this->username = 'user' . ++$row['id'];
        }

        return $this->username;
    }

    /** @inheritdoc */
    public function beforeSave($insert) {
        if ($insert) {
            $this->setAttribute('auth_key', Yii::$app->security->generateRandomString());
            if (Yii::$app instanceof WebApplication) {
                $this->setAttribute('registration_ip', Yii::$app->request->userIP);
            }
        }
        if (!empty($this->password)) {
            $this->setAttribute('password_hash', Password::hash($this->password));
        }
        if (empty($this->lang)) {
            $this->setAttribute('lang', Yii::$app->language);
        }
        return parent::beforeSave($insert);
    }

    /** @inheritdoc */
    public function afterSave($insert, $changedAttributes) {
        parent::afterSave($insert, $changedAttributes);
        if ($insert) {
            if ($this->_profile == null) {
                $this->_profile = Yii::createObject(Profile::className());
            }
            $this->_profile->link('user', $this);
        }
        if($insert || empty($this->profile->public_email) || ($this->profile->public_email == $this->email)) {
            $this->profile->setAttribute('public_email', $this->email);
            $this->profile->save();
        }
    }

    /** @inheritdoc */
    public static function tableName() {
        return '{{%user}}';
    }

    /** @inheritdoc */
    public static function findIdentityByAccessToken($token, $type = null) {
        throw new NotSupportedException('Method "' . __CLASS__ . '::' . __METHOD__ . '" is not implemented.');
    }

    /** @inheritdoc */
    public static function findIdentity($id) {
        return static::findOne($id);
    }

}


<?php
namespace Zodream\Http;
/**
* socket
*
* @author Jason
*/

class Socket {
	protected $socket;

	protected $ip;

	protected $port;

    public function __construct($ip = null, $port = null) {
        if (!empty($ip) && !empty($port)) {
            $this->setIpAddress($ip, $port);
        }
    }

    /**
     * SET IP AND PORT
     * @param string $ip
     * @param int $port
     * @return $this
     */
    public function setIpAddress($ip, $port = 80) {
        if (false !== strpos($ip, ':')) {
            list($ip, $port) = explode(':', $ip);
        }
        if (empty($ip)) {
            $ip = '127.0.0.1';
        }
        $this->ip = $ip;
        $this->port = intval($port);
        return $this;
    }

    /**
	 * 创建
	 */
	public function create() {
		$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
        return $this;
	}

	/**
	 * 服务端
	 * @param int|number $backlog
	 */
	public function listen($backlog = 4) {
		socket_bind($this->socket, $this->ip, $this->port);
		socket_listen($this->socket, $backlog); // 4条等待
        return $this;
	}

	/**
	 * 客户端
	 */
	public function connect() {
		socket_connect($this->socket, $this->ip, $this->port);
        return $this;
	}

	/**
	 * 接受，需要循环接受 接受到信息后 read()
	 */
	public function accept() {
		socket_accept($this->socket);
        return $this;
	}

	/**
	 * 取出信息
	 * @param int|string $length
	 * @return string
	 */
	public function read($length = 8192) {
		$content = '';
		while ($buff = socket_read($this->socket, $length)) {
			$content .= $buff;
		}
		return $content;
	}

	/**
	 * 发送信息
	 * @param string $content
	 */
	public function write($content) {
	    socket_write($this->socket, $content);
        return $this;
	}

	/**
	 * 关闭
	 */
	public function close() {
		socket_close($this->socket);
        return $this;
	}

	/**
	 * 获取上一天错误信息
	 */
	public function getError() {
		return socket_strerror(socket_last_error($this->socket));
	}

}


<?php
namespace gossi\trixionary\client\action;

use keeko\framework\foundation\AbstractAction;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use gossi\trixionary\model\SportQuery;
use gossi\trixionary\domain\SportDomain;
use keeko\framework\domain\payload\Blank;
use gossi\trixionary\model\Sport;
use keeko\framework\domain\payload\NotValid;
use Symfony\Component\OptionsResolver\OptionsResolver;

/**
 * Edits a Sport
 *
 * This code is automatically created. Modifications will probably be overwritten.
 *
 * @author Thomas Gossmann
 */
class ManageEditAction extends AbstractAction {

	protected function configureParams(OptionsResolver $resolver) {
		$resolver->setRequired(['id']);
	}

	/**
	 * Automatically generated run method
	 *
	 * @param Request $request
	 * @return Response
	 */
	public function run(Request $request) {
		$id = $this->getParam('id');
		$sport = SportQuery::create()->findOneById($id);
		$data = ['sport' => $sport];
		$payload = new Blank($data);
		if ($request->isMethod('POST')) {
			$post = $request->request;

			$domain = new SportDomain($this->getServiceContainer());
			$serializer = Sport::getSerializer();

			$fields = $serializer->getFields();
			$attribs = [];

			foreach ($fields as $field) {
				if ($post->has($field)) {
					$attribs[$field] = $post->get($field);
				}
			}

			$attribs['feature_composition'] = $post->has('feature_composition');
			$attribs['feature_tester'] = $post->has('feature_tester');

			$payload = $domain->update($id, [
				'meta' => $post->get('meta', []),
				'attributes' => $attribs
			]);
			if ($payload instanceof NotValid) {
				$payload = new NotValid(array_merge($data, $payload->get()));
			}
		}

		return $this->responder->run($request, $payload);
	}
}


<?php

declare(strict_types=1);

namespace Maestroprog\Container;

use Psr\Container\ContainerInterface;

class Container implements IterableContainerInterface
{
    protected $servicesExtractor;

    /**
     * Маппинг идентификаторов сервисов на контейнеры.
     *
     * @var array serviceId => containerId
     */
    private $ids = [];
    /**
     * Маппинг типов сервисов на их идентификаторы.
     *
     * @var array returnType => serviceId[]
     */
    private $map = [];
    /**
     * Маппинг декорируемых сервисов на декораторы.
     *
     * @var array serviceId => decoratorId
     */
    private $decorators = [];
    /**
     * Свойства сервисов.
     *
     * @var Argument[] serviceId => properties
     */
    private $list = [];
    /**
     * Маппинг переопределяемых сервисов на переопределяющие.
     * Отладочная информация.
     *
     * @var array fromId => [fromContainerId, toId, toContainerId]
     */
    private $overridden = [];

    /**
     * @var ContainerInterface[]
     */
    protected $containers = [];

    /**
     * @var int[] priorities of containers
     */
    protected $priorities = [];

    /**
     * @var array of services instances
     */
    protected $instances = [];

    private $state = [];

    public function __construct()
    {
        $this->servicesExtractor = new ServicesExtractor();
    }

    /**
     * @inheritdoc
     */
    public function get($id)
    {
        $id = ucfirst($id);
        if (array_key_exists($id, $this->instances)) {
            // fast getter
            return $this->instances[$id];
        }
        $found = $this->has($id);
        if ($found) {
            if (!isset($this->ids[$id])) {
                if (count($this->map[$id]) > 1) {
                    $msg = 'An attempt to get an indefinite service. Please use the explicit service identifier.';
                    throw new ContainerException($msg);
                }
                $id = end($this->map[$id]);
            }
        } elseif (!class_exists($id)) {
            throw new NotFoundException('Not found "' . $id . '" in DI container.');
        } else {
            $instance = $id;
        }
        if (array_key_exists($id, $this->instances)) {
            // slow-fast getter
            return $this->instances[$id];
        }

        if (in_array($id, $this->state)) {
            throw new ContainerException(sprintf(
                'Recursive get detected: "%s > %s".',
                implode(' => ', $this->state),
                $id
            ));
        }

        try {
            $this->state[] = $id;

            if ($found) {
                if ($this->containers[$this->ids[$id]] instanceof IterableContainerInterface) {
                    $instance = $this->containers[$this->ids[$id]]->get($id);
                } else {
                    $method = $this->list[$id]->getMethodName();
                    $container = $this->containers[$this->ids[$id]];
                    if (method_exists($container, $method)) {
                        $instance = $this->instances[$id] = $container->{$method}();
                    } else {
                        throw new NotFoundException('Cannot find service "' . $id . '".');
                    }
                }
            } elseif (!isset($instance)) {
                throw new \LogicException('$instance must be set.');
            }

            if (is_string($instance) && class_exists($instance)) {
                $class = new \ReflectionClass($instance);
                $constructor = $class->getConstructor();
                $parameters = $constructor->getParameters();
                $arguments = [];
                foreach ($parameters as $parameter) {
                    if ($parameter->getClass()) {
                        $argType = $parameter->getClass()->getName();
                    } else {
                        $argType = $parameter->getType()->getName();
                    }
                    $arguments[] = $this->get($argType);
                }
                $instance = new $instance(...$arguments);
            }

            return $this->instances[$id] = $instance;
        } finally {
            if (end($this->state) === $id) {
                array_pop($this->state);
            }
        }
    }

    /**
     * @inheritdoc
     */
    public function has($id): bool
    {
        return array_key_exists($id, $this->ids) || array_key_exists($id, $this->map);
    }

    /**
     * @inheritdoc
     */
    public function list(): array
    {
        return $this->list;
    }

    /**
     * @param $name
     * @param $arguments
     *
     * @return mixed|string
     * @throws ContainerException
     */
    public function __call($name, $arguments)
    {
        if (substr($name, 0, 3) === 'get') {
            return $this->get(substr($name, 3));
        }
        throw new ContainerException('Unknown using magic method "' . $name . '".');
    }

    /**
     * Регистрирует новый контейнер.
     *
     * @param IterableContainerInterface|HasContainerLinkInterface|object $container
     *
     * @return void
     */
    public function register($container): void
    {
        static $id = 0;

        $this->containers[++$id] = $container;

        $priority = 0;
        if ($container instanceof HasPriorityInterface) {
            $priority = $container->priority();
        }
        $this->priorities[$id] = $priority;

        if ($container instanceof IterableContainerInterface) {
            $servicesList = $container->list();
        } else {
            try {
                $servicesList = $this->servicesExtractor->extractServicesId($container);
            } catch (\ReflectionException $e) {
                $servicesList = [];
            }
        }
        $this->loadServices($id, $servicesList);
        if ($container instanceof HasContainerLinkInterface) {
            $container->setContainer($this);
        }
    }

    public function addDependencies(array $dependencies): self
    {
        foreach ($dependencies as $dependency) {
            $this->addDependency($dependency);
        }

        return $this;
    }

    public function addDependency($dependency, string $alias = null): void
    {
        if (!is_object($dependency)) {
            throw new \InvalidArgumentException('Invalid dependency type.');
        }
        $this->instances[get_class($dependency)] = $dependency;
        if (null !== $alias) {
            $this->instances[$alias] = $dependency;
        }
    }

    /**
     * @param int $containerId
     * @param Argument[] $list
     *
     * @return void
     */
    protected function loadServices(int $containerId, array $list): void
    {
        foreach ($list as $serviceId => $argument) {
            $this->addService($containerId, $serviceId, $argument);
        }
    }

    /**
     * @param int $containerId
     * @param string $serviceId
     * @param Argument $argument
     *
     * @return void
     */
    protected function addService(int $containerId, string $serviceId, Argument $argument): void
    {
        if (substr($serviceId, -8) === 'Original') {
            throw new \InvalidArgumentException(sprintf(
                'Service id cannot ends with "Original" keyword in "%s".',
                $serviceId
            ));
        }

        if (array_key_exists($serviceId, $this->ids)) {
            // overriding

            $returnType = $argument->getReturnType();

            $otherReturnType = $this->list[$serviceId]->getReturnType();
            $isSubclass = is_a($otherReturnType, $returnType, true);

            if ($otherReturnType !== $returnType && !$isSubclass) {
                throw new \InvalidArgumentException(sprintf(
                    'Invalid override: Service "%s" with type "%s" override service with type "%s"',
                    $serviceId,
                    $returnType,
                    $otherReturnType
                ));
            }

            if ($argument->isDecorator() && $serviceId === $argument->getDecoratedService()) {
            } elseif ($this->list[$serviceId]->isDecorator()) {
            } elseif ($this->priorities[$this->ids[$serviceId]] === $this->priorities[$containerId]) {
                throw new \InvalidArgumentException('Equals priority in two services, please, fix it!');

            } elseif ($this->priorities[$this->ids[$serviceId]] > $this->priorities[$containerId]) {
                return;
            }
        }

        $this->append($argument, $serviceId, $containerId);
    }

    /**
     * @param Argument $argument
     * @param string $serviceId
     * @param int $containerId
     *
     * @return void
     */
    protected function append(Argument $argument, string $serviceId, int $containerId): void
    {
        $returnType = $argument->getReturnType();

        $overridden = false;
        if (isset($this->decorators[$serviceId])) {
            if ($this->list[$serviceId]->isDecorator() && $argument->isDecorator()) {
                throw new \InvalidArgumentException('Cannot add two or more decorators for one service.');
            }
            $decoratorId = $this->decorators[$serviceId];
            $this->overridden[$serviceId] = [$containerId, $decoratorId, $this->ids[$serviceId]];
            $serviceId .= 'Original';
            $overridden = true;
        }

        if ($argument->isDecorator()) {
            $decoratedService = $argument->getDecoratedService();
            if (isset($this->list[$decoratedService])) {
                $this->overridden[$decoratedService] = [$this->ids[$decoratedService], $serviceId, $containerId];
                $this->replace($decoratedService, $decoratedService . 'Original');
            }
            $this->decorators[$decoratedService] = $serviceId;
            $serviceId = $decoratedService;
        }

        $this->list[$serviceId] = $argument;
        $this->ids[$serviceId] = $containerId;
        if (!$overridden) {
            $this->map[$returnType][] = $serviceId;
        }
    }

    protected function replace($fromId, $toId): void
    {
        $this->list[$toId] = $this->list[$fromId];
        $this->ids[$toId] = $this->ids[$fromId];
        $returnType = $this->list[$toId]->getReturnType();
        $mapIndex = array_search($fromId, $this->map[$returnType], true);
        unset($this->map[$returnType][$mapIndex]);
        unset($this->ids[$fromId]);
        unset($this->list[$fromId]);
    }

    /**
     * @param Argument $argument
     * @param string $serviceId
     *
     * @return void
     */
    protected function remove(Argument $argument, string $serviceId): void
    {
        $returnType = $argument->getReturnType();

        unset($this->map[$returnType][array_search($serviceId, $this->map[$returnType], true)]);
        if (empty($this->map[$returnType])) {
            unset($this->map[$returnType]);
        }

        unset($this->list[$serviceId], $this->ids[$serviceId]);
    }
}


<?php namespace Ordercloud\Entities\Products;

use JsonSerializable;

class ProductExtraSet extends AbstractProductAddonSet implements JsonSerializable
{
    /**
     * @var array|ProductExtra[]
     * @reflectType Ordercloud\Entities\Products\ProductExtra
     */
    protected $extras;

    /**
     * @param int                  $id
     * @param string               $name
     * @param string               $displayName
     * @param string               $description
     * @param boolean              $enabled
     * @param array|ProductExtra[] $extras
     */
    public function __construct($id, $name, $displayName, $description, $enabled, array $extras)
    {
        parent::__construct($id, $name, $displayName, $description, $enabled);
        $this->extras = $extras;
    }

    /**
     * @return array|ProductExtra[]
     */
    public function getExtras()
    {
        return $this->extras;
    }

    public function getSortedExtras(ProductAddonComparator $comparator)
    {
        $extras = $this->getExtras();

        usort($extras, $comparator);

        return $extras;
    }

    /**
     * @param $extraID
     *
     * @return ProductExtra|null
     */
    public function getExtraByID($extraID)
    {
        foreach ($this->getExtras() as $extra) {
            if ($extra->getId() == $extraID) {
                return $extra;
            }
        }

        return null;
    }

    /**
     * Specify data which should be serialized to JSON
     */
    public function jsonSerialize()
    {
        $json = parent::jsonSerialize();

        $json['extras'] = $this->getExtras();

        return $json;
    }
}


<?php
namespace Gosyl\CommonBundle\Service;

use Gosyl\CommonBundle\Entity\ParamUsers;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Response;

class Mail {
	/**
	 * @var \Swift_Message
	 */
	private $_swiftInstance;

	/**
	 * @var \Swift_Mailer
	 */
	private $_mailer;

	/**
	 * @var Container
	 */
	private $_oContainer;

	/**
	 * @var string
	 */
	private $_contentType = 'text/html';

	/**
	 * @var string
	 */
	private $_charset = 'UTF-8';

	/**
	 *
	 * @param unknown $mailer
	 * @param UtilisateursController $ctrl
	 */

	public function __construct(\Swift_Mailer $mailer, Container $oContainer) {
		$this->_swiftInstance = \Swift_Message::newInstance();

		$this->_mailer = $mailer;

		$this->_oContainer = $oContainer;
	}

	/**
	 * Envoi d'un mail à chaque admin du site lors d'une inscripion
	 *
	 * @param string $sUsername
	 * @param string $sNom
	 * @param string $sPrenom
	 * @param string $sMail
	 * @param array $aListeAdmin
	 * @return void
	 */
	public function envoyerMailValiderNouvelUtilisateur($sUsername, $sNom, $sPrenom, $sMail, array $aListeAdmin) {
		$this->_swiftInstance->setSubject("Inscription d'un nouvel utilisateur");
		$addresses = array();
		foreach ($aListeAdmin as $aAdmin) {
			$this->_swiftInstance->addTo($aAdmin['email'], $aAdmin['username']);
			$addresses[] = $aAdmin['email'];
		}
		$this->_swiftInstance->addFrom($sMail, $sUsername)
			->setBody(
				$this->renderView(
					'GosylCommonBundle:Mail:newUserAlert.html.twig',
					array(
						'newUsername' => $sUsername,
						'newName' => $sNom,
						'newUserFirstname' => $sPrenom
					)
				),
				$this->_contentType,
				$this->_charset
			);

		$this->_swiftInstance->setReplyTo($addresses);

		$nbRecept = $this->_sendMail();
		if($nbRecept != count($aListeAdmin)) {
			return array('error' => true);
		} else {
			return array('error' => false);
		}
	}

	/**
	 * Envoi d'un mail d'information à un utilisateur - Compte activé
	 *
	 * @param ParamUsers $oInfoUser
	 * @param ParamUsers $oUserAdmin
	 */
	public function envoyerMailCompteValide(ParamUsers $oInfoUser, ParamUsers $oUserAdmin) {
		$this->_swiftInstance->setSubject("Validation de votre compte");

		$sUsername = $oInfoUser->getUsername();
		$sEmail = $oInfoUser->getEmail();

		$this->_swiftInstance->setFrom($oUserAdmin->getEmail(), $oUserAdmin->getUsername());

		$this->_swiftInstance->setTo($sEmail, $sUsername)
			 ->setBody(
			 	$this->renderView(
			 		'GosylCommonBundle:Mail:userIsValid.html.twig',
			 		array(
			 			'username' => $sUsername
			 		)
			 	),
			 	$this->_contentType,
			 	$this->_charset
			 );

		$this->_sendMail();
	}

	/**
	 * Envoi d'un mail d'information à un utilisateur - Compte desactivé
	 *
	 * @param ParamUsers $oInfoUser
	 * @param ParamUsers $oUserAdmin
	 */
	public function envoyerMailCompteInvalide(ParamUsers $oInfoUser, ParamUsers $oUserAdmin) {
		$this->_swiftInstance->setSubject("Désactivation de votre compte");

		$sUsername = $oInfoUser->getUsername();
		$sEmail = $oInfoUser->getEmail();

		$this->_swiftInstance->setFrom($oUserAdmin->getEmail(), $oUserAdmin->getUsername());

		$this->_swiftInstance->setTo($sEmail, $sUsername)
		->setBody(
				$this->renderView(
						'GosylCommonBundle:Mail:userIsInvalid.html.twig',
						array(
				 			'username' => $sUsername
						)
				 	),
				$this->_contentType,
				$this->_charset
				);

		$this->_sendMail();
	}

	/**
	 * Envoi d'un mail d'information à un utilisateur - Compte supprimé
	 *
	 * @param ParamUsers $oInfoUser
	 * @param ParamUsers $oUserAdmin
	 */
	public function envoyerMailCompteSupprime(ParamUsers $oInfoUser, ParamUsers $oUserAdmin) {
		$this->_swiftInstance->setSubject("Suppression de votre compte");

		$sUsername = $oInfoUser->getUsername();
		$sEmail = $oInfoUser->getEmail();

		$this->_swiftInstance->setFrom($oUserAdmin->getEmail(), $oUserAdmin->getUsername());

		$this->_swiftInstance->setTo($sEmail, $sUsername)
		->setBody(
				$this->renderView(
						'GosylCommonBundle:Mail:userIsDeleted.html.twig',
						array(
							'username' => $sUsername
						)
					),
				$this->_contentType,
				$this->_charset
				);

		$this->_sendMail();
	}

	/**
     * Returns a rendered view.
     *
     * @param string $view       The view name
     * @param array  $parameters An array of parameters to pass to the view
     *
     * @return string The rendered view
     */
    protected function renderView($view, array $parameters = array())
    {
        if ($this->_oContainer->has('templating')) {
            return $this->_oContainer->get('templating')->render($view, $parameters);
        }

        if (!$this->_oContainer->has('twig')) {
            throw new \LogicException('You can not use the "renderView" method if the Templating Component or the Twig Bundle are not available.');
        }

        return $this->_oContainer->get('twig')->render($view, $parameters);
    }

	/**
	 * Envoi du mail
	 *
	 * @param void
	 * @return int
	 */
	protected function _sendMail() {
		return $this->_mailer->send($this->_swiftInstance);
	}
}


<?php

namespace Orbt\StyleMirror\Css;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Orbt\ResourceMirror\Exception\MaterializeException;
use Orbt\ResourceMirror\ResourceMirror;
use Orbt\ResourceMirror\Event\ResourceMaterializeEvent;
use Orbt\ResourceMirror\Event\ResourceEvents;
use Orbt\ResourceMirror\Resource\MaterializedResource;

/**
 * A resource event listener that fetches all linked resources in CSS.
 */
class LinkedResourceFetcher implements EventSubscriberInterface
{
    /**
     * {@inheritdoc}
     */
    public static function getSubscribedEvents()
    {
        return array(
            ResourceEvents::MATERIALIZE => 'onResourceMaterialize',
        );
    }

    /**
     * @var ResourceScanner
     */
    protected $scanner;

    /**
     * @var ResourceMirror
     */
    protected $mirror;

    /**
     * Creates a linked fetcher.
     */
    public function __construct(ResourceScanner $scanner, ResourceMirror $mirror)
    {
        $this->scanner = $scanner;
        $this->mirror = $mirror;
    }

    /**
     * Scans all linked resources.
     */
    public function onResourceMaterialize(ResourceMaterializeEvent $e)
    {
        /** @var $resource MaterializedResource */
        $resource = $e->getResource();

        // Only scan resources with .css extension.
        if (preg_match('/\.css$/i', $resource->getPath())) {
            $this->scanner->scan($resource, $resource->getContent());
            $collection = $this->scanner->getQueue()->flush();
            // TODO Aggregate collection scans and materialize post hoc.
            // Materialize non-existing resources.
            foreach ($collection as $linkedResource) {
                if (!$this->mirror->exists($linkedResource)) {
                    try {
                        $this->mirror->materialize($linkedResource);
                    }
                    catch (MaterializeException $e) {}
                }
            }
        }
    }
}


<?php
/**
 * @section LICENSE
 * This file is part of MediaWiki simple i18n.
 *
 * MediaWiki simple i18n is free software: you can redistribute it
 * and/or modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * MediaWiki simple i18n is distributed in the hope that it will
 * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with MediaWiki simple i18n.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @file
 */

namespace Wikimedia\SimpleI18n;

use Psr\Log\LoggerInterface;

/**
 * Localizable message.
 *
 * This class can be used to look up a localized message based on a given key
 * and the active I18nContext language and convert it to a plain or escaped
 * string.
 *
 * @copyright © 2014 Wikimedia Foundation
 */
class Message {

	/**
	 * @var LoggerInterface $logger
	 */
	protected $logger;

	/**
	 * @var string $key
	 */
	protected $key;

	/**
	 * @var array $params
	 */
	protected $params;

	/**
	 * @var I18nContext $ctx
	 */
	protected $ctx;

	/**
	 * @var string $format
	 */
	protected $format = 'plain';

	/**
	 * @var string $message
	 */
	protected $message;

	/**
	 * @param string $key
	 * @param array $params
	 * @param I18nContext $ctx
	 * @param LoggerInterface $logger
	 */
	public function __construct(
		$key,
		array $params = array(),
		I18nContext $ctx,
		LoggerInterface $logger = null
	) {
		$this->logger = $logger ?: new \Psr\Log\NullLogger();
		$this->key = $key;
		$this->params = array_values( $params );
		$this->ctx = $ctx;
	}

	/**
	 * @return string
	 */
	public function getKey() {
		return $this->key;
	}

	/**
	 * @return array
	 */
	public function getParams() {
		return $this->params;
	}

	/**
	 * Add parameters to the paramter list of this message.
	 *
	 * @param mixed $params,... Parameters as strings or a single argument that
	 * is an array of strings.
	 *
	 * @return Message Self
	 */
	public function params( /*...*/ ) {
		$args = func_get_args();
		if ( isset( $args[0] ) && is_array( $args[0] ) ) {
			$args = $args[0];
		}
		$values = array_values( $args );
		$this->params = array_merge( $this->params, $values );
		return $this;
	}

	/**
	 * @return string
	 */
	public function getFormat() {
		return $this->format;
	}

	/**
	 * @return I18nContext
	 */
	public function getI18nContext() {
		return $this->ctx;
	}

	/**
	 * Get message contents from MessageCache.
	 * @return string|bool False if message doesn't exist, otherwise raw
	 * message text
	 */
	protected function fetchMessage() {
		if ( $this->message === null ) {
			$this->message = $this->ctx->getMessageCache()->get(
				$this->key,
				array(
					$this->ctx->getCurrentLanguage(),
					$this->ctx->getDefaultLanguage(),
			) );
		}
		return $this->message;
	}

	/**
	 * @return bool
	 */
	public function exists() {
		return $this->fetchMessage() !== false;
	}

	/**
	 * @return bool
	 */
	public function isBlank() {
		$msg = $this->fetchMessage();
		return $msg === false || $msg === '';
	}

	/**
	 * @return string
	 */
	public function toString() {
		$lang = $this->ctx->getCurrentLanguage();
		if ( $lang === 'qqx' ) {
			return "({$this->key})";
		}
		$text = $this->fetchMessage();
		if ( $text === false ) {
			$this->logger->warning(
				'No translation for key "{key}" in {lang}',
				array(
					'method' => __METHOD__,
					'key' => $this->key,
					'lang' => $lang,
			) );
			$text = "<{$this->key}>";
		}

		// Replace any $N parameters
		$replace = array();
		foreach( $this->params as $n => $p ) {
			$replace['$' . ( $n + 1 )] = $p;
		}
		$text = strtr( $text, $replace );

		// Escape if asked
		if ( $this->format === 'escaped' ) {
			$text = htmlspecialchars( $text, ENT_QUOTES, 'UTF-8', false );
		}

		return $text;
	}

	public function plain() {
		$this->format = 'plain';
		return $this->toString();
	}

	public function escaped() {
		$this->format = 'escaped';
		return $this->toString();
	}

	public function __toString() {
		try {
			return $this->toString();
		} catch ( Exception $ex ) {
			$this->logger->error(
				'Exception caught converting {{key}} to string',
				array(
					'key' => $this->key,
					'exception' => $ex,
			) );
			$text = "<{$this->key}>";
			if ( $this->format === 'escaped' ) {
				$text = htmlspecialchars( $text, ENT_QUOTES, 'UTF-8', false );
			}
			return $text;
		}
	}
}


<?php
/**
 * This file is a part of CSCFA project.
 *
 * PHP version 5.5
 *
 * @category Object
 * @package  CscfaCacheSystemBundle
 * @author   Matthieu VALLANCE <matthieu.vallance@cscfa.fr>
 * @license  http://opensource.org/licenses/MIT MIT
 * @filesource
 * @link     http://cscfa.fr
 */
namespace Cscfa\Bundle\CacheSystemBundle\Object\facade;

use Cscfa\Bundle\CacheSystemBundle\Object\Cache;
use Cscfa\Bundle\CacheSystemBundle\Object\provider\CacheProviderInterface;
use Cscfa\Bundle\CacheSystemBundle\Object\Element\CacheCollection;

/**
 * CacheManager
 *
 * The CacheManager manage
 * the cache system
 *
 * @category Object
 * @package  CscfaCacheSystemBundle
 * @author   Matthieu VALLANCE <matthieu.vallance@cscfa.fr>
 * @license  http://opensource.org/licenses/MIT MIT
 * @filesource
 * @link     http://cscfa.fr
 */
class CacheManager
{

    /**
     * Cache
     *
     * The cache object
     *
     * @var Cache
     */
    protected $cache;

    /**
     * Provider
     *
     * The cache provider
     *
     * @var CacheProviderInterface
     */
    protected $provider;

    /**
     * Get cache
     *
     * Return the cache
     *
     * @return Cache
     */
    public function getCache()
    {
        return $this->cache;
    }

    /**
     * Set cache
     *
     * Set the cache
     *
     * @param Cache $cache - the cache
     *
     * @return CacheManager
     */
    public function setCache(Cache $cache)
    {
        $this->cache = $cache;
        return $this;
    }

    /**
     * Process
     *
     * Return a cache element
     * or the result of the
     * closure if undefined
     * and register it into
     * the cache
     *
     * @param string   $index        - the cache index formatted as 'id@key'
     * @param \Closure $closure      - the closure
     * @param mixed    $arguments... - the closure arguments
     *
     * @return string
     * @throws \Exception - throw an exception if the result of the closure is not a string
     */
    public function process($index, \Closure $closure)
    {
        $closureArguments = func_get_args();
        $closureArguments = array_slice($closureArguments, 2);

        list ($id, $key) = explode("@", $index, 2);

        $cacheCollection = $this->getProvider()->get($id);
        if ($cacheCollection !== null) {
            if ($cacheCollection->has($key)) {
                return $cacheCollection->get($key)->getContent();
            } else {
                return $this->callClosure($closure, $closureArguments, $id, $key);
            }
        } else {
            return $this->callClosure($closure, $closureArguments, $id, $key);
        }
    }

    /**
     * Call closure
     *
     * Call the given closure
     * and register the result
     * in cache
     *
     * @param \Closure $closure          - the closure
     * @param array    $closureArguments - the closure arguments
     * @param string   $id               - the cache id
     * @param string   $key              - the cache key
     *
     * @return string - the result of the closure
     * @throws \Exception - throw an exception if the result of the closure is not a string
     */
    protected function callClosure(\Closure $closure, $closureArguments, $id, $key)
    {
        $result = call_user_func_array($closure, $closureArguments);

        $cacheCollection = $this->getProvider()->get($id);
        if ($cacheCollection === null) {
            $cacheCollection = new CacheCollection($id);
        }

        if ($cacheCollection->has($key)) {
            $cacheCollection->get($key)->setContent($result);
        } else {
            $cacheCollection->create($key, $result);
        }

        try{
            $this->getProvider()->save($cacheCollection);
        } catch (\Exception $e) {
            throw new \Exception(sprintf("The closure must return a string value to be stored into the cache. %s returned", gettype($result)), 500);
        }

        return $result;
    }

    /**
     * Get provider
     *
     * Return the provider
     *
     * @return CacheProviderInterface
     */
    protected function getProvider()
    {
        if ($this->provider !== null) {
            return $this->provider;
        } else {
            $this->provider = $this->cache->getProvider();
            return $this->provider;
        }
    }
}


<?php

declare(strict_types=1);

namespace Psi\Component\Description;

/**
 * Descriptive metadata for objects.
 */
class Description implements DescriptionInterface
{
    /**
     * @var array
     */
    private $descriptors = [];

    /**
     * @var array
     */
    private $priorities = [];

    /**
     * {@inheritdoc}
     */
    public function get($descriptorKey): DescriptorInterface
    {
        if (!isset($this->descriptors[$descriptorKey])) {
            throw new \InvalidArgumentException(sprintf(
                'Descriptor "%s" is not supported',
                $descriptorKey,
                implode('", "', array_keys($this->descriptors))
            ));
        }

        return $this->descriptors[$descriptorKey];
    }

    /**
     * {@inheritdoc}
     */
    public function has($descriptor): bool
    {
        return isset($this->descriptors[$descriptor]);
    }

    /**
     * {@inheritdoc}
     */
    public function all(): array
    {
        return $this->descriptors;
    }

    /**
     * {@inheritdoc}
     */
    public function set(string $key, DescriptorInterface $descriptor, int $priority = 0)
    {
        // do not overwrite descriptor if a lower priority is given.
        if (isset($this->priorities[$key])) {
            if ($priority < $this->priorities[$key]) {
                return;
            }
        }

        $this->descriptors[$key] = $descriptor;
        $this->priorities[$key] = $priority;
    }
}


<?php

/*
 * This file is part of the Valkyrja framework.
 *
 * (c) Melech Mizrachi
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Valkyrja\Crypt;

use Exception;
use Valkyrja\Application;
use Valkyrja\Crypt\Exceptions\CryptException;
use Valkyrja\Filesystem\Filesystem;
use Valkyrja\Support\Providers\Provides;

/**
 * Interface Crypt.
 */
class SodiumCrypt implements Crypt
{
    use Provides;

    /**
     * The filesystem.
     *
     * @var Filesystem
     */
    protected $filesystem;

    /**
     * SodiumCrypt constructor.
     *
     * @param Filesystem $filesystem
     */
    public function __construct(Filesystem $filesystem)
    {
        $this->filesystem = $filesystem;
    }

    /**
     * Get the key.
     *
     * @return string
     */
    public function getKey(): string
    {
        return $this->filesystem->read(config()['crypt']['keyPath'] ?? envPath('key'));
    }

    /**
     * Encrypt a message.
     *
     * @param string $message The message to encrypt
     * @param string $key     The encryption key
     *
     * @throws Exception Random Bytes Failure
     *
     * @return string
     */
    public function encrypt(string $message, string $key = null): string
    {
        $key = $key ?? $this->getKey();

        $nonce = random_bytes(
            SODIUM_CRYPTO_SECRETBOX_NONCEBYTES
        );

        $cipher = base64_encode(
            $nonce .
            sodium_crypto_secretbox(
                $message,
                $nonce,
                $key
            )
        );

        sodium_memzero($message);
        sodium_memzero($key);

        return $cipher;
    }

    /**
     * Decrypt a message.
     *
     * @param string $encrypted The encrypted message to decrypt
     * @param string $key       The encryption key
     *
     * @throws CryptException On any failure
     *
     * @return string
     */
    public function decrypt(string $encrypted, string $key = null): string
    {
        $key     = $key ?? $this->getKey();
        $decoded = base64_decode($encrypted, true);

        if ($decoded === false) {
            throw new CryptException('The encoding failed');
        }

        if (mb_strlen($decoded, '8bit') < (SODIUM_CRYPTO_SECRETBOX_NONCEBYTES + SODIUM_CRYPTO_SECRETBOX_MACBYTES)) {
            throw new CryptException('The message was truncated');
        }

        $nonce      = mb_substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, '8bit');
        $cipherText = mb_substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES, null, '8bit');

        $plain = sodium_crypto_secretbox_open(
            $cipherText,
            $nonce,
            $key
        );

        if ($plain === false) {
            throw new CryptException('The message was tampered with in transit');
        }

        sodium_memzero($cipherText);
        sodium_memzero($key);

        return $plain;
    }

    /**
     * Encrypt an array.
     *
     * @param array  $array The array to encrypt
     * @param string $key   The encryption key
     *
     * @throws Exception Random Bytes Failure
     *
     * @return string
     */
    public function encryptArray(array $array, string $key = null): string
    {
        return $this->encrypt(\json_encode($array), $key);
    }

    /**
     * Decrypt a message originally encrypted from an array.
     *
     * @param string $encrypted The encrypted message
     * @param string $key       The encryption key
     *
     * @throws CryptException On any failure
     *
     * @return array
     */
    public function decryptArray(string $encrypted, string $key = null): array
    {
        return \json_decode($this->decrypt($encrypted, $key), true);
    }

    /**
     * Encrypt a json array.
     *
     * @param object $object The object to encrypt
     * @param string $key    The encryption key
     *
     * @throws Exception Random Bytes Failure
     *
     * @return string
     */
    public function encryptObject(object $object, string $key = null): string
    {
        return $this->encrypt(\json_encode($object), $key);
    }

    /**
     * Decrypt a message originally encrypted from an object.
     *
     * @param string $encrypted The encrypted message
     * @param string $key       The encryption key
     *
     * @throws CryptException On any failure
     *
     * @return object
     */
    public function decryptObject(string $encrypted, string $key = null): object
    {
        return \json_decode($this->decrypt($encrypted, $key), true);
    }

    /**
     * The items provided by this provider.
     *
     * @return array
     */
    public static function provides(): array
    {
        return [
            Crypt::class,
        ];
    }

    /**
     * Publish the provider.
     *
     * @param Application $app The application
     *
     * @return void
     */
    public static function publish(Application $app): void
    {
        $app->container()->singleton(
            Crypt::class,
            new static($app->filesystem())
        );
    }
}


<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Cache
 * @subpackage Zend_Cache_Backend
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: Static.php 24989 2012-06-21 07:24:13Z mabe $
 */

/**
 * @see Zend_Cache_Backend_Interface
 */

/**
 * @see Zend_Cache_Backend
 */

/**
 * @package    Zend_Cache
 * @subpackage Zend_Cache_Backend
 * @copyright  Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */
class Zend_Cache_Backend_Static
    extends Zend_Cache_Backend
    implements Zend_Cache_Backend_Interface
{
    const INNER_CACHE_NAME = 'zend_cache_backend_static_tagcache';

    /**
     * Static backend options
     * @var array
     */
    protected $_options = array(
        'public_dir'            => null,
        'sub_dir'               => 'html',
        'file_extension'        => '.html',
        'index_filename'        => 'index',
        'file_locking'          => true,
        'cache_file_umask'      => 0600,
        'cache_directory_umask' => 0700,
        'debug_header'          => false,
        'tag_cache'             => null,
        'disable_caching'       => false
    );

    /**
     * Cache for handling tags
     * @var Zend_Cache_Core
     */
    protected $_tagCache = null;

    /**
     * Tagged items
     * @var array
     */
    protected $_tagged = null;

    /**
     * Interceptor child method to handle the case where an Inner
     * Cache object is being set since it's not supported by the
     * standard backend interface
     *
     * @param  string $name
     * @param  mixed $value
     * @return Zend_Cache_Backend_Static
     */
    public function setOption($name, $value)
    {
        if ($name == 'tag_cache') {
            $this->setInnerCache($value);
        } else {
            parent::setOption($name, $value);
        }
        return $this;
    }

    /**
     * Retrieve any option via interception of the parent's statically held
     * options including the local option for a tag cache.
     *
     * @param  string $name
     * @return mixed
     */
    public function getOption($name)
    {
        $name = strtolower($name);

        if ($name == 'tag_cache') {
            return $this->getInnerCache();
        }

        return parent::getOption($name);
    }

    /**
     * Test if a cache is available for the given id and (if yes) return it (false else)
     *
     * Note : return value is always "string" (unserialization is done by the core not by the backend)
     *
     * @param  string  $id                     Cache id
     * @param  boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested
     * @return string|false cached datas
     */
    public function load($id, $doNotTestCacheValidity = false)
    {
        if (($id = (string)$id) === '') {
            $id = $this->_detectId();
        } else {
            $id = $this->_decodeId($id);
        }
        if (!$this->_verifyPath($id)) {
            Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path');
        }
        if ($doNotTestCacheValidity) {
            $this->_log("Zend_Cache_Backend_Static::load() : \$doNotTestCacheValidity=true is unsupported by the Static backend");
        }

        $fileName = basename($id);
        if ($fileName === '') {
            $fileName = $this->_options['index_filename'];
        }
        $pathName = $this->_options['public_dir'] . dirname($id);
        $file     = rtrim($pathName, '/') . '/' . $fileName . $this->_options['file_extension'];
        if (file_exists($file)) {
            $content = file_get_contents($file);
            return $content;
        }

        return false;
    }

    /**
     * Test if a cache is available or not (for the given id)
     *
     * @param  string $id cache id
     * @return bool
     */
    public function test($id)
    {
        $id = $this->_decodeId($id);
        if (!$this->_verifyPath($id)) {
            Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path');
        }

        $fileName = basename($id);
        if ($fileName === '') {
            $fileName = $this->_options['index_filename'];
        }
        if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) {
            $this->_tagged = $tagged;
        } elseif (!$this->_tagged) {
            return false;
        }
        $pathName = $this->_options['public_dir'] . dirname($id);

        // Switch extension if needed
        if (isset($this->_tagged[$id])) {
            $extension = $this->_tagged[$id]['extension'];
        } else {
            $extension = $this->_options['file_extension'];
        }
        $file     = $pathName . '/' . $fileName . $extension;
        if (file_exists($file)) {
            return true;
        }
        return false;
    }

    /**
     * Save some string datas into a cache record
     *
     * Note : $data is always "string" (serialization is done by the
     * core not by the backend)
     *
     * @param  string $data            Datas to cache
     * @param  string $id              Cache id
     * @param  array $tags             Array of strings, the cache record will be tagged by each string entry
     * @param  int   $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime)
     * @return boolean true if no problem
     */
    public function save($data, $id, $tags = array(), $specificLifetime = false)
    {
        if ($this->_options['disable_caching']) {
            return true;
        }
        $extension = null;
        if ($this->_isSerialized($data)) {
            $data = unserialize($data);
            $extension = '.' . ltrim($data[1], '.');
            $data = $data[0];
        }

        clearstatcache();
        if (($id = (string)$id) === '') {
            $id = $this->_detectId();
        } else {
            $id = $this->_decodeId($id);
        }

        $fileName = basename($id);
        if ($fileName === '') {
            $fileName = $this->_options['index_filename'];
        }

        $pathName = realpath($this->_options['public_dir']) . dirname($id);
        $this->_createDirectoriesFor($pathName);

        if ($id === null || strlen($id) == 0) {
            $dataUnserialized = unserialize($data);
            $data = $dataUnserialized['data'];
        }
        $ext = $this->_options['file_extension'];
        if ($extension) $ext = $extension;
        $file = rtrim($pathName, '/') . '/' . $fileName . $ext;
        if ($this->_options['file_locking']) {
            $result = file_put_contents($file, $data, LOCK_EX);
        } else {
            $result = file_put_contents($file, $data);
        }
        @chmod($file, $this->_octdec($this->_options['cache_file_umask']));

        if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) {
            $this->_tagged = $tagged;
        } elseif ($this->_tagged === null) {
            $this->_tagged = array();
        }
        if (!isset($this->_tagged[$id])) {
            $this->_tagged[$id] = array();
        }
        if (!isset($this->_tagged[$id]['tags'])) {
            $this->_tagged[$id]['tags'] = array();
        }
        $this->_tagged[$id]['tags'] = array_unique(array_merge($this->_tagged[$id]['tags'], $tags));
        $this->_tagged[$id]['extension'] = $ext;
        $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME);
        return (bool) $result;
    }

    /**
     * Recursively create the directories needed to write the static file
     */
    protected function _createDirectoriesFor($path)
    {
        if (!is_dir($path)) {
            $oldUmask = umask(0);
            if ( !@mkdir($path, $this->_octdec($this->_options['cache_directory_umask']), true)) {
                $lastErr = error_get_last();
                umask($oldUmask);
                Zend_Cache::throwException("Can't create directory: {$lastErr['message']}");
            }
            umask($oldUmask);
        }
    }

    /**
     * Detect serialization of data (cannot predict since this is the only way
     * to obey the interface yet pass in another parameter).
     *
     * In future, ZF 2.0, check if we can just avoid the interface restraints.
     *
     * This format is the only valid one possible for the class, so it's simple
     * to just run a regular expression for the starting serialized format.
     */
    protected function _isSerialized($data)
    {
        return preg_match("/a:2:\{i:0;s:\d+:\"/", $data);
    }

    /**
     * Remove a cache record
     *
     * @param  string $id Cache id
     * @return boolean True if no problem
     */
    public function remove($id)
    {
        if (!$this->_verifyPath($id)) {
            Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path');
        }
        $fileName = basename($id);
        if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) {
            $this->_tagged = $tagged;
        } elseif (!$this->_tagged) {
            return false;
        }
        if (isset($this->_tagged[$id])) {
            $extension = $this->_tagged[$id]['extension'];
        } else {
            $extension = $this->_options['file_extension'];
        }
        if ($fileName === '') {
            $fileName = $this->_options['index_filename'];
        }
        $pathName = $this->_options['public_dir'] . dirname($id);
        $file     = realpath($pathName) . '/' . $fileName . $extension;
        if (!file_exists($file)) {
            return false;
        }
        return unlink($file);
    }

    /**
     * Remove a cache record recursively for the given directory matching a
     * REQUEST_URI based relative path (deletes the actual file matching this
     * in addition to the matching directory)
     *
     * @param  string $id Cache id
     * @return boolean True if no problem
     */
    public function removeRecursively($id)
    {
        if (!$this->_verifyPath($id)) {
            Zend_Cache::throwException('Invalid cache id: does not match expected public_dir path');
        }
        $fileName = basename($id);
        if ($fileName === '') {
            $fileName = $this->_options['index_filename'];
        }
        $pathName  = $this->_options['public_dir'] . dirname($id);
        $file      = $pathName . '/' . $fileName . $this->_options['file_extension'];
        $directory = $pathName . '/' . $fileName;
        if (file_exists($directory)) {
            if (!is_writable($directory)) {
                return false;
            }
            if (is_dir($directory)) {
                foreach (new DirectoryIterator($directory) as $file) {
                    if (true === $file->isFile()) {
                        if (false === unlink($file->getPathName())) {
                            return false;
                        }
                    }
                }
            }
            rmdir($directory);
        }
        if (file_exists($file)) {
            if (!is_writable($file)) {
                return false;
            }
            return unlink($file);
        }
        return true;
    }

    /**
     * Clean some cache records
     *
     * Available modes are :
     * Zend_Cache::CLEANING_MODE_ALL (default)    => remove all cache entries ($tags is not used)
     * Zend_Cache::CLEANING_MODE_OLD              => remove too old cache entries ($tags is not used)
     * Zend_Cache::CLEANING_MODE_MATCHING_TAG     => remove cache entries matching all given tags
     *                                               ($tags can be an array of strings or a single string)
     * Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG => remove cache entries not {matching one of the given tags}
     *                                               ($tags can be an array of strings or a single string)
     * Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG => remove cache entries matching any given tags
     *                                               ($tags can be an array of strings or a single string)
     *
     * @param  string $mode Clean mode
     * @param  array  $tags Array of tags
     * @return boolean true if no problem
     */
    public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())
    {
        $result = false;
        switch ($mode) {
            case Zend_Cache::CLEANING_MODE_MATCHING_TAG:
            case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:
                if (empty($tags)) {
                    throw new Zend_Exception('Cannot use tag matching modes as no tags were defined');
                }
                if ($this->_tagged === null && $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME)) {
                    $this->_tagged = $tagged;
                } elseif (!$this->_tagged) {
                    return true;
                }
                foreach ($tags as $tag) {
                    $urls = array_keys($this->_tagged);
                    foreach ($urls as $url) {
                        if (isset($this->_tagged[$url]['tags']) && in_array($tag, $this->_tagged[$url]['tags'])) {
                            $this->remove($url);
                            unset($this->_tagged[$url]);
                        }
                    }
                }
                $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME);
                $result = true;
                break;
            case Zend_Cache::CLEANING_MODE_ALL:
                if ($this->_tagged === null) {
                    $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME);
                    $this->_tagged = $tagged;
                }
                if ($this->_tagged === null || empty($this->_tagged)) {
                    return true;
                }
                $urls = array_keys($this->_tagged);
                foreach ($urls as $url) {
                    $this->remove($url);
                    unset($this->_tagged[$url]);
                }
                $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME);
                $result = true;
                break;
            case Zend_Cache::CLEANING_MODE_OLD:
                $this->_log("Zend_Cache_Backend_Static : Selected Cleaning Mode Currently Unsupported By This Backend");
                break;
            case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:
                if (empty($tags)) {
                    throw new Zend_Exception('Cannot use tag matching modes as no tags were defined');
                }
                if ($this->_tagged === null) {
                    $tagged = $this->getInnerCache()->load(self::INNER_CACHE_NAME);
                    $this->_tagged = $tagged;
                }
                if ($this->_tagged === null || empty($this->_tagged)) {
                    return true;
                }
                $urls = array_keys($this->_tagged);
                foreach ($urls as $url) {
                    $difference = array_diff($tags, $this->_tagged[$url]['tags']);
                    if (count($tags) == count($difference)) {
                        $this->remove($url);
                        unset($this->_tagged[$url]);
                    }
                }
                $this->getInnerCache()->save($this->_tagged, self::INNER_CACHE_NAME);
                $result = true;
                break;
            default:
                Zend_Cache::throwException('Invalid mode for clean() method');
                break;
        }
        return $result;
    }

    /**
     * Set an Inner Cache, used here primarily to store Tags associated
     * with caches created by this backend. Note: If Tags are lost, the cache
     * should be completely cleaned as the mapping of tags to caches will
     * have been irrevocably lost.
     *
     * @param  Zend_Cache_Core
     * @return void
     */
    public function setInnerCache(Zend_Cache_Core $cache)
    {
        $this->_tagCache = $cache;
        $this->_options['tag_cache'] = $cache;
    }

    /**
     * Get the Inner Cache if set
     *
     * @return Zend_Cache_Core
     */
    public function getInnerCache()
    {
        if ($this->_tagCache === null) {
            Zend_Cache::throwException('An Inner Cache has not been set; use setInnerCache()');
        }
        return $this->_tagCache;
    }

    /**
     * Verify path exists and is non-empty
     *
     * @param  string $path
     * @return bool
     */
    protected function _verifyPath($path)
    {
        $path = realpath($path);
        $base = realpath($this->_options['public_dir']);
        return strncmp($path, $base, strlen($base)) !== 0;
    }

    /**
     * Determine the page to save from the request
     *
     * @return string
     */
    protected function _detectId()
    {
        return $_SERVER['REQUEST_URI'];
    }

    /**
     * Validate a cache id or a tag (security, reliable filenames, reserved prefixes...)
     *
     * Throw an exception if a problem is found
     *
     * @param  string $string Cache id or tag
     * @throws Zend_Cache_Exception
     * @return void
     * @deprecated Not usable until perhaps ZF 2.0
     */
    protected static function _validateIdOrTag($string)
    {
        if (!is_string($string)) {
            Zend_Cache::throwException('Invalid id or tag : must be a string');
        }

        // Internal only checked in Frontend - not here!
        if (substr($string, 0, 9) == 'internal-') {
            return;
        }

        // Validation assumes no query string, fragments or scheme included - only the path
        if (!preg_match(
                '/^(?:\/(?:(?:%[[:xdigit:]]{2}|[A-Za-z0-9-_.!~*\'()\[\]:@&=+$,;])*)?)+$/',
                $string
            )
        ) {
            Zend_Cache::throwException("Invalid id or tag '$string' : must be a valid URL path");
        }
    }

    /**
     * Detect an octal string and return its octal value for file permission ops
     * otherwise return the non-string (assumed octal or decimal int already)
     *
     * @param string $val The potential octal in need of conversion
     * @return int
     */
    protected function _octdec($val)
    {
        if (is_string($val) && decoct(octdec($val)) == $val) {
            return octdec($val);
        }
        return $val;
    }

    /**
     * Decode a request URI from the provided ID
     *
     * @param string $id
     * @return string
     */
    protected function _decodeId($id)
    {
        return pack('H*', $id);
    }
}


<?php
/**
 * This file is part of the CarteBlanche PHP framework.
 *
 * (c) Pierre Cassat <me@e-piwi.fr> and contributors
 *
 * License Apache-2.0 <http://github.com/php-carteblanche/carteblanche/blob/master/LICENSE>
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Lib\Manifest;

use \ArrayAccess;
use \Lib\Manifest\ManifestArrayAccess;
use \Lib\Manifest\Package;

abstract class AbstractPackageDependent extends ManifestArrayAccess implements ArrayAccess
{

    /**
     * The class default settings
     */
    public static $defaults = array();

    /**
     * The manifest file object received by the contsructor
     */
    protected $package;

    /**
     * Constructor receiving a manifest file entity
     */
    public function __construct(Package $package)
    {
        $this->package = $package;
        $this->init()->parse();
    }

    /**
     * Initialize the object with default values and first settings
     *
     * @return self `$this` for method chaining
     */
    protected function init()
    {
        $clsname = get_called_class();
        if (property_exists($clsname, 'defaults')) {
            foreach($clsname::$defaults as $name=>$value) {
                $this->{$name} = $value;
            }
        }
        return $this;
    }

    /**
     * Parse the values with the confguration file data
     */
    abstract public function parse();

}

// Endfile


<?php

/**
 * Jin Framework
 * Diatem
 */

namespace Jin2\Form\Components;

use Jin2\Assets\AssetsInterface;
use Jin2\Language\Translation;

/**
 * Classe parent de tout composant de type FORM (destinés à être utilisés avec des balises FORM)
 */
abstract class AbstractComponent implements AssetsInterface
{

  /**
   * @var string  Nom du composant
   */
  protected $name;

  /**
   * @var string  Id du composant
   */
  protected $id = '';

  /**
   * @var string Personnalisation de la balise style
   */
  protected $style = '';

  /**
   * @var array Classes appliquées
   */
  protected $classes = array();

  /**
   * @var array Attributs ajoutés
   */
  protected $attributes = array();

  /**
   * @var string Texte d'erreur affiché
   */
  protected $error = '';

  /**
   * @var string classe d'erreur affiché
   */
  protected $errorclass = 'error';

  /**
   * @var string|array  Valeur actuelle.
   */
  protected $value = null;

  /**
   * @var string|array  Placeholder
   */
  protected $placeholder = null;

  /**
   * @var string  Label affiché
   */
  protected $label = '';

  /**
   * Constructeur
   *
   * @param string $name  Label du composant
   */
  public function __construct($name)
  {
    $this->name = $name;
    $this->label = $name;
    $root =  __DIR__
      . DIRECTORY_SEPARATOR .'..'
      . DIRECTORY_SEPARATOR .'..'
      . DIRECTORY_SEPARATOR .'..'
      . DIRECTORY_SEPARATOR .'languages';
    Translation::addStorage($root, 0);
    Translation::loadFile('formcomponents');
  }

  /**
   * Retourne le type de composant
   *
   * @return string
   */
  abstract public static function getType();

  /**
   * Implements getAssetUrl function
   *
   * @param string $key
   * @return string
   */
  public static function getAssetUrl($key)
  {
    $root =  __DIR__
      . DIRECTORY_SEPARATOR .'..'
      . DIRECTORY_SEPARATOR .'..'
      . DIRECTORY_SEPARATOR .'..'
      . DIRECTORY_SEPARATOR .'assets'
      . DIRECTORY_SEPARATOR .static::getType();
    return sprintf('%s%s%s.tpl', $root, DIRECTORY_SEPARATOR, $key);
  }

  /**
   * Implements getAssetContent function
   *
   * @param string $key
   * @return string
   */
  public static function getAssetContent($key)
  {
    if ($url = static::getAssetUrl($key)) {
      return file_get_contents($url, FILE_USE_INCLUDE_PATH);
    }
    return null;
  }

  /**
   * Retourne le nom du composant
   *
   * @return string
   */
  public function getName()
  {
    return $this->name;
  }

  /**
   * Retourne l'identifiant
   *
   * @return string
   */
  public function getId()
  {
    return $this->id;
  }

  /**
   * Modifie l'identifiant
   *
   * @param string $id
   */
  public function setId($id)
  {
    $this->id = $id;
  }

  /**
   * Définit ce qui sera affiché dans la balise style du composant
   *
   * @param string $style Déclaration CSS
   */
  public function setStyle($style)
  {
    $this->style = $style;
  }

  /**
   * Retourne ce qui est affiché dans la balise style du composant
   */
  public function getStyle()
  {
    return $this->style;
  }

  /**
   * Applique une nouvelle classe CSS
   *
   * @param  string $className Nom de la classe à appliquer
   * @return boolean  Retourne FALSE si cette classe était déjà appliquée
   */
  public function addClass($className)
  {
    if (!is_numeric(array_search($className, $this->classes))) {
      $this->classes[] = $className;
      return true;
    }
    return false;
  }

  /**
   * Supprime une classe CSS appliquée
   *
   * @param  string $className Nom de la classe à supprimer
   * @return boolean  Retourne FALSE si cette classe n'était pas appliquée
   */
  public function removeClass($className)
  {
    $pos = array_search($className, $this->classes);
    if (is_numeric($pos)) {
      unset($this->classes[$pos]);
      return true;
    }
    return false;
  }

  /**
   * Retourne un tableau des classes CSS appliquées
   *
   * @return array
   */
  public function getClasses()
  {
    return $this->classes;
  }

  /**
   * Ajoute un nouvel attribut
   *
   * @param  string $attributeName  Nom de l'attribut
   * @param  string $attributeValue Value de l'attribut
   * @return boolean               Retourne FALSE si cet atribut était déjà ajouté
   */
  public function addAttribute($attributeName, $attributeValue)
  {
    if (!array_key_exists($attributeName, $this->attributes)) {
      $this->attributes[$attributeName] = $attributeValue;
      return true;
    }
    return false;
  }

  /**
   * Supprime un attribut ajouté
   *
   * @param  string $attributeName Nom de l'attribut
   * @return boolean              Retourne FALSE si cet attribut n'était pas ajouté
   */
  public function removeAttribute($attributeName)
  {
    if (isset($this->attributes[$attributeName])) {
      unset($this->attributes[$attributeName]);
      return true;
    }
    return false;
  }

  /**
   * Retourne un tableau des attributs ajoutés
   * @return array
   */
  public function getAttributes(){
      return $this->attributes;
  }

  /**
   * Définit l'erreur affichée
   *
   * @param string $error   Texte de l'erreur
   */
  public function setError($error)
  {
    $this->error = $error;
  }

  /**
   * Définit l'erreur affichée
   *
   * @param string $errorclass class de l'erreur
   */
  public function setErrorClass($errorclass)
  {
    $this->errorclass = $errorclass;
  }

  /**
   * Retourne l'erreur affichée
   *
   * @return string
   */
  public function getError()
  {
    return $this->error;
  }

  /**
   * Retourne la classe d'erreur  affichée
   *
   * @return string
   */
  public function getErrorClass()
  {
    return $this->errorclass;
  }

  /**
   * Définit la valeur actuelle
   *
   * @param string $value Valeur actuelle
   */
  public function setValue($value)
  {
    $this->value = $value;
  }

  /**
   * Retourne la valeur actuelle
   *
   * @return string
   */
  public function getValue()
  {
    return $this->value;
  }

  /**
   * Définit la valeur par défaut
   *
   * @param string $value Valeur actuelle
   */
  public function setPlaceholder($value)
  {
    $this->placeholder = $value;
  }

  /**
   * Retourne la valeur  par défaut
   *
   * @return string
   */
  public function getPlaceholder()
  {
    return $this->placeholder;
  }

  /**
   * Définit la valeur du label
   *
   * @param string $label Valeur du label
   */
  public function setLabel($label)
  {
    $this->label = $label;
  }

  /**
   * Retourne la valeur du label
   *
   * @return string
   */
  public function getLabel()
  {
    return $this->label;
  }

  /**
   * Rendu par défaut d'un composant
   *
   * @return  string
   */
  public function render()
  {
    return $this->replaceMagicFields(static::getAssetContent('html'));
  }

  /**
   * Remplace les champs magiques des assets - concernant uniquement les champs magiques des composants de type FORM
   * @param  string $html  HTML à inspeter
   * @return string
   */
  public function replaceMagicFields($html)
  {
    $html = str_replace('%id%', $this->getId(), $html);
    $html = str_replace('%class%', implode(' ', $this->classes), $html);
    $html = str_replace('%style%', $this->getStyle(), $html);
    $html = str_replace('%name%', $this->getName(), $html);
    $html = str_replace('%label%', $this->getLabel(), $html);

    $strAttributes = '';
    foreach ($this->attributes as $key => $value) {
      $strAttributes .= ' ' . $key . '="' . $value . '"';
    }
    $html = str_replace('%attributes%', $strAttributes, $html);
    if (!is_array($this->getValue())) {
      $html = str_replace('%value%', $this->getValue(), $html);
    }

    if (!is_array($this->getPlaceholder())) {
      $html = str_replace('%placeholder%', $this->getPlaceholder(), $html);
    }

    $html = str_replace('%error%', $this->getError(), $html);
    return $html;
  }

}


<?php

declare(strict_types=1);

namespace Psi\Bridge\ObjectAgent\Doctrine\Orm;

use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query\Expr;
use Doctrine\ORM\QueryBuilder;
use Psi\Component\ObjectAgent\Query\Comparison;
use Psi\Component\ObjectAgent\Query\Composite;
use Psi\Component\ObjectAgent\Query\Expression;
use Psi\Component\ObjectAgent\Query\Join;
use Psi\Component\ObjectAgent\Query\Query;

class PsiToOrmQueryBuilderConverter
{
    const FROM_ALIAS = 'a';

    private $paramIndex = 0;
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }

    /**
     * Convert the given Psi Query into a Doctrine ORM QueryBuilder instance.
     */
    public function convert(Query $query): QueryBuilder
    {
        $queryBuilder = $this->entityManager
            ->getRepository($query->getClassFqn())
            ->createQueryBuilder(self::FROM_ALIAS);

        $this->buildSelects($queryBuilder, $query);
        $this->buildJoins($queryBuilder, $query);

        if ($query->hasExpression()) {
            $this->buildWhere($queryBuilder, $query);
        }

        $this->buildOrderings($queryBuilder, $query);
        $this->buildLimit($queryBuilder, $query);

        return $queryBuilder;
    }

    private function buildSelects(QueryBuilder $queryBuilder, Query $query)
    {
        $selects = [];
        foreach ($query->getSelects() as $selectName => $selectAlias) {
            $select = $selectName . ' ' . $selectAlias;

            // if the "index" is numeric, then assume that the value is the
            // name and that no alias is being used.
            if (is_int($selectName)) {
                $select = $selectAlias;
            }

            $selects[] = $select;
        }

        if (empty($selects)) {
            return;
        }

        $queryBuilder->select($selects);
    }

    private function buildJoins(QueryBuilder $queryBuilder, Query $query)
    {
        foreach ($query->getJoins() as $join) {
            switch ($join->getType()) {
                case Join::INNER_JOIN:
                    $queryBuilder->innerJoin($join->getJoin(), $join->getAlias());
                    continue 2;
                case Join::LEFT_JOIN:
                    $queryBuilder->leftJoin($join->getJoin(), $join->getAlias());
                    continue 2;
            }

            throw new \InvalidArgumentException(sprintf(
                'Do not know what to do with join of type "%s"', $join->getType()
            ));
        }
    }

    private function buildWhere(QueryBuilder $queryBuilder, Query $query)
    {
        $expr = $this->walkExpression($queryBuilder, $query->getExpression());
        $queryBuilder->where($expr);
    }

    private function buildOrderings(QUeryBuilder $queryBuilder, Query $query)
    {
        foreach ($query->getOrderings() as $field => $order) {
            $queryBuilder->addOrderBy($this->getField($field), $order);
        }
    }

    private function buildLimit(QueryBuilder $queryBuilder, Query $query)
    {
        if (null !== $query->getFirstResult()) {
            $queryBuilder->setFirstResult($query->getFirstResult());
        }

        if (null !== $query->getMaxResults()) {
            $queryBuilder->setMaxResults($query->getMaxResults());
        }
    }

    private function walkExpression(QueryBuilder $queryBuilder, Expression $expr)
    {
        switch (true) {
            case $expr instanceof Comparison:
                return $this->walkComparison($queryBuilder, $expr);
                break;

            case $expr instanceof Composite:
                return $this->walkComposite($queryBuilder, $expr);
        }

        throw new \RuntimeException(sprintf(
            'Unknown Expression: %s',
            get_class($expr)
        ));
    }

    private function walkComparison(QueryBuilder $queryBuilder, Comparison $comparison)
    {
        $expressionFactory = $queryBuilder->expr();

        $field = $comparison->getField();
        $value = $comparison->getValue();

        switch ($comparison->getComparator()) {
            case Comparison::EQUALS:
                return $expressionFactory->eq($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::NOT_EQUALS:
                return $expressionFactory->neq($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::LESS_THAN:
                return $expressionFactory->lt($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::LESS_THAN_EQUAL:
                return $expressionFactory->lte($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::GREATER_THAN:
                return $expressionFactory->gt($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::GREATER_THAN_EQUAL:
                return $expressionFactory->gte($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::IN:
                return $expressionFactory->in($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::NOT_IN:
                return $expressionFactory->notIn($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::CONTAINS:
                return $expressionFactory->like($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::NOT_CONTAINS:
                return $expressionFactory->notLike($this->getField($field), $this->registerParameter($queryBuilder, $value));

            case Comparison::NULL:
                return $expressionFactory->isNull($this->getField($field));

            case Comparison::NOT_NULL:
                return $expressionFactory->isNotNull($this->getField($field));
        }

        throw new \RuntimeException('Unknown comparator: ' . $comparison->getComparator());
    }

    private function walkComposite(QueryBuilder $queryBuilder, Composite $expression)
    {
        $expressions = $expression->getExpressions();

        $ormExpressions = [];
        foreach ($expressions as $index => $childExpression) {
            $ormExpressions[] = $this->walkExpression($queryBuilder, $childExpression);
        }

        $method = $expression->getType() == Composite::AND ? 'andX' : 'orX';

        return call_user_func_array([$queryBuilder->expr(), $method], $ormExpressions);
    }

    private function getField($field): string
    {
        // if a source alias has been used, then use that
        if (false !== strpos($field, '.')) {
            return $field;
        }

        // otherwise use the primary source alias.
        return self::FROM_ALIAS . '.' . $field;
    }

    private function registerParameter(QueryBuilder $queryBuilder, $value)
    {
        $name = 'param' . $this->paramIndex++;
        $queryBuilder->setParameter($name, $value);

        return ':' . $name;
    }
}