<?php

namespace Interpro\ImageAggr\Operation;

use Interpro\Core\Contracts\Ref\ARef;
use Interpro\ImageAggr\Contracts\Db\ImageAggrDbAgent as ImageAggrDbAgentInterface;
use Interpro\ImageAggr\Contracts\Settings\Collection\ModSet;
use Interpro\ImageAggr\Contracts\Settings\GenerationSetting;
use Interpro\ImageAggr\Contracts\Settings\ModSetting;
use Interpro\ImageAggr\Exception\OperationException;
use Interpro\ImageAggr\Contracts\Operation\Enum\MimeType;
use Interpro\ImageAggr\Contracts\Placeholder\PlaceholderAgent as PlaceholderAgentInterface;
use Interpro\ImageAggr\Contracts\Settings\CropSetting as CropSettingInterface;
use Interpro\ImageAggr\Contracts\Settings\Enum\GenVariant;
use Interpro\ImageAggr\Contracts\Settings\ImageSetting as ImageSettingInterface;
use Interpro\ImageAggr\Contracts\Settings\PathResolver as PathResolverInterface;
use Interpro\ImageAggr\Contracts\Settings\ResizeSetting as ResizeSettingInterface;
use Interpro\Core\Contracts\Taxonomy\Taxonomy as TaxonomyInterface;
use Illuminate\Support\Facades\File;
use Intervention\Image\Facades\Image as ImageFacade;

abstract class Operation
{
    protected $imageType;
    protected $resizeType;
    protected $cropType;

    protected $pathResolver;
    protected $taxonomy;
    protected $dbAgent;
    protected $phAgent;

    protected $mime_types;

    public function __construct(PathResolverInterface $pathResolver,
                                TaxonomyInterface $taxonomy,
                                ImageAggrDbAgentInterface $imageAggrDbAgent,
                                PlaceholderAgentInterface $placeholderAgent)
    {
        $this->pathResolver = $pathResolver;
        $this->taxonomy = $taxonomy;
        $this->dbAgent = $imageAggrDbAgent;
        $this->phAgent = $placeholderAgent;

        $this->imageType = $this->taxonomy->getType('image');
        $this->resizeType = $this->taxonomy->getType('resize');
        $this->cropType = $this->taxonomy->getType('crop');

        $this->mime_types = [
            'gif'=>'image/gif',
            'jpeg'=>'image/jpeg',
            'png'=>'image/png',
            'svg'=>'image/svg+xml'
        ];
    }

    protected function checkOwner(ARef $aRef)
    {
        if(!$this->dbAgent->ownerExist($aRef))
        {
            throw new OperationException('Сущность '.$aRef->getType()->getName().'('.$aRef->getId().') не найдена!');
        }
    }

    protected function deleteAllFilesByPath($path)
    {
        foreach (glob($path.'*.*') as $file)
        {
            if(is_dir($file))
            {
                continue;
            }
            unlink($file);
        }
    }

    protected function deleteAllFiles(ARef $aRef, ImageSettingInterface $imageSetting, $tmp = false)
    {
        if($tmp)
        {
            $images_dir = $this->pathResolver->getTmpDir();
        }
        else
        {
            $images_dir = $this->pathResolver->getImageDir();
        }

        if (!is_writable($images_dir))
        {
            throw new OperationException('Дирректория картинок ('.$images_dir.') не доступна для записи!');
        }

        $image_prefix = $this->getImagePrefix($aRef->getType()->getName(), $aRef->getId(), $imageSetting->getName(), GenVariant::NONE);

        $this->deleteAllFilesByPath($images_dir.'/'.$image_prefix);

        $this->deleteGens($aRef, $imageSetting, $tmp);
    }

    protected function deleteGens(ARef $aRef, ImageSettingInterface $imageSetting, $tmp = false)
    {
        if($tmp)
        {
            $resize_dir = $this->pathResolver->getResizeTmpDir();
        }
        else
        {
            $resize_dir = $this->pathResolver->getResizeDir();
        }

        if (!is_writable($resize_dir))
        {
            throw new OperationException('Дирректория ресайзов ('.$resize_dir.') не доступна для записи!');
        }

        $image_prefix = $this->getImagePrefix($aRef->getType()->getName(), $aRef->getId(), $imageSetting->getName(), GenVariant::NONE);

        if(!$tmp)
        {
            $crop_dir = $this->pathResolver->getCropDir();

            if (!is_writable($crop_dir))
            {
                throw new OperationException('Дирректория кропов ('.$crop_dir.') не доступна для записи!');
            }

            $this->deleteAllFilesByPath($crop_dir.'/'.$image_prefix);
        }

        $this->deleteAllFilesByPath($resize_dir.'/'.$image_prefix);
    }

    protected function getImagePrefix($owner_name, $owner_id, $image_name, $gen_variant, $gen_name = '')
    {
        return $owner_name.'_'.$owner_id.'_'.$image_name.($gen_variant !== GenVariant::NONE ? '_'.$gen_name : '');
    }

    protected function isVectorImage($mime)
    {
        if($mime === MimeType::SVG)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    protected function getExtension($mime)
    {
        $ext = array_search($mime, $this->mime_types);

        if(!$ext)
        {
            throw new OperationException('Попытка получить расширение файла для не поддерживаемого типа '.$mime.'!');
        }

        return $ext;
    }

    protected function getNamedAttrs($name, & $attrs)
    {
        $item_attrs = [];

        if(array_key_exists($name, $attrs))
        {
            $item_attrs = & $attrs[$name];
        }

        return $item_attrs;
    }

    protected function getModImg(ModSetting $modSetting)
    {
        $image = $modSetting->getImageField();
        $genSetting = $modSetting->getGen();
        $gen_var = $genSetting->getVariant();

        $mod_file_prefix = $this->getImagePrefix('modimages', 0, $image->getName(), $gen_var, $genSetting->getName());

        if($gen_var === GenVariant::RESIZE)
        {
            $images_dir = $this->pathResolver->getResizeDir();
        }
        elseif($gen_var === GenVariant::CROP)
        {
            $images_dir = $this->pathResolver->getCropDir();
        }
        else
        {
            throw new OperationException('Ошибка определения дирректории файла модификации картинки (вариант должен быть Resize или Crop)!');
        }

        $mod_file_path = $images_dir.'/'.$mod_file_prefix;

        $mod_file_name = false;

        foreach (glob($mod_file_path.'.*') as $file)
        {
            if(is_dir($file))
            {
                continue;
            }

            $original_mime = File::mimeType($file);

            if($this->isVectorImage($original_mime))
            {
                continue;
            }

            $mod_file_name = $file;

            break;
        }

        if(!$mod_file_name)
        {
            throw new OperationException('Не найден ни один файл модификации '.$mod_file_path.' с растровым расширением!');
        }

        $modImg = $resizeImage = ImageFacade::make($mod_file_name);

        return $modImg;
    }

    protected function modImage(\Intervention\Image\Image $img, ModSet $mods)
    {
        foreach($mods as $modSetting)
        {
            $position   = $modSetting->getPosition();
            $x          = $modSetting->getX();
            $y          = $modSetting->getY();

            $modImg = $this->getModImg($modSetting);

            $img->insert($modImg, $position, $x, $y);
        }
    }

    /**
     * @param ImageSettingInterface $imageSetting
     * @param int $owner_id
     * @param array $attrs
     * @param bool $init
     *
     * @return void
     */
    protected function makePhImageResizes(ARef $aRef, ImageSettingInterface $imageSetting, $attrs = [], $init = false)
    {
        $resizes = $imageSetting->getResizes();

        foreach($resizes as $resize_name => $resizeSetting)
        {
            $item_attrs = $this->getNamedAttrs($resize_name, $attrs);

            $item_attrs['link'] = $this->phAgent->getResizePh($resizeSetting);

            $width = $resizeSetting->getWidth();
            $height = $resizeSetting->getHeight();

            //Все будет квадратным
            if(!$width)
            {
                $width = $height;
            }
            if(!$height)
            {
                $height = $width;
            }

            $item_attrs['width'] = $width;
            $item_attrs['height'] = $height;

            $this->dbAgent->resizeToDb($aRef, $imageSetting, $resizeSetting, $item_attrs, $init);
        }
    }

    /**
     * @param \Interpro\Core\Contracts\Ref\ARef
     * @param \Interpro\ImageAggr\Contracts\Settings\ImageSetting $imageSetting
     * @param array $attrs
     * @param bool $init
     *
     * @return void
     */
    protected function makePhImageCrops(ARef $aRef, ImageSettingInterface $imageSetting, $attrs = [], $init = false)
    {
        $crops = $imageSetting->getCrops();

        foreach($crops as $crop_name => $cropSetting)
        {
            $item_attrs = $this->getNamedAttrs($crop_name, $attrs);

            $item_attrs['link'] = $this->phAgent->getCropPh($cropSetting);

            $width = $cropSetting->getWidth();
            $height = $cropSetting->getHeight();

            $item_attrs['width'] = $width;
            $item_attrs['height'] = $height;
            $item_attrs['x'] = 0;
            $item_attrs['y'] = 0;

            $this->dbAgent->cropToDb($aRef, $imageSetting, $cropSetting, $item_attrs, $init);
        }
    }

    /**
     * @param \Interpro\Core\Contracts\Ref\ARef
     * @param \Interpro\ImageAggr\Contracts\Settings\ImageSetting $imageSetting
     * @param string $original_file_name
     * @param array $attrs
     *
     * @return void
     */
    protected function makeSameImageResizes(ARef $aRef, ImageSettingInterface $imageSetting, $original_file_name, $attrs = [])
    {
        $resizes = $imageSetting->getResizes();

        foreach($resizes as $resize_name => $resizeSetting)
        {
            $item_attrs = $this->getNamedAttrs($resize_name, $attrs);

            $item_attrs['link'] = $original_file_name;

            $this->dbAgent->resizeToDb($aRef, $imageSetting, $resizeSetting, $item_attrs);
        }
    }

    /**
     * @param \Interpro\Core\Contracts\Ref\ARef
     * @param \Interpro\ImageAggr\Contracts\Settings\ImageSetting $imageSetting
     * @param string $original_file_name
     * @param array $attrs
     *
     * @return void
     */
    protected function makeSameImageCrops(ARef $aRef, ImageSettingInterface $imageSetting, $original_file_name, $attrs = [])
    {
        $crops = $imageSetting->getCrops();

        foreach($crops as $crop_name => $cropSetting)
        {
            $item_attrs = $this->getNamedAttrs($crop_name, $attrs);

            $item_attrs['link'] = $original_file_name;

            $this->dbAgent->cropToDb($aRef, $imageSetting, $cropSetting, $item_attrs);
        }
    }

    /**
     * @param \Interpro\Core\Contracts\Ref\ARef $aRef
     * @param \Interpro\ImageAggr\Contracts\Settings\ImageSetting $imageSetting
     * @param array $attrs
     * @param bool $tmp
     *
     * @return void
     */
    protected function makeImageResizes(ARef $aRef, ImageSettingInterface $imageSetting, array $attrs = [], $tmp = false)
    {
        $resizes = $imageSetting->getResizes();

        foreach($resizes as $resize_name => $resizeSetting)
        {
            if($tmp and !$resizeSetting->whenUpload())
            {
                continue;
            }

            $item_attrs = $this->getNamedAttrs($resize_name, $attrs);

            $this->makeResize($aRef, $imageSetting, $resizeSetting, $item_attrs, $tmp);
        }
    }

    /**
     * @param \Interpro\Core\Contracts\Ref\ARef $aRef
     * @param \Interpro\ImageAggr\Contracts\Settings\ImageSetting $imageSetting
     * @param array $attrs
     *
     * @return void
     */
    protected function makeImageCrops(ARef $aRef, ImageSettingInterface $imageSetting, array $attrs = [])
    {
        $crops = $imageSetting->getCrops();

        foreach($crops as $crop_name => $cropSetting)
        {
            //Получить или создать атрибуты для текущего кропа
            $item_attrs = $this->getNamedAttrs($crop_name, $attrs);

            $this->makeCrop($aRef, $imageSetting, $cropSetting, $item_attrs);
        }
    }

    /**
     * @param \Interpro\Core\Contracts\Ref\ARef $aRef
     * @param \Interpro\ImageAggr\Contracts\Settings\ImageSetting $imageSetting
     * @param \Interpro\ImageAggr\Contracts\Settings\ResizeSetting $resizeSetting
     * @param array $item_attrs
     * @param bool $tmp
     *
     * @return void
     */
    protected function makeResize(ARef $aRef, ImageSettingInterface $imageSetting, ResizeSettingInterface $resizeSetting, array $item_attrs = [], $tmp = false)
    {
        if($tmp)
        {
            $images_dir = $this->pathResolver->getTmpDir();
        }
        else
        {
            $images_dir = $this->pathResolver->getImageDir();
        }

        if (!is_readable($images_dir))
        {
            throw new OperationException('Дирректория картинок недоступна для чтения!');
        }

        if($tmp)
        {
            $resizes_dir = $this->pathResolver->getResizeTmpDir();
        }
        else
        {
            $resizes_dir = $this->pathResolver->getResizeDir();
        }

        if (!is_writable($resizes_dir))
        {
            throw new OperationException('Дирректория ресайзов недоступна для записи!');
        }

        $original_prefix = $this->getImagePrefix($imageSetting->getEntityName(), $aRef->getId(), $imageSetting->getName(), GenVariant::NONE);
        $original_file_path = $images_dir.'/'.$original_prefix;

        $original_file_name = false;

        foreach (glob($original_file_path.'.*') as $file)
        {
            if(is_dir($file))
            {
                continue;
            }

            $original_mime = File::mimeType($file);

            if($this->isVectorImage($original_mime))
            {
                throw new OperationException('Попытка выполнить ресайз векторного файла '.$file.'!');
            }

            $original_file_name = $file;

            break;
        }

        if(!$original_file_name)
        {
            throw new OperationException('Не найден файл цели для ресайза!');
        }

        $extension = File::extension($original_file_name);

        $width = $resizeSetting->getWidth();
        $height = $resizeSetting->getHeight();

        $img = ImageFacade::make($original_file_name);

        if($width or $height)
        {
            $aspectRatio = !($width and $height);

            if(!$width)
            {
                $width = null;
            }
            if(!$height)
            {
                $height = null;
            }

            $img = $img->resize($width, $height,
                function ($constraint) use ($aspectRatio)
                {
                    if($aspectRatio)
                    {
                        $constraint->aspectRatio();
                    }
                });
        }

        $this->modImage($img, $resizeSetting->getMods());

        $resize_prefix = $this->getImagePrefix($imageSetting->getEntityName(), $aRef->getId(), $imageSetting->getName(), GenVariant::RESIZE, $resizeSetting->getName());
        $resize_file_name = $resize_prefix.'.'.$extension;
        $resize_file_path = $resizes_dir.'/'.$resize_prefix.'.'.$extension;

        $img->save($resize_file_path, 100);

        chmod($resize_file_path, 0644);

        if(!$tmp)
        {
            $resizeImage = ImageFacade::make($resize_file_path);
            $width = $resizeImage->getWidth();
            $height = $resizeImage->getHeight();
            $item_attrs['link'] = $this->pathResolver->getResizePath().'/'.$resize_file_name;
            $item_attrs['width'] = $width;
            $item_attrs['height'] = $height;
            $this->dbAgent->resizeToDb($aRef, $imageSetting, $resizeSetting, $item_attrs);
        }
    }

    /**
     * @param \Interpro\Core\Contracts\Ref\ARef $aRef
     * @param \Interpro\ImageAggr\Contracts\Settings\ImageSetting $imageSetting
     * @param \Interpro\ImageAggr\Contracts\Settings\CropSetting $cropSetting
     * @param array $item_attrs
     *
     * @return void
     */
    protected function makeCrop(ARef $aRef, ImageSettingInterface $imageSetting, CropSettingInterface $cropSetting, array $item_attrs = [])
    {
        $manual = false;

        if(array_key_exists('manual', $item_attrs))
        {
            $manual = (bool) $item_attrs['manual'];
        }

        $resizes_dir = $this->pathResolver->getResizeDir();

        if (!is_readable($resizes_dir))
        {
            throw new OperationException('Дирректория ресайзов недоступна для чтения!');
        }

        $crops_dir = $this->pathResolver->getCropDir();

        if (!is_writable($crops_dir))
        {
            throw new OperationException('Дирректория кропов недоступна для записи!');
        }

        $crop_x = 0;
        $crop_y = 0;

        if(array_key_exists('x', $item_attrs))
        {
            $crop_x = $item_attrs['x'];
        }

        if(array_key_exists('y', $item_attrs))
        {
            $crop_y = $item_attrs['y'];
        }

        //Ищем целевой ресайз
        $targetResizeSetting = $cropSetting->getTarget();
        $target_prefix = $this->getImagePrefix($imageSetting->getEntityName(), $aRef->getId(), $imageSetting->getName(), GenVariant::RESIZE, $targetResizeSetting->getName());
        $target_path = $resizes_dir.'/'.$target_prefix;

        $target_file_name = false;

        foreach (glob($target_path.'.*') as $file)
        {
            if(is_dir($file))
            {
                continue;
            }

            $target_mime = File::mimeType($file);

            if($this->isVectorImage($target_mime))
            {
                throw new OperationException('Попытка выполнить кроп векторного файла '.$file.'!');
            }

            $target_file_name = $file;

            break;
        }

        if(!$target_file_name)
        {
            throw new OperationException('Не найден файл цели для кропа по пути '.$target_path.'!');
        }

        $target_extension = File::extension($target_file_name);

        //Формирование пути к файлу кропа
        $crop_prefix = $this->getImagePrefix($imageSetting->getEntityName(), $aRef->getId(), $imageSetting->getName(), GenVariant::CROP, $cropSetting->getName());
        $crop_file_name = $crop_prefix.'.'.$target_extension;
        $crop_path = $crops_dir.'/'.$crop_file_name;

        //Выполнение кропа картинки
        $crop_width = $cropSetting->getWidth();
        $crop_height = $cropSetting->getHeight();
        $crop_color = $cropSetting->getColor();

        $target = ImageFacade::make($target_file_name);

        //Размеры цели
        $target_width = $target->getWidth();
        $target_height = $target->getHeight();

        //Сценарий №1, если кроп больше цели и не спозиционирован
        if($target_width < $crop_width and $target_height < $crop_height and $crop_x === 0 and $crop_y === 0 and !$manual)
        {
            ImageFacade::canvas($crop_width, $crop_height, $crop_color)->insert($target, 'center')->save($crop_path, 100);
        }
        else //Сценарий №2, если кроп спозиционирован или меньше цели
        {
            $crop_left = $crop_x;
            $target_left = 0;

            $crop_right = $crop_x + $crop_width;
            $target_right = $target_width;

            $crop_top = $crop_y;
            $target_top = 0;

            $crop_bottom = $crop_y + $crop_height;
            $target_bottom = $target_height;

            //Если не пересекаются:
            //(Нижний край рамки кропа выше верхнего края цели)
            //или (верхний край рамки кропа ниже нижнего края цели)
            //или (правый край рамки кропа левее левого края цели)
            //или (левый край рамки кропа правее правого края цели)
            if($crop_bottom <= $target_top
                or $crop_top >= $target_bottom
                or $crop_right <= $target_left
                or $crop_left >= $target_right)
            {
                //Пустая картинка цветом фона кропа
                ImageFacade::canvas($crop_width, $crop_height, $crop_color)->save($crop_path, 100);
            }
            else
            {
                //Находим прямоугольник пересечения и вырезаем его

                //Если кроп внутри цели
                if($crop_left >= $target_left and $crop_right <= $target_right and $crop_top >= $target_top and $crop_bottom <= $target_bottom)
                {
                    $target->crop($crop_width, $crop_height, $crop_x, $crop_y);
                    $target->save($crop_path, 100);
                }
                //Если цель внутри кропа
                elseif($target_left >= $crop_left and $target_right <= $crop_right and $target_top >= $crop_top and $target_bottom <= $crop_bottom)
                {
                    ImageFacade::canvas($crop_width, $crop_height, $crop_color)->insert($target, 'top-left', abs($crop_x), abs($crop_y))->save($crop_path, 100);
                }
                else //Тогда находим прямоугольник совпадения
                {
                    //Координаты совпадения по X
                    if($crop_left <= $target_left)
                    {
                        $target_crop_x = 0;
                        $crop_insert_x = -$crop_left;
                    }
                    else
                    {
                        $target_crop_x = $crop_left;
                        $crop_insert_x = 0;
                    }

                    if($crop_right >= $target_right)
                    {
                        $target_crop_width = $target_width;
                    }
                    else
                    {
                        $target_crop_width = $target_width - ($target_right - $crop_right);
                    }

                    $target_crop_width -= $target_crop_x;

                    //Координаты совпадения по Y
                    if($crop_top <= $target_top)
                    {
                        $target_crop_y = 0;
                        $crop_insert_y = -$crop_top;
                    }
                    else
                    {
                        $target_crop_y = $crop_top;
                        $crop_insert_y = 0;
                    }

                    if($crop_bottom >= $target_bottom)
                    {
                        $target_crop_height = $target_height;
                    }
                    else
                    {
                        $target_crop_height = $target_height - ($target_bottom - $crop_bottom);
                    }

                    $target_crop_height -= $target_crop_y;

                    $target->crop($target_crop_width, $target_crop_height, $target_crop_x, $target_crop_y);

                    ImageFacade::canvas($crop_width, $crop_height, $crop_color)->insert($target, 'top-left', $crop_insert_x, $crop_insert_y)->save($crop_path, 100);
                }
            }
        }

        chmod($crop_path, 0644);

        $item_attrs['link'] = $this->pathResolver->getCropPath().'/'.$crop_file_name;
        //-----------------------------------------------------

        $this->dbAgent->cropToDb($aRef, $imageSetting, $cropSetting, $item_attrs);
    }

}


<?php
namespace Able\Prototypes;

use \Able\Helpers\Arr;
use \Able\Prototypes\THierarchical;

trait TRetrospective {
	use THierarchical;

	/**
	 * Returns a static property value as an array
	 * extended by a similar values provided by parent classes.
	 *
	 * @param string $name
	 * @return array
	 */
	protected final static function retrospect(string $name){
		return call_user_func_array('array_merge', array_map(function($class) use ($name){
			return property_exists($class, $name) ? $class::${$name} : [];
		}, array_reverse(static::hierarchy())));
	}
}


<?php

/*
 * This file is part of the Glavweb DataSchemaBundle package.
 *
 * (c) Andrey Nilov <nilov@glavweb.ru>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Glavweb\DataSchemaBundle\Command;

use Glavweb\DataSchemaBundle\Generator\ScopeGenerator;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

/**
 * Class GenerateScopeCommand
 *
 * @author Andrey Nilov <nilov@glavweb.ru>
 * @package Glavweb\DataSchemaBundle
 */
class GenerateScopeCommand extends ContainerAwareCommand
{
    /**
     * Configure
     */
    protected function configure()
    {
        $this
            ->setName('glavweb:scope')
            ->setDescription('Generates a scope based on the given model class')
            ->addArgument('model', InputArgument::REQUIRED, 'The fully qualified model class')
        ;
    }

    /**
     * {@inheritDoc}
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $container         = $this->getContainer();
        $modelClass        = $this->validateClass($input->getArgument('model'));
        $doctrine          = $this->getContainer()->get('doctrine');
        $skeletonDirectory = __DIR__ . '/../Resources/skeleton';

        try {
            $scopeGenerator = new ScopeGenerator(
                $container->get('kernel'),
                $doctrine,
                $container->getParameter('glavweb_data_schema.scope_dir'),
                $skeletonDirectory
            );

            $scopeGenerator->generate($modelClass);
            $output->writeln(sprintf(
                '%sThe scope file "<info>%s</info>" has been %s.',
                PHP_EOL,
                realpath($scopeGenerator->getTemplateFile()),
                ($scopeGenerator->isFileTemplateUpdated() ? 'updated' : 'generated')
            ));

            if ($scopeGenerator->isFileGenerated()) {
                $output->writeln(sprintf(
                    '%sThe scope file "<info>%s</info>" has been generated.',
                    PHP_EOL,
                    realpath($scopeGenerator->getFile())
                ));
            }

        } catch (\Exception $e) {
            $this->writeError($output, $e->getMessage());
        }

        return 0;
    }

    /**
     * @param OutputInterface $output
     * @param string $message
     */
    protected function writeError(OutputInterface $output, $message)
    {
        $output->writeln(sprintf("\n<error>%s</error>", $message));
    }

    /**
     *
     * @param string $class
     * @return string
     * @throws \InvalidArgumentException
     */
    public function validateClass($class)
    {
        $class = str_replace('/', '\\', $class);

        if (!class_exists($class)) {
            throw new \InvalidArgumentException(sprintf('The class "%s" does not exist.', $class));
        }

        return $class;
    }
}


<?php

namespace Interpro\ImageAggr\Executors;

use Illuminate\Support\Facades\DB;
use Interpro\Core\Contracts\Executor\AUpdateExecutor;
use Interpro\Core\Contracts\Mediator\UpdateMediator;
use Interpro\Core\Contracts\Ref\ARef as ARefInterface;
use Interpro\Core\Taxonomy\Enum\TypeMode;
use Interpro\ImageAggr\Exception\ImageAggrException;

class ModImagesUpdateExecutor implements AUpdateExecutor
{
    private $updateMediator;

    public function __construct(UpdateMediator $updateMediator)
    {
        $this->updateMediator = $updateMediator;
    }

    /**
     * @return string
     */
    public function getFamily()
    {
        return 'modimages';
    }

    /**
     * @param \Interpro\Core\Contracts\Ref\ARef $ref
     * @param array $values
     *
     * @return void
     */
    public function update(ARefInterface $ref, array $values)
    {
        $type = $ref->getType();
        $type_name = $type->getName();
        $mode = $type->getMode();

        if($type_name !== 'modimages' or $mode !== TypeMode::MODE_A)
        {
            throw new ImageAggrException('Модификатор предназначен для изменения блока modimages(A), передано: '.$type_name.'('.$mode.')!');
        }

        //[[[
        DB::beginTransaction();

        $owns = $type->getOwns();

        foreach($owns as $own_name => $own)
        {
            $family = $own->getFieldTypeFamily();
            $mode = $own->getMode();

            if(array_key_exists($own_name, $values))
            {
                $value = $values[$own_name];

                if($mode === TypeMode::MODE_B)
                {
                    $updater = $this->updateMediator->getBUpdateExecutor($family);
                    $updater->update($ref, $own, $value);
                }
                elseif($mode === TypeMode::MODE_C)
                {
                    $updater = $this->updateMediator->getCUpdateExecutor($family);
                    $updater->update($ref, $own, $value);
                }
            }
        }

        DB::commit();
        //]]]
    }
}


<?php

/**
 * This file is part of the cyberalien/simple-tokenizer package.
 *
 * (c) Vjacheslav Trushkin <cyberalien@gmail.com>
 *
 * This is not open source library.
 * This library can be used only with products available on artodia.com
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 *
 * @package cyberalien/simple-tokenizer
 */

namespace CyberAlien\SimpleTokenizer;

/**
 * Class that converts css code into list or tree of tokens
 */
class Tokenizer
{
    /**
     * Convert list or tree of tokens to string
     *
     * @param array $tokens
     * @param array $options (optional)
     * @return string
     */
    public static function build($tokens, $options = []) {
        return (new Builder($options))->build($tokens);
    }

    /*
     * Options
     */
    public $splitRules;
    public $ignoreErrors;
    public $lessSyntax;
    public $ruleModifiers;
    public $errors;

    /*
     * Internal stuff
     */
    protected $_tokens;
    protected $_css;
    protected $_cssLC;

    /**
     * Constructor
     *
     * @param array $options (optional)
     */
    public function __construct($options = []) {
        $this->splitRules = !isset($options['splitRules']) || $options['splitRules'] !== false;
        $this->ignoreErrors = !isset($options['ignoreErrors']) || $options['ignoreErrors'] !== false;
        $this->lessSyntax = !empty($options['lessSyntax']);
        $this->ruleModifiers = isset($options['ruleModifiers']) ? $options['ruleModifiers'] : ['default', 'important'];
    }

    /**
     * Get tokens as tree
     *
     * @param string $css
     * @return array
     */
    public function tree($css) {
        // Do stuff
        $this->_tokens = $this->tokenize($css);
        $results = $this->_parseTokens(array_shift($this->_tokens));

        // Add remaining items to root element
        while (count($this->_tokens)) {
            if (!$this->ignoreErrors) {
                $this->errors[] = new ParseError('Unmatched }', $this->_css, $this->_tokens[0]['index']);
            }
            $results = array_merge($results, $this->_parseTokens(array_shift($this->_tokens)));
        }

        return $results;
    }

    /**
     * Convert css into list of tokens
     *
     * @param string $css
     * @return array
     */
    public function tokenize($css) {
        $this->_css = $css;
        $this->_cssLC = strtolower($this->_css);
        $this->errors = [];

        $start = 0;
        $words = [];
        $items = [];
        $depth = 0;
        $functionDepth = 0;
        $expressionDepth = 0;
        $blockStart = 0;
        $selectorStart = 0;
        $error = false;
        $cssLength = strlen($this->_css);

        $validTokens = ['"', "'", '/*', '{', '}', ';', 'url(', '\\'];
        if ($this->lessSyntax) {
            $validTokens = array_merge($validTokens, ['(', ')', '//', '@{', '#{']);
        }

        $tokens = $this->_findTokens($validTokens);
        foreach($tokens as $token) {
            if ($token['index'] < $start) {
                continue;
            }

            switch ($token['token']) {
                case '//':
                    // Skip to end of line
                    $words[] = [
                        'type'  => 'text',
                        'text'  => substr($this->_css, $start, $token['index'] - $start),
                        'index' => $start,
                    ];
                    $start = $token['index'];

                    $end1 = strpos($this->_css, "\n", $start + 2);
                    $end2 = strpos($this->_css, "\r", $start + 2);
                    $end = $end1 === false ? $end2 : ($end2 === false ? $end1 : min($end1, $end2));
                    if ($end === false) {
                        // Last string
                        $start = $cssLength;
                        break;
                    }

                    $start = $end + 1;
                    break;

                case '/*':
                    // Skip to end of comment
                    $words[] = [
                        'type'  => 'text',
                        'text'  => substr($this->_css, $start, $token['index'] - $start),
                        'index' => $start,
                    ];
                    $start = $token['index'];

                    $end = strpos($this->_css, '*/', $start + 2);
                    if ($end === false) {
                        // Skip to end of file
                        if (!$this->ignoreErrors) {
                            $this->errors[] = new ParseError('Missing comment closing statement', $this->_css, $start);
                            $error = true;
                        }
                        $start = $cssLength;
                        break;
                    }

                    $start = $end + 2;
                    break;

                case '\\':
                    // Escaped character, skip next character
                    $words[] = [
                        'type'  => 'text',
                        'text'  => substr($this->_css, $start, $token['index'] - $start + 2),
                        'index' => $start,
                    ];
                    $start = $token['index'] + 2;
                    break;

                case 'url(':
                    $words[] = [
                        'type'  => 'text',
                        'text'  => substr($this->_css, $start, $token['index'] - $start),
                        'index' => $start,
                    ];
                    $start = $token['index'];

                    // Skip to end of URL
                    $end = $this->_findEndOfURL($start);
                    if (!is_numeric($end)) {
                        // Invalid URL - skip "url"
                        $words[] = [
                            'type'  => 'text',
                            'text'  => substr($this->_css, $start, 3),
                            'index' => $start,
                        ];
                        if (!$this->ignoreErrors) {
                            $this->errors[] = new ParseError('Incomplete URL', $this->_css, $start);
                            $error = true;
                        }
                        $start += 3;
                        break;
                    }
                    $words[] = [
                        'type'  => 'url',
                        'text'  => substr($this->_css, $start, $end - $start),
                        'index' => $start,
                    ];
                    $start = $end;
                    break;

                case '"':
                case '\'':
                    $words[] = [
                        'type'  => 'text',
                        'text'  => substr($this->_css, $start, $token['index'] - $start),
                        'index' => $start,
                    ];
                    $start = $token['index'];

                    // Skip to end of quoted string
                    $end = $this->_findEndOfQuotedString($token['token'], $start);
                    if ($end === false) {
                        // Missing closing quote
                        if ($this->ignoreErrors) {
                            $words[] = [
                                'type'  => 'text',
                                'text'  => substr($this->_css, $start, 1),
                                'index' => $start,
                            ];
                            $start ++;
                        }
                        else {
                            $this->errors[] = new ParseError('Missing closing ' . $token['token'], $this->_css, $start);
                            $error = true;
                            $words[] = [
                                'type'  => 'code',
                                'text'  => substr($this->_css, $start),
                                'index' => $start,
                            ];
                            $start = $cssLength;
                        }
                        break;
                    }
                    $words[] = [
                        'type'  => 'string',
                        'text'  => substr($this->_css, $start, $end - $start),
                        'index' => $start,
                    ];
                    $start = $end;
                    break;

                case ';':
                    if ($functionDepth > 0) {
                        break;
                    }
                    if ($this->splitRules) {
                        $words[] = [
                            'type'  => 'text',
                            'text'  => substr($this->_css, $start, $token['index'] - $start),
                            'index' => $start,
                        ];
                        $items[] = $this->_checkRule($words, $token['token'], $error);
                        if ($error) {
                            $items[count($items) - 1]['error'] = true;
                            $error = false;
                        }
                    }
                    $selectorStart = $start = $token['index'] + 1;
                    $words = [];
                    break;

                case '{':
                    // Get selector
                    if (!$this->splitRules) {
                        if ($selectorStart > $blockStart) {
                            $code = trim(substr($this->_css, $blockStart, $selectorStart - $blockStart));
                            if (strlen($code)) {
                                $items[] = [
                                    'token' => 'code',
                                    'code'  => $code,
                                    'index' => $blockStart,
                                ];
                                if ($error) {
                                    $items[count($items) - 1]['error'] = true;
                                    $error = false;
                                }
                            }
                        }
                    }
                    $words[] = [
                        'type'  => 'text',
                        'text'  => substr($this->_css, $start, $token['index'] - $start),
                        'index' => $start,
                    ];
                    $items[] = $this->_checkSelectors($words);

                    $blockStart = $selectorStart = $start = $token['index'] + 1;
                    $words = [];
                    $depth ++;
                    break;

                case '}':
                    if ($expressionDepth > 0) {
                        // LESS/SASS expression
                        if ($expressionDepth === 1 && $this->splitRules) {
                            // Find start of expression
                            $found = false;
                            $text = substr($this->_css, $start, $token['index'] - $start + 1);

                            for ($i = count($words) - 1; $i >= 0; $i --) {
                                if (!empty($words[$i]['beforeExpression'])) {
                                    $found = true;
                                    unset($words[$i]['beforeExpression']);
                                    if ($i === count($words) - 1) {
                                        // Previous token starts expression - do not change word tokens
                                        $words[] = [
                                            'type'  => 'expression',
                                            'text'  => $text,
                                            'index' => $start
                                        ];
                                    } else {
                                        // Merge with previous tokens
                                        $start = $words[$i + 1]['index'];
                                        $words = array_slice($words, 0, $i + 1);
                                        $words[] = [
                                            'type'  => 'expression',
                                            'text'  => $text,
                                            'index' => $start
                                        ];
                                    }
                                    break;
                                }
                                $text = $words[$i]['text'] . $text;
                            }
                            if (!$found) {
                                $words[] = [
                                    'type'  => 'expression',
                                    'text'  => $text,
                                    'index' => $start,
                                    'error' => true
                                ];
                            }
                            $start = $token['index'] + 1;
                        }
                        $expressionDepth --;
                        break;
                    }
                    // End of block
                    if ($this->splitRules) {
                        $words[] = [
                            'type'  => 'text',
                            'text'  => substr($this->_css, $start, $token['index'] - $start),
                            'index' => $start,
                        ];
                        $items[] = $this->_checkRule($words, '', $error);
                        if ($error) {
                            $items[count($items) - 1]['error'] = true;
                        }
                    } else {
                        $code = trim(substr($this->_css, $blockStart, $token['index'] - $blockStart));
                        if (strlen($code)) {
                            $items[] = [
                                'token' => 'code',
                                'code'  => $code,
                                'index' => $blockStart,
                            ];
                            if ($error) {
                                $items[count($items) - 1]['error'] = true;
                            }
                        }
                    }
                    $error = false;
                    $items[] = [
                        'token' => '}',
                        'index' => $token['index'],
                    ];

                    if (!$depth && !$this->ignoreErrors) {
                        $this->errors[] = new ParseError('Unexpected }', $this->_css, $token['index']);
                    }
                    $depth --;

                    $blockStart = $selectorStart = $start = $token['index'] + 1;
                    $words = [];
                    $functionDepth = 0;
                    break;

                case '(':
                    // Function with LESS syntax enabled
                    if ($this->splitRules) {
                        $row = [
                            'type'  => 'text',
                            'text'  => substr($this->_css, $start, $token['index'] - $start),
                            'index' => $start,
                        ];
                        if (!$functionDepth) {
                            $row['beforeFunction'] = true;
                        }
                        $words[] = $row;
                        $start = $token['index'];
                    }
                    $functionDepth ++;
                    break;

                case ')':
                    // End of function with LESS syntax enabled
                    if ($functionDepth === 1 && $this->splitRules) {
                        // Find start of function
                        $found = false;
                        $text = substr($this->_css, $start, $token['index'] - $start + 1);

                        for ($i = count($words) - 1; $i >= 0; $i --) {
                            if (!empty($words[$i]['beforeFunction'])) {
                                $found = true;
                                unset($words[$i]['beforeFunction']);
                                if ($i === count($words) - 1) {
                                    // Previous token starts function - do not change word tokens
                                    $words[] = [
                                        'type'  => 'function',
                                        'text'  => $text,
                                        'index' => $start
                                    ];
                                } else {
                                    // Merge with previous tokens
                                    $start = $words[$i + 1]['index'];
                                    $words = array_slice($words, 0, $i + 1);
                                    $words[] = [
                                        'type'  => 'function',
                                        'text'  => $text,
                                        'index' => $start
                                    ];
                                }
                                break;
                            }
                            $text = $words[$i]['text'] . $text;
                        }
                        if (!$found) {
                            $words[] = [
                                'type'  => 'function',
                                'text'  => $text,
                                'index' => $start,
                                'error' => true
                            ];
                        }
                        $start = $token['index'] + 1;
                    }
                    $functionDepth --;
                    if ($functionDepth < 0) {
                        $functionDepth = 0;
                    }
                    break;

                case '@{':
                case '#{':
                    // Expression with LESS/SASS syntax enabled
                    if ($this->splitRules) {
                        $row = [
                            'type'  => 'text',
                            'text'  => substr($this->_css, $start, $token['index'] - $start + 2),
                            'index' => $start,
                        ];
                        if (!$expressionDepth) {
                            $row['beforeExpression'] = true;
                        }
                        $words[] = $row;
                        $start = $token['index'] + 2;
                    }
                    $expressionDepth ++;
                    break;
            }
        }

        if ($depth > 0 && !$this->ignoreErrors) {
            $this->errors[] = new ParseError('Missing }', $this->_css, $cssLength);
        }

        // Add remaining code
        if ($this->splitRules) {
            $words[] = [
                'type'  => 'text',
                'text'  => substr($this->_css, $start),
                'index' => $start,
            ];
            $items[] = $this->_checkRule($words, '', $error);
            if ($error) {
                $items[count($items) - 1]['error'] = true;
            }
        } else {
            $code = trim(substr($this->_css, $blockStart));
            if (strlen($code)) {
                $items[] = [
                    'token' => 'code',
                    'code'  => $code,
                    'index' => $blockStart,
                ];
                if ($error) {
                    $items[count($items) - 1]['error'] = true;
                }
            }
        }

        return array_values(array_filter($items, function($item) {
            return $item !== false;
        }));
    }

    /**
     * Find all tokens in code
     *
     * @param array $tokens Array of tokens
     * @return array
     */
    protected function _findTokens($tokens) {
        $list = [];

        foreach ($tokens as $token) {
            $index = 0;
            while (true) {
                $index = strpos($this->_cssLC, $token, $index);
                if ($index === false) {
                    break;
                }
                $list[] = [
                    'token' => $token,
                    'index' => $index
                ];
                $index ++;
            }
        }

        usort($list, function($a, $b) {
            return $a['index'] - $b['index'];
        });
        return $list;
    }

    /**
     * Find end of quoted string
     *
     * @param string $quote Quote character
     * @param int $start Position of first quote
     * @return int|bool Position of character after end of string, false if string is broken
     */
    protected function _findEndOfQuotedString($quote, $start) {
        $nextEscape = strpos($this->_css, '\\', $start + 1);
        $end = strpos($this->_css, $quote, $start + 1);

        if ($end === false) {
            // Invalid string
            return false;
        }

        while ($nextEscape !== false && $nextEscape < $end) {
            if ($end === $nextEscape + 1) {
                $end = strpos($this->_css, $quote, $end + 1);
                if ($end === false) {
                    // Invalid string
                    return false;
                }
            }
            $nextEscape = strpos($this->_css, '\\', $nextEscape + 2);
        }

        return $end + 1;
    }

    /**
     * Find end of url
     *
     * @param int $start
     * @return int|ParseError Position of character after end of url() or error message
     */
    protected function _findEndOfURL($start = 0) {
        $length = strlen($this->_css);
        $index = $start + 4;

        while ($index < $length) {
            $next = substr($this->_css, $index, 1);
            switch ($next) {
                case '"':
                case '\'':
                    // quoted url
                    $end = $this->_findEndOfQuotedString($next, $index);
                    if ($end === false) {
                        return new ParseError('Incomplete string', $this->_css, $index);
                    }
                    $end = strpos($this->_css, ')', $end);
                    return $end === false ? new ParseError('Cannot find end of URL', $this->_css, $start) : $end + 1;

                case ' ':
                case "\t":
                case "\r":
                case "\n":
                    // skip whitespace
                    $index ++;
                    break;

                default:
                    // unquoted url
                    while (true) {
                        switch ($next) {
                            case ')':
                                return $index + 1;

                            case '"':
                            case '\'':
                            case '(':
                            case ' ':
                            case "\t":
                            case "\r":
                            case "\n":
                                return new ParseError('Invalid URL', $this->_css, $start);

                            default:
                                if (ord(substr($this->_css, $index, 1)) < 32) {
                                    return new ParseError('Invalid URL', $this->_css, $start);
                                }
                        }
                        $index ++;
                        if ($index >= $length) {
                            return new ParseError('Cannot find end of URL', $this->_css, $start);
                        }
                        $next = substr($this->_css, $index, 1);
                    }
            }
        }
        return new ParseError('Cannot find end of URL', $this->_css, $start);
    }

    /**
     * Check for valid css rule, return either code or rule token
     *
     * @param array $words Array of words
     * @param string $extra Additional text to add if returning code
     * @param bool $ignoreErrors True if errors should be ignored
     * @return array|bool
     */
    protected function _checkRule($words, $extra, $ignoreErrors) {
        $pairs = $this->_findRulePairs($words);

        if (is_bool($pairs)) {
            $value = $this->_mergeWords($words) . $extra;
            if (!strlen($value)) {
                return false;
            }

            $index = $words[0]['index'];
            if ($pairs === false && !$this->ignoreErrors && !$ignoreErrors) {
                $this->errors[] = new ParseError('Invalid css rule', $this->_css, $index);
            }
            return [
                'token' => 'code',
                'code'  => $value,
                'index' => $index,
            ];
        }
        return $pairs;
    }

    /**
     * Merge words list to string
     *
     * @param array $words
     * @return string
     */
    protected function _mergeWords($words) {
        $value = '';

        foreach ($words as $word) {
            $value .= $word['text'];
        }

        return trim($value);
    }

    /**
     * Get token with selectors list
     *
     * @param array $words
     * @return array
     */
    protected function _checkSelectors($words) {
        $selectors = $this->_getSelectors($words);
        $result = [
            'token' => '{',
            'code'  => $this->_mergeWords($words),
            'index' => $words[0]['index'],
        ];

        if (!count($selectors)) {
            return $result;
        }

        if (substr($selectors[0], 0, 1) === '@') {
            $split = preg_split('/\s+/', $selectors[0]);
            $result['atRule'] = substr($split[0], 1);
            $selectors[0] = trim(substr($selectors[0], 1 + strlen($result['atRule'])));
            $result['atValues'] = $selectors;
        } else {
            $result['selectors'] = $selectors;
        }

        return $result;
    }

    /**
     * Get list of selectors from list of words
     *
     * @param array $words
     * @return array
     */
    protected function _getSelectors($words) {
        $selectors = [];
        $selector = '';

        foreach ($words as $word) {
            if ($word['type'] !== 'text') {
                $selector .= $word['text'];
                continue;
            }

            $list = explode(',', $word['text']);
            $selector .= array_shift($list);
            while (count($list) > 0) {
                $selectors[] = trim($selector);
                $selector = array_shift($list);
            }
        }

        $selectors[] = trim($selector);

        $results = [];
        foreach ($selectors as $row) {
            if (strlen($row) > 0) {
                $results[] = $row;
            }
        }
        return $results;
    }

    /**
     * Get key/value pairs from list of words
     *
     * @param array $words
     * @return array|bool
     */
    protected function _findRulePairs($words)
    {
        $key = '';
        $value = '';
        $isKey = true;
        $hasFunction = false;

        foreach ($words as $word) {
            if ($word['type'] !== 'text') {
                if ($isKey) {
                    if (!$this->lessSyntax) {
                        // Cannot have URL or quoted string in key
                        return false;
                    }

                    // Check for function
                    if ($word['type'] === 'function') {
                        $hasFunction = true;
                    }
                    $key .= $word['text'];
                    continue;
                }
                $value .= $word['text'];
                continue;
            }

            $pairs = explode(':', $word['text']);
            if ($this->lessSyntax && count($pairs) > 1) {
                // Check for "&:extend" LESS syntax
                $updated = false;
                for ($index = 1; $index < count($pairs); $index ++) {
                    if ($pairs[$index] === 'extend' || substr($pairs[$index], 0, 7) === 'extend(') {
                        $pairs[$index - 1] .= $pairs[$index];
                        $pairs[$index] = null;
                        $updated = true;
                    }
                }

                if ($updated) {
                    $newPairs = [];
                    foreach ($pairs as $item) {
                        if ($item !== null) {
                            $newPairs[] = $item;
                        }
                    }
                    $pairs = $newPairs;
                }
            }

            if (count($pairs) > 2) {
                return false;
            }
            if (count($pairs) === 2) {
                if (!$isKey) {
                    return false;
                }
                $key .= $pairs[0];
                $value = $pairs[1];
                $isKey = false;
                continue;
            }
            if ($isKey) {
                $key .= $word['text'];
            } else {
                $value .= $word['text'];
            }
        }

        if ($isKey) {
            // True if token should be treated as code
            return $this->lessSyntax ? $hasFunction || substr(trim($key), 0, 1) === '@' : false;
        }

        $key = trim($key);
        $value = trim($value);
        if (!strlen($key) || !strlen($value)) {
            return false;
        }

        $result = [
            'token' => 'rule',
            'key'   => $key,
            'value' => $value,
            'index' => $words[0]['index'],
        ];

        foreach($this->ruleModifiers as $word) {
            if (strtolower(substr($result['value'], -1 - strlen($word))) === '!' . $word) {
                $result[$word] = true;
                $result['value'] = trim(substr($result['value'], 0, strlen($result['value']) - strlen($word) - 1));
                if (!strlen($result['value'])) {
                    return false;
                }
            }
        }

        return $result;
    }

    /**
     * Convert to tree
     *
     * @param array $item
     * @return array
     */
    protected function _parseTokens($item) {
        $results = [];
        while ($item !== null) {
            switch ($item['token']) {
                case '}':
                    return $results;

                case '{':
                    $item['children'] = $this->_parseTokens(array_shift($this->_tokens));
                    $results[] = $item;
                    break;

                default:
                    $results[] = $item;
            }

            $item = array_shift($this->_tokens);
        }
        return $results;
    }
}


<?php

namespace ElfSundae\Laravel\Api;

use Closure;
use Illuminate\Support\Str;
use Illuminate\Http\Request;

class Helper
{
    /**
     * Stores the app key of the current api client.
     */
    const CURRENT_APP_KEY = 'current_app_key';

    /**
     * Set the current app key for the request.
     *
     * @param  string  $key
     * @param  \Illuminate\Http\Request|null  $request
     * @return \Illuminate\Http\Request
     */
    public static function setCurrentAppKeyForRequest($key, Request $request = null)
    {
        $request = $request ?: app('request');

        $request->attributes->set(static::CURRENT_APP_KEY, $key);

        return $request;
    }

    /**
     * Get the app key of the current api client.
     *
     * @param  \Illuminate\Http\Request|null  $request
     * @return string|null
     */
    public static function getCurrentAppKey(Request $request = null)
    {
        $request = $request ?: app('request');

        return $request->attributes->get(static::CURRENT_APP_KEY);
    }

    /**
     * Add JSON type to the "Accept" header for the request.
     *
     * @see https://laravel-china.org/topics/3430
     *
     * @param  \Closure  $determination
     * @param  \Closure  $callback
     * @return mixed
     */
    public static function addAcceptableJsonTypeForRequest(Closure $determination = null, Closure $callback = null)
    {
        app()->rebinding('request', function ($app, Request $request) use ($determination, $callback) {
            if (is_null($determination) || $determination($request)) {
                $accept = $request->headers->get('Accept');

                if (! Str::contains($accept, ['/json', '+json'])) {
                    $accept = rtrim('application/json,'.$accept, ',');

                    $request->headers->set('Accept', $accept);
                    $request->server->set('HTTP_ACCEPT', $accept);
                    $_SERVER['HTTP_ACCEPT'] = $accept;

                    if ($callback) {
                        $callback($request);
                    }
                }
            }
        });
    }
}


<?php

namespace Interpro\ImageAggr\Executors;

use Interpro\Core\Contracts\Ref\ARef;

use Interpro\Core\Contracts\Executor\OwnSynchronizer as OwnSynchronizerInterface;
use Interpro\Core\Contracts\Taxonomy\Fields\OwnField;
use Interpro\Core\Taxonomy\Enum\TypeMode;
use Interpro\ImageAggr\Contracts\Operation\InitOperation;
use Interpro\ImageAggr\Contracts\Settings\Collection\ImageSettingsSet;
use Interpro\ImageAggr\Exception\ImageAggrException;

class Synchronizer implements OwnSynchronizerInterface
{

    private $operation;
    private $settingsSet;

    public function __construct(InitOperation $operation, ImageSettingsSet $settingsSet)
    {
        $this->operation = $operation;
        $this->settingsSet = $settingsSet;
    }

    /**
     * @return string
     */
    public function getFamily()
    {
        return 'imageaggr';
    }

    /**
     * @param \Interpro\Core\Contracts\Ref\ARef $ref
     * @param \Interpro\Core\Contracts\Taxonomy\Fields\OwnField $own
     *
     * @return void
     */
    public function sync(ARef $ref, OwnField $own)
    {
        $type = $own->getFieldType();
        $name = $type->getName();
        $mode = $type->getMode();

        if($name !== 'image' or $mode !== TypeMode::MODE_B)
        {
            throw new ImageAggrException('Синхронизатор предназначен для поля типа image(B), передано: '.$name.'('.$mode.')!');
        }

        $imageSetting = $this->settingsSet->getImage($own);

        //Инициализация в картинках работает как синхронизация всегда
        $this->operation->execute($ref, $imageSetting);

    }

}


<?php

namespace Praxigento\Accounting\Ui\DataProvider\Grid\Type\Asset;

use Praxigento\Accounting\Repo\Data\Type\Asset as ETypeAsset;

class Query
    extends \Praxigento\Core\App\Ui\DataProvider\Grid\Query\Builder
{
    /**#@+ Tables aliases for external usage ('camelCase' naming) */
    const AS_TYP_ASSET = 'tas';
    /**#@- */
    const A_CODE = 'code';
    /**#@+
     * Aliases for data attributes.
     */
    const A_ID_ASSET = 'id';
    const A_NOTE = 'note';

    /**#@- */

    protected function getMapper()
    {
        if (is_null($this->mapper)) {
            $map = [
                self::A_ID_ASSET => self::AS_TYP_ASSET . '.' . ETypeAsset::A_ID,
                self::A_CODE => self::AS_TYP_ASSET . '.' . ETypeAsset::A_CODE,
                self::A_NOTE => self::AS_TYP_ASSET . '.' . ETypeAsset::A_NOTE
            ];
            $this->mapper = new \Praxigento\Core\App\Repo\Query\Criteria\Def\Mapper($map);
        }
        $result = $this->mapper;
        return $result;
    }

    protected function getQueryItems()
    {
        $result = $this->conn->select();
        /* define tables aliases for internal usage (in this method) */
        $asTypAsset = self::AS_TYP_ASSET;

        /* SELECT FROM prxgt_acc_type_asset */
        $tbl = $this->resource->getTableName(ETypeAsset::ENTITY_NAME);
        $as = $asTypAsset;
        $cols = [
            self::A_ID_ASSET => ETypeAsset::A_ID,
            self::A_CODE => ETypeAsset::A_CODE,
            self::A_NOTE => ETypeAsset::A_NOTE
        ];
        $result->from([$as => $tbl], $cols);
        return $result;
    }

    protected function getQueryTotal()
    {
        /* get query to select items */
        /** @var \Magento\Framework\DB\Select $result */
        $result = $this->getQueryItems();
        /* ... then replace "columns" part with own expression */
        $value = 'COUNT(' . self::AS_TYP_ASSET . '.' . ETypeAsset::A_ID . ')';

        /**
         * See method \Magento\Framework\DB\Select\ColumnsRenderer::render:
         */
        /**
         * if ($column instanceof \Zend_Db_Expr) {...}
         */
        $exp = new \Praxigento\Core\App\Repo\Query\Expression($value);
        /**
         *  list($correlationName, $column, $alias) = $columnEntry;
         */
        $entry = [null, $exp, null];
        $cols = [$entry];
        $result->setPart('columns', $cols);
        return $result;
    }
}


<?php
/**
 * Copyright 2017 NanoSector
 *
 * You should have received a copy of the MIT license with the project.
 * See the LICENSE file for more information.
 */

namespace ValidationClosures;

class Utils
{
	/**
	 * @param \Closure $closure
	 *
	 * @return \Closure
	 */
	public static function invert(\Closure $closure): \Closure
	{
		return function ($value) use ($closure)
		{
			return !$closure($value);
		};
	}

	/**
	 * @param \Closure $closure1
	 * @param \Closure $closure2
	 *
	 * @return \Closure
	 */
	public static function merge(\Closure $closure1, \Closure $closure2): \Closure
	{
		return function ($value) use ($closure1, $closure2)
		{
			return $closure1($value) || $closure2($value);
		};
	}

	/**
	 * @param \Closure $closure1
	 * @param \Closure $closure2
	 *
	 * @return \Closure
	 */
	public static function both(\Closure $closure1, \Closure $closure2): \Closure
	{
		return function ($value) use ($closure1, $closure2)
		{
			return $closure1($value) && $closure2($value);
		};
	}

	/**
	 * @param \Closure $closure
	 * @param array $values
	 *
	 * @return bool
	 */
	public static function validateArray(\Closure $closure, array $values): bool
	{
		foreach ($values as $value)
			if (!$closure($value))
				return false;

		return true;
	}

    /**
     * @param callable $callable
     *
     * @return \Closure
     */
    public static function createClosureFromCallable(callable $callable)
    {
        // Closure::fromCallable was introduced in PHP 7.1.0
        if (version_compare(PHP_VERSION, '7.1.0', '>='))
            return \Closure::fromCallable($callable);

        return function ($value) use ($callable)
        {
            return $callable($value);
        };
	}
}


<?php

namespace Praxigento\Accounting\Ui\DataProvider\Grid\Transaction;

use Praxigento\Accounting\Config as Cfg;
use Praxigento\Accounting\Repo\Data\Account as EAccount;
use Praxigento\Accounting\Repo\Data\Log\Change\Admin as ELogAdmin;
use Praxigento\Accounting\Repo\Data\Log\Change\Customer as ELogCustomer;
use Praxigento\Accounting\Repo\Data\Transaction as ETransaction;
use Praxigento\Accounting\Repo\Data\Type\Asset as ETypeAsset;
use Praxigento\Core\App\Repo\Query\Expression as AnExpress;

class Query
    extends \Praxigento\Core\App\Ui\DataProvider\Grid\Query\Builder
{

    /**#@+ Tables aliases for external usage ('camelCase' naming) */
    const AS_ACC_CREDIT = 'acrd';
    const AS_ACC_DEBIT = 'adbt';
    const AS_ASSET = 'ass';
    const AS_BY_ADMIN = 'admin';
    const AS_BY_CUST = 'cust';
    const AS_CUST_CREDIT = 'ccrd';
    const AS_CUST_DEBIT = 'cdbt';
    const AS_LOG_ADMIN = 'logAdmin';
    const AS_LOG_CUST = 'logCust';
    const AS_TRANS = 'trn';
    /**#@- */

    /**#@+
     * Aliases for data attributes.
     */
    const A_ASSET = 'asset';
    const A_CREDIT_CUST_ID = 'creditCustId';
    const A_CREDIT_CUST_NAME = 'creditCustName';
    const A_CUSTOMER = 'customer';
    const A_DATE_APPLIED = 'dateApplied';
    const A_DEBIT_CUST_ID = 'debitCustId';
    const A_DEBIT_CUST_NAME = 'debitCustName';
    const A_ID_OPER = 'operId';
    const A_ID_TRANS = 'transId';
    const A_NOTE = 'note';
    const A_USER = 'user';
    const A_VALUE = 'value';

    private function expressByCust()
    {
        $first = self::AS_BY_CUST . '.' . Cfg::E_CUSTOMER_A_FIRSTNAME;
        $last = self::AS_BY_CUST . '.' . Cfg::E_CUSTOMER_A_LASTNAME;
        $exp = "CONCAT($first,' ',$last)";
        $result = new AnExpress($exp);
        return $result;
    }

    private function expressCustCredit()
    {
        $first = self::AS_CUST_CREDIT . '.' . Cfg::E_CUSTADDR_A_FIRSTNAME;
        $last = self::AS_CUST_CREDIT . '.' . Cfg::E_CUSTADDR_A_LASTNAME;
        $exp = "CONCAT($first,' ',$last)";
        $result = new AnExpress($exp);
        return $result;
    }

    private function expressCustDebit()
    {
        $first = self::AS_CUST_DEBIT . '.' . Cfg::E_CUSTADDR_A_FIRSTNAME;
        $last = self::AS_CUST_DEBIT . '.' . Cfg::E_CUSTADDR_A_LASTNAME;
        $exp = "CONCAT($first,' ',$last)";
        $result = new AnExpress($exp);
        return $result;
    }

    /**#@- */

    protected function getMapper()
    {
        $expDebit = $this->expressCustDebit();
        $expCredit = $this->expressCustCredit();
        $expCust = $this->expressByCust();
        if (is_null($this->mapper)) {
            $map = [
                self::A_ASSET => self::AS_ASSET . '.' . ETypeAsset::A_CODE,
                self::A_CREDIT_CUST_ID => self::AS_CUST_CREDIT . '.' . Cfg::E_CUSTOMER_A_ENTITY_ID,
                self::A_CREDIT_CUST_NAME => $expCredit,
                self::A_CUSTOMER => $expCust,
                self::A_DATE_APPLIED => self::AS_TRANS . '.' . ETransaction::A_DATE_APPLIED,
                self::A_DEBIT_CUST_ID => self::AS_CUST_DEBIT . '.' . Cfg::E_CUSTOMER_A_ENTITY_ID,
                self::A_DEBIT_CUST_NAME => $expDebit,
                self::A_ID_OPER => self::AS_TRANS . '.' . ETransaction::A_OPERATION_ID,
                self::A_ID_TRANS => self::AS_TRANS . '.' . ETransaction::A_ID,
                self::A_NOTE => self::AS_TRANS . '.' . ETransaction::A_NOTE,
                self::A_USER => self::AS_BY_ADMIN . '.' . Cfg::E_ADMIN_USER_A_USERNAME,
                self::A_VALUE => self::AS_TRANS . '.' . ETransaction::A_VALUE
            ];
            $this->mapper = new \Praxigento\Core\App\Repo\Query\Criteria\Def\Mapper($map);
        }
        $result = $this->mapper;
        return $result;
    }

    protected function getQueryItems()
    {
        $result = $this->conn->select();
        /* define tables aliases for internal usage (in this method) */
        $asAccCredit = self::AS_ACC_CREDIT;
        $asAccDebit = self::AS_ACC_DEBIT;
        $asAsset = self::AS_ASSET;
        $asByAdmin = self::AS_BY_ADMIN;
        $asByCust = self::AS_BY_CUST;
        $asCustCredit = self::AS_CUST_CREDIT;
        $asCustDebit = self::AS_CUST_DEBIT;
        $asLogAdmin = self::AS_LOG_ADMIN;
        $asLogCust = self::AS_LOG_CUST;
        $asTrans = self::AS_TRANS;

        /* SELECT FROM prxgt_acc_transaction */
        $tbl = $this->resource->getTableName(ETransaction::ENTITY_NAME);
        $as = $asTrans;
        $cols = [
            self::A_ID_TRANS => ETransaction::A_ID,
            self::A_ID_OPER => ETransaction::A_OPERATION_ID,
            self::A_DATE_APPLIED => ETransaction::A_DATE_APPLIED,
            self::A_VALUE => ETransaction::A_VALUE,
            self::A_NOTE => ETransaction::A_NOTE
        ];
        $result->from([$as => $tbl], $cols);

        /* LEFT JOIN prxgt_acc_account as debit */
        $tbl = $this->resource->getTableName(EAccount::ENTITY_NAME);
        $as = $asAccDebit;
        $cond = $asAccDebit . '.' . EAccount::A_ID . '=' . $asTrans . '.' . ETransaction::A_DEBIT_ACC_ID;
        $cols = [];
        $result->joinLeft([$as => $tbl], $cond, $cols);

        /* LEFT JOIN customer_entity as debit */
        $tbl = $this->resource->getTableName(Cfg::ENTITY_MAGE_CUSTOMER);
        $as = $asCustDebit;
        $cond = $asCustDebit . '.' . Cfg::E_CUSTOMER_A_ENTITY_ID . '=' . $asAccDebit . '.' . EAccount::A_CUST_ID;
        $exp = $this->expressCustDebit();
        $cols = [
            self::A_DEBIT_CUST_ID => Cfg::E_CUSTOMER_A_ENTITY_ID,
            self::A_DEBIT_CUST_NAME => $exp
        ];
        $result->joinLeft([$as => $tbl], $cond, $cols);

        /* LEFT JOIN prxgt_acc_account as credit */
        $tbl = $this->resource->getTableName(EAccount::ENTITY_NAME);
        $as = $asAccCredit;
        $cond = $asAccCredit . '.' . EAccount::A_ID . '=' . $asTrans . '.' . ETransaction::A_CREDIT_ACC_ID;
        $cols = [];
        $result->joinLeft([$as => $tbl], $cond, $cols);

        /* LEFT JOIN customer_entity as credit */
        $tbl = $this->resource->getTableName(Cfg::ENTITY_MAGE_CUSTOMER);
        $as = $asCustCredit;
        $cond = $asCustCredit . '.' . Cfg::E_CUSTOMER_A_ENTITY_ID . '=' . $asAccCredit . '.' . EAccount::A_CUST_ID;
        $exp = $this->expressCustCredit();
        $cols = [
            self::A_CREDIT_CUST_ID => Cfg::E_CUSTOMER_A_ENTITY_ID,
            self::A_CREDIT_CUST_NAME => $exp
        ];
        $result->joinLeft([$as => $tbl], $cond, $cols);

        /* LEFT JOIN prxgt_acc_type_asset */
        $tbl = $this->resource->getTableName(ETypeAsset::ENTITY_NAME);
        $as = $asAsset;
        $cond = $asAsset . '.' . ETypeAsset::A_ID . '=' . $asAccDebit . '.' . EAccount::A_ASSET_TYPE_ID;
        $cols = [
            self::A_ASSET => ETypeAsset::A_CODE
        ];
        $result->joinLeft([$as => $tbl], $cond, $cols);

        /* LEFT JOIN prxgt_acc_log_change_admin */
        $tbl = $this->resource->getTableName(ELogAdmin::ENTITY_NAME);
        $as = $asLogAdmin;
        $cond = "$as." . ELogAdmin::A_OPER_REF . '=' . $asTrans . '.' . ETransaction::A_OPERATION_ID;
        $cols = [];
        $result->joinLeft([$as => $tbl], $cond, $cols);

        /* LEFT JOIN admin_user */
        $tbl = $this->resource->getTableName(Cfg::ENTITY_MAGE_ADMIN_USER);
        $as = $asByAdmin;
        $cond = "$as." . Cfg::E_ADMIN_USER_A_USER_ID . '=' . $asLogAdmin . '.' . ELogAdmin::A_USER_REF;
        $cols = [
            self::A_USER => Cfg::E_ADMIN_USER_A_USERNAME
        ];
        $result->joinLeft([$as => $tbl], $cond, $cols);

        /* LEFT JOIN prxgt_acc_log_change_customer */
        $tbl = $this->resource->getTableName(ELogCustomer::ENTITY_NAME);
        $as = $asLogCust;
        $cond = "$as." . ELogCustomer::A_OPER_REF . '=' . $asTrans . '.' . ETransaction::A_OPERATION_ID;
        $cols = [];
        $result->joinLeft([$as => $tbl], $cond, $cols);

        /* LEFT JOIN customer_entity */
        $tbl = $this->resource->getTableName(Cfg::ENTITY_MAGE_CUSTOMER);
        $as = $asByCust;
        $cond = "$as." . Cfg::E_CUSTOMER_A_ENTITY_ID . '=' . $asLogCust . '.' . ELogCustomer::A_CUST_REF;
        $exp = $this->expressByCust();
        $cols = [
            self::A_CUSTOMER => $exp
        ];
        $result->joinLeft([$as => $tbl], $cond, $cols);

        return $result;
    }

    protected function getQueryTotal()
    {
        /* get query to select items */
        /** @var \Magento\Framework\DB\Select $result */
        $result = $this->getQueryItems();
        /* ... then replace "columns" part with own expression */
        $value = 'COUNT(' . self::AS_TRANS . '.' . ETransaction::A_ID . ')';

        /**
         * See method \Magento\Framework\DB\Select\ColumnsRenderer::render:
         */
        /**
         * if ($column instanceof \Zend_Db_Expr) {...}
         */
        $exp = new AnExpress($value);
        /**
         *  list($correlationName, $column, $alias) = $columnEntry;
         */
        $entry = [null, $exp, null];
        $cols = [$entry];
        $result->setPart('columns', $cols);
        return $result;
    }
}


<?php

namespace Interpro\ImageAggr;

use Interpro\Core\Contracts\Taxonomy\TypesForecastList;
use Interpro\Core\Taxonomy\Enum\TypeRank;
use Interpro\Core\Taxonomy\Manifests\ATypeManifest;
use Interpro\ImageAggr\Exception\ImageAggrException;

class ModImagesConfigInterpreter
{
    private $forecastList;

    public function __construct(TypesForecastList $forecastList)
    {
        $this->forecastList = $forecastList;
    }

    /**
     * @param array $config
     *
     * @return \Interpro\Core\Taxonomy\Manifests\ATypeManifest
     */
    public function interpretConfig(array $config)
    {
        $owns = [
            'name' => 'string',
            'title' => 'string',
        ];

        //Добавляем имена картинок
        foreach($config as $image_name)
        {
            if(!is_string($image_name))
            {
                throw new ImageAggrException('Имена в конфигурации блока модифицирования картинок должны быть заданы строкой!');
            }
            else
            {
                $owns[$image_name] = 'image';
            }
        }

        return new ATypeManifest('modimages', 'modimages', TypeRank::BLOCK, $owns, []);
    }

}


<?php
/**
 * Authors: Alex Gusev <alex@flancer64.com>
 * Since: 2019
 */

namespace Praxigento\Accounting\Service\Account\Balance\Validate\A\ProcessOneAsset\A\Repo\Query;

use Praxigento\Accounting\Repo\Data\Account as EAcc;
use Praxigento\Accounting\Repo\Data\Transaction as ETran;

class GetTransactions
    extends \Praxigento\Core\App\Repo\Query\Builder
{
    /** Tables aliases for external usage ('camelCase' naming) */
    const AS_ACC = 'acc';
    const AS_TRAN = 'trn';

    /** Columns/expressions aliases for external usage ('camelCase' naming) */
    const A_ACC_ID_CREDIT = 'accIdCredit';
    const A_ACC_ID_DEBIT = 'accIdDebit';
    const A_AMOUNT = 'amount';

    /** Bound variables names ('camelCase' naming) */
    const BND_ASSET_TYPE_ID = 'assetTypeId';
    const BND_DATE_FROM = 'dateFrom';

    /** Entities are used in the query */
    const E_ACC = EAcc::ENTITY_NAME;
    const E_TRAN = ETran::ENTITY_NAME;

    /**
     *SELECT
     * `trn`.`debit_acc_id` AS `accIdDebit`,
     * `trn`.`credit_acc_id` AS `accIdCredit`,
     * `trn`.`value` AS `amount`
     * FROM
     * `prxgt_acc_transaction` AS `trn`
     * LEFT JOIN `prxgt_acc_account` AS `acc` ON
     * acc.id = trn.debit_acc_id
     * WHERE
     * ((acc.asset_type_id =:assetTypeId)
     * AND (trn.date_applied >=:dateFrom))
     */
    public function build(\Magento\Framework\DB\Select $source = null)
    {
        /* this is root query builder (started from SELECT) */
        $result = $this->conn->select();

        /* define tables aliases for internal usage (in this method) */
        $asAcc = self::AS_ACC;
        $asTran = self::AS_TRAN;

        /* FROM prxgt_acc_transaction */
        $tbl = $this->resource->getTableName(self::E_TRAN);    // name with prefix
        $as = $asTran;
        $cols = [
            self::A_ACC_ID_DEBIT => ETran::A_DEBIT_ACC_ID,
            self::A_ACC_ID_CREDIT => ETran::A_CREDIT_ACC_ID,
            self::A_AMOUNT => ETran::A_VALUE
        ];
        $result->from([$as => $tbl], $cols);    // standard names for the variables

        /* LEFT JOIN prxgt_acc_account */
        $tbl = $this->resource->getTableName(self::E_ACC);
        $as = $asAcc;
        $cols = [];
        $cond = "$as." . EAcc::A_ID . "=$asTran." . ETran::A_DEBIT_ACC_ID;
        $result->joinLeft([$as => $tbl], $cond, $cols);

        /* query tuning */
        $byAsset = "$asAcc." . EAcc::A_ASSET_TYPE_ID . "=:" . self::BND_ASSET_TYPE_ID;
        $byDate = "$asTran." . ETran::A_DATE_APPLIED . ">=:" . self::BND_DATE_FROM;
        $result->where("($byAsset) AND ($byDate)");

        return $result;
    }

}


<?php
/**
 * Authors: Alex Gusev <alex@flancer64.com>
 * Since: 2018
 */

namespace Praxigento\Accounting\Service\Account\Balance\LastDate\A\Repo\Query;

use Praxigento\Accounting\Repo\Data\Account as EAcc;
use Praxigento\Accounting\Repo\Data\Balance as EBal;

/**
 * Get base query to select maximal date for existing balances by asset type or account IDs.
 * Add appropriate 'where' clauses after build.
 */
class GetMaxDateBalance
    extends \Praxigento\Core\App\Repo\Query\Builder
{
    /** Tables aliases for external usage ('camelCase' naming) */
    const AS_ACC = 'acc';
    const AS_BAL = 'bal';

    /** Columns/expressions aliases for external usage ('camelCase' naming) */
    const A_MAX_DATE = 'maxDate';

    /** Entities are used in the query */
    const E_ACC = EAcc::ENTITY_NAME;
    const E_BAL = EBal::ENTITY_NAME;

    /**
     * Get base query to select maximal date for existing balances by asset type or account IDs.
     * Add appropriate 'where' clauses after build.
     *
     * SELECT
     * MAX(b.`date`) as maxDate
     * FROM
     * prxgt_acc_balance as b
     * LEFT JOIN prxgt_acc_account AS a ON
     * a.id = b.account_id
     *
     * @inheritdoc
     */
    public function build(\Magento\Framework\DB\Select $source = null)
    {
        /* this is root query builder (started from SELECT) */
        $result = $this->conn->select();

        /* define tables aliases for internal usage (in this method) */
        $asAcc = self::AS_ACC;
        $asBal = self::AS_BAL;

        /* FROM prxgt_acc_balance */
        $tbl = $this->resource->getTableName(self::E_BAL);    // name with prefix
        $as = $asBal;    // alias for 'current table' (currently processed in this block of code)
        $exp = $this->expMax();
        $cols = [
            self::A_MAX_DATE => $exp
        ];
        $result->from([$as => $tbl], $cols);    // standard names for the variables

        /* LEFT JOIN prxgt_acc_account */
        $tbl = $this->resource->getTableName(self::E_ACC);
        $as = $asAcc;
        $cols = [];
        /* bind account to transaction as debit account to bind asset type below (credit acc. has the same type) */
        $cond = "$as." . EAcc::A_ID . "=$asBal." . EBal::A_ACCOUNT_ID;
        $result->joinLeft([$as => $tbl], $cond, $cols);

        return $result;
    }

    private function expMax()
    {
        $value = 'MAX(' . self::AS_BAL . '.' . EBal::A_DATE . ")";
        $result = new \Praxigento\Core\App\Repo\Query\Expression($value);
        return $result;
    }
}


<?php

namespace ContentScheduler;

class Unpublish
{
    public function __construct()
    {
        add_action('post_submitbox_misc_actions', array($this, 'setupUi'));
        add_action('save_post', array($this, 'saveUnpublish'));
        add_action('unpublish_post', array($this, 'unpublishPost'), 10, 2);
    }

    /**
     * Does the actual unpublishing, called from cron
     * @param  integer $postId The post to unpublisch
     * @param  string $action  What to do with it (trash or draft)
     * @return boolean
     */
    public function unpublishPost($postId, $action = 'trash')
    {
        $postStatus = get_post_status($postId);
        if (!in_array($postStatus, array('publish', 'private', 'password', 'draft'))) {
            return false;
        }

        switch ($action) {
            case 'draft':
                wp_update_post(array(
                    'ID' => (int)$postId,
                    'post_status' => 'draft'
                ));
                break;

            default:
                wp_trash_post($postId);
                break;
        }

        return true;
    }

    /**
     * Saves the unpublish settings and sets up scheduled task
     * @param  integer $postId Post id
     * @return void
     */
    public function saveUnpublish($postId)
    {
        // Do not proceed if post is a revision
        if (wp_is_post_revision($postId)) {
            return false;
        }

        $args = array(
            'post_id' => $postId
        );

        wp_unschedule_event(wp_next_scheduled('unpublish_post', $args), 'unpublish_post', $args);

        if (!isset($_POST['unpublish-active']) || $_POST['unpublish-active'] != 'true') {
            delete_post_meta($postId, 'unpublish-date');
            delete_post_meta($postId, 'unpublish-action');

            return;
        }

        $offset = get_option('gmt_offset');

        if ($offset > -1) {
            $offset = '-' . $offset;
        } else {
            $offset = '+' . (1 * abs($offset));
        }

        $unpublishDate = $_POST['unpublish-aa'] . '-' . $_POST['unpublish-mm'] . '-' . $_POST['unpublish-jj'] . ' ' . $_POST['unpublish-hh'] . ':' . $_POST['unpublish-mn'] . ':00';
        $unpublishTime = strtotime($offset . ' hours', strtotime($unpublishDate));

        $unpubParts = array(
            'aa' => $_POST['unpublish-aa'],
            'mm' => $_POST['unpublish-mm'],
            'jj' => $_POST['unpublish-jj'],
            'hh' => $_POST['unpublish-hh'],
            'mn' => $_POST['unpublish-mn']
        );

        $action = isset($_POST['unpublish-action']) && !empty($_POST['unpublish-action']) ? $_POST['unpublish-action'] : 'trash';

        update_post_meta($postId, 'unpublish-date', $unpubParts);
        update_post_meta($postId, 'unpublish-action', $action);

        wp_schedule_single_event($unpublishTime, 'unpublish_post', array(
            'post_id' => $postId,
            'action' => $action
        ));
    }

    /**
     * The UI for the unpublish section
     * @return void
     */
    public function setupUi($post)
    {
        $activated = $this->initScheduler($post->ID);

        if ($activated) {
            include CONTENTSCHEDULER_TEMPLATE_PATH . '/unpublish.php';
        }
    }

    /**
     * Check if current post type is activated in settings
     * @param  int|string $postId Current post id
     * @return bool
     */
    public function initScheduler($postId) : bool
    {
        $active = true;
        $post_types = get_field('content_scheduler_posttypes', 'option');

        if (is_array($post_types) && !empty($post_types)) {
            $current = get_post_type($postId);
            $active = in_array($current, $post_types);
        }

        return $active;
    }
}


<?php

namespace Onoi\Tesa;

use Onoi\Tesa\Tokenizer\Tokenizer;
use Onoi\Tesa\Synonymizer\Synonymizer;
use Onoi\Tesa\StopwordAnalyzer\StopwordAnalyzer;
use RuntimeException;

/**
 * @license GNU GPL v2+
 * @since 0.1
 *
 * @author mwjames
 */
class Sanitizer {

	const WHITELIST = 'WHITELIST';
	const MIN_LENGTH = 'MIN_LENGTH';

	/**
	 * Any change to the content of its data files should be reflected in a
	 * version change (the version number does not necessarily correlate with
	 * the library version)
	 */
	const VERSION = '0.2';

	/**
	 * @var string
	 */
	private $string = '';

	/**
	 * @var array
	 */
	private $whiteList = array();

	/**
	 * @var array
	 */
	private $minLength = 3;

	/**
	 * @since 0.1
	 *
	 * @param string $string
	 */
	public function __construct( $string = '' ) {
		$this->setText( $string );
	}

	/**
	 * @since 0.1
	 *
	 * @param string $name
	 * @param mixed $value
	 */
	public function setOption( $name, $value ) {

		if ( $name === self::WHITELIST && is_array( $value ) && $value !== array() ) {
			$this->whiteList = array_fill_keys( $value, true );
		}

		if ( $name === self::MIN_LENGTH ) {
			$this->minLength = (int)$value;
		}
	}

	/**
	 * @since 0.1
	 *
	 * @param string $string
	 */
	public function setText( $string ) {
		$this->string = $string;
	}

	/**
	 * @since 0.1
	 *
	 * @param integer $flag
	 */
	public function applyTransliteration( $flag = Transliterator::DIACRITICS ) {
		$this->string = Normalizer::applyTransliteration( $this->string, $flag );
	}

	/**
	 * @see Localizer::convertDoubleWidth
	 *
	 * @since 0.1
	 *
	 * @param integer $flag
	 */
	public function convertDoubleWidth() {
		$this->string = Normalizer::convertDoubleWidth( $this->string );
	}

	/**
	 * @since 0.1
	 *
	 * @param Tokenizer $tokenizer
	 * @param StopwordAnalyzer $stopwordAnalyzer
	 *
	 * @return string
	 */
	public function sanitizeWith( Tokenizer $tokenizer, StopwordAnalyzer $stopwordAnalyzer, Synonymizer $synonymizer ) {

		// Treat non-words tokenizers (Ja,Zh*) differently
		$minLength = $tokenizer->isWordTokenizer() ? $this->minLength : 1;

		$words = $tokenizer->tokenize( $this->string );

		if ( !$words || !is_array( $words ) ) {
			return $this->string;
		}

		$index = array();
		$pos = 0;

		foreach ( $words as $key => $word ) {

			$word = $synonymizer->synonymize( $word );

			// If it is not an exemption and less than the required minimum length
			// or identified as stop word it is removed
			if ( !isset( $this->whiteList[$word] ) && ( mb_strlen( $word ) < $minLength || $stopwordAnalyzer->isStopWord( $word ) ) ) {
				continue;
			}

			// Simple proximity, check for same words appearing next to each other
			if ( isset( $index[$pos-1] ) && $index[$pos-1] === $word ) {
				continue;
			}

			$index[] = trim( $word );
			$pos++;
		}

		return implode( ' ' , $index );
	}

	/**
	 * @since 0.1
	 */
	public function toLowercase() {
		$this->string = Normalizer::toLowercase( $this->string );
	}

	/**
	 * @since 0.1
	 *
	 * @param integer $length
	 */
	public function reduceLengthTo( $length ) {
		$this->string = Normalizer::reduceLengthTo( $this->string, $length );
	}

	/**
	 * @see http://www.phpwact.org/php/i18n/utf-8#str_replace
	 * @since 0.1
	 *
	 * @param string $search
	 * @param string $replace
	 */
	public function replace( $search, $replace ) {
		$this->string = str_replace( $search, $replace, $this->string );
	}

	/**
	 * @since 0.1
	 *
	 * @return string
	 */
	public function __toString() {
		return $this->string;
	}

}


<?php

namespace ElfSundae\Laravel\Api;

class Token
{
    /**
     * The Client instance.
     *
     * @var \ElfSundae\Laravel\Api\Client
     */
    protected $client;

    /**
     * Constructor.
     *
     * @param  \ElfSundae\Laravel\Api\Client  $client
     */
    public function __construct(Client $client)
    {
        $this->client = $client;
    }

    /**
     * Get the Client instance.
     *
     * @return \ElfSundae\Laravel\Api\Client
     */
    public function getClient()
    {
        return $this->client;
    }

    /**
     * Set the Client instance.
     *
     * @param  \ElfSundae\Laravel\Api\Client  $client
     */
    public function setClient(Client $client)
    {
        $this->client = $client;
    }

    /**
     * Generate an api token.
     *
     * @param  string  $key
     * @param  string  $secret
     * @param  string|int  $time
     * @return string|null
     */
    public function generate($key, $secret, $time)
    {
        if ($key && $secret && $time) {
            return substr(md5($key.$secret.$time), 10, 20);
        }
    }

    /**
     * Generate an api token for the given app key.
     *
     * @param  string  $key
     * @param  string|int  $time
     * @return string|null
     */
    public function generateForKey($key, $time)
    {
        if ($secret = $this->client->getAppSecretForKey($key)) {
            return $this->generate($key, $secret, $time);
        }
    }

    /**
     * Verify an api token.
     *
     * @param  string  $token
     * @param  string  $key
     * @param  string|int  $time
     * @return bool
     */
    public function verify($token, $key, $time)
    {
        return $token && $key && $time && $token === $this->generateForKey($key, $time);
    }

    /**
     * Generate a token data array.
     *
     * @param  string  $key
     * @param  string  $secret
     * @param  string|int|null  $time
     * @return array
     */
    public function generateData($key, $secret, $time = null)
    {
        $time = $time ?: time();
        $token = $this->generate($key, $secret, $time);

        return $token ? compact('key', 'time', 'token') : [];
    }

    /**
     * Generate a token data array.
     *
     * @param  string  $key
     * @param  string|int|null  $time
     * @return array
     */
    public function generateDataForKey($key, $time = null)
    {
        if ($secret = $this->client->getAppSecretForKey($key)) {
            return $this->generateData($key, $secret, $time);
        }

        return [];
    }

    /**
     * Generate HTTP headers with a new token.
     *
     * @param  string  $appKey
     * @param  string|int|null  $time
     * @return array
     */
    public function generateHttpHeaders($appKey, $time = null)
    {
        $headers = [];

        foreach ($this->generateDataForKey($appKey, $time) as $key => $value) {
            $headers['X-API-'.strtoupper($key)] = $value;
        }

        return $headers;
    }

    /**
     * Generate query data with a new token.
     *
     * @param  string  $appKey
     * @param  string|int|null  $time
     * @return array
     */
    public function generateQueryData($appKey, $time = null)
    {
        $query = [];

        foreach ($this->generateDataForKey($appKey, $time) as $key => $value) {
            $query['_'.$key] = $value;
        }

        return $query;
    }

    /**
     * Generate query string with a new token.
     *
     * @param  string  $appKey
     * @param  string|int|null  $time
     * @return string
     */
    public function generateQueryString($appKey, $time = null)
    {
        return http_build_query($this->generateQueryData($appKey, $time));
    }
}


<?php

namespace Onoi\Tesa\Tokenizer;

/**
 * @license GNU GPL v2+
 * @since 0.1
 *
 * @author mwjames
 */
class GenericRegExTokenizer implements Tokenizer {

	/**
	 * @var Tokenizer
	 */
	private $tokenizer;

	/**
	 * @var string
	 */
	private $patternExemption = '';

	/**
	 * @since 0.1
	 *
	 * @param Tokenizer|null $tokenizer
	 */
	public function __construct( Tokenizer $tokenizer = null ) {
		$this->tokenizer = $tokenizer;
	}

	/**
	 * @since 0.1
	 *
	 * {@inheritDoc}
	 */
	public function setOption( $name, $value ) {

		if ( $this->tokenizer !== null ) {
			$this->tokenizer->setOption( $name, $value );
		}

		if ( $name === self::REGEX_EXEMPTION ) {
			$this->patternExemption = $value;
		}
	}

	/**
	 * @since 0.1
	 *
	 * {@inheritDoc}
	 */
	public function isWordTokenizer() {
		return $this->tokenizer !== null ? $this->tokenizer->isWordTokenizer() :true;
	}

	/**
	 * @since 0.1
	 *
	 * @param string $string
	 *
	 * @return array|false
	 */
	public function tokenize( $string ) {

		if ( $this->tokenizer !== null ) {
			$string = implode( " ", $this->tokenizer->tokenize( $string ) );
		}

		// (?<=\p{L})(?=\p{N}) to split alphanumeric and numeric

		$pattern = str_replace(
			$this->patternExemption,
			'',
			'([\s\-_,:;?!%\'\|\/\(\)\[\]{}<>\r\n"]|(?<!\d)\.(?!\d)|(?<=\p{L})(?=\p{N}))'
		);

		$result = preg_split( '/' . $pattern . '/u', $string, null, PREG_SPLIT_NO_EMPTY );

		if ( $result === false ) {
			$result = array();
		}

		return $result;
	}

}