<?php
/**
 *
 * PHP version >= 7.1
 *
 * @package andydune/array-container
 * @link  https://github.com/AndyDune/ArrayContainer for the canonical source repository
 * @license   http://www.opensource.org/licenses/mit-license.html  MIT License
 * @author Andrey Ryzhov  <info@rznw.ru>
 * @copyright 2019 Andrey Ryzhov
 */

namespace AndyDune\ArrayContainer;

use AndyDune\ArrayContainer\Action\AbstractAction;

class ArrayContainer implements \ArrayAccess
{
    protected $array = [];
    protected $defaultValue = null;

    protected $filters = [];

    /**
     * @var null|AbstractAction
     */
    protected $action = null;

    public function __construct($array = [])
    {
        $this->array = $array;
    }

    /**
     * Set value to return if no key exist within source array.
     *
     * @param mixed $value
     * @return $this
     */
    public function setDefaultValue($value)
    {
        $this->defaultValue = $value;
        return $this;
    }

    /**
     * Set strategy pattern action for modification array.
     * Action callable object resieves whole array in container and return array ro replace.
     *
     * @param AbstractAction $action
     * @return $this
     */
    public function setAction(AbstractAction $action)
    {
        $this->action = $action;
        $this->action->setArrayContainer($this);
        return $this;
    }

    /**
     * @param array ...$params
     * @return mixed
     */
    public function executeAction(...$params)
    {
        return $this->action->execute(...$params);
    }

    /**
     * Returns encapsulated array.
     *
     * @return array
     */
    public function getArrayCopy()
    {
        return $this->array;
    }

    /**
     * @param $array
     * @return $this
     */
    public function setArray($array)
    {
        $this->array = $array;
        return $this;
    }

    /**
     * Add filter.
     * There are may be several filters.
     *
     * @param $filter
     * @return $this
     */
    public function addFilter($filter)
    {
        $this->filters[] = $filter;
        return $this;
    }

    /**
     * Access to value if source array is nested.
     *
     * @param $keyString
     * @param null $default default value if no nested keys has been matched
     * @param string $separator
     * @return array|mixed|null
     */
    public function getNested($keyString, $default = null, $separator = '.')
    {
        $keys = explode($separator, $keyString);
        $data = $this->array;
        foreach ($keys as $key) {
            if(!is_array($data) or !array_key_exists($key, $data)) {
                return $default;
            }
            $data = $data[$key];
        }
        return $data;
    }

    public function has($offset)
    {
        return array_key_exists($offset, $this->array);
    }

    public function get($offset)
    {
        if (array_key_exists($offset, $this->array)) {
            return $this->applyFilters($this->array[$offset], $offset);
        }
        return $this->defaultValue;
    }

    public function set($offset, $value)
    {
        $this->array[$offset] = $value;
        return $this;
    }

    /**
     * It applies filter function to requested value of array.
     *
     * @param $value
     * @param $key
     * @return mixed
     */
    protected function applyFilters($value, $key)
    {
        foreach ($this->filters as $filter) {
            $value = $filter($value, $key);
        }
        return $value;
    }

    /**
     * Whether a offset exists
     * @link http://php.net/manual/en/arrayaccess.offsetexists.php
     * @param mixed $offset

     * An offset to check for.
     *

     * @return boolean true on success or false on failure.
     *

     *

     * The return value will be casted to boolean if non-boolean was returned.
     * @since 5.0.0
     */
    public function offsetExists($offset)
    {
        return array_key_exists($offset, $this->array);
    }

    /**
     * Offset to retrieve
     * @link http://php.net/manual/en/arrayaccess.offsetget.php
     * @param mixed $offset

     * The offset to retrieve.
     *

     * @return mixed Can return all value types.
     * @since 5.0.0
     */
    public function offsetGet($offset)
    {
        return $this->get($offset);
    }

    /**
     * Offset to set
     * @link http://php.net/manual/en/arrayaccess.offsetset.php
     * @param mixed $offset

     * The offset to assign the value to.
     *

     * @param mixed $value

     * The value to set.
     *

     * @return void
     * @since 5.0.0
     */
    public function offsetSet($offset, $value)
    {
        $this->array[$offset] = $value;
    }

    /**
     * Offset to unset
     * @link http://php.net/manual/en/arrayaccess.offsetunset.php
     * @param mixed $offset

     * The offset to unset.
     *

     * @return void
     * @since 5.0.0
     */
    public function offsetUnset($offset)
    {
        if (array_key_exists($offset, $this->array)) {
            unset($this->array[$offset]);
        }

    }
}


<?php

namespace RocknRoot\StrayFw\Database\Postgres\Query;

use InvalidArgumentException;
use RocknRoot\StrayFw\Database\Database;
use RocknRoot\StrayFw\Exception\AppException;
use RocknRoot\StrayFw\Exception\BadUse;
use RocknRoot\StrayFw\Logger;

/**
 * Representation class for PostgreSQL select queries.
 *
 * @author Nekith <nekith@errant-works.com>
 */
class Select extends Query
{
    /**
     * If true, will be executed on write server.
     *
     * @var bool
     */
    protected $isCritical;

    /**
     * Select clause.
     *
     * @var string|null
     */
    protected $select;

    /**
     * From clause.
     *
     * @var string
     */
    protected $from;

    /**
     * Where clause.
     *
     * @var Condition
     */
    protected $where;

    /**
     * Group by clause.
     *
     * @var string
     */
    protected $groupBy;

    /**
     * Having clause.
     *
     * @var Condition
     */
    protected $having;

    /**
     * Order by clause.
     *
     * @var string|null
     */
    protected $orderBy;

    /**
     * Distinct clause.
     *
     * @var string
     */
    protected $distinct;

    /**
     * Limit clause.
     *
     * @var int|null
     */
    protected $limit;

    /**
     * Offset clause.
     *
     * @var int|null
     */
    protected $offset;

    /**
     * Inner join table clause.
     *
     * @var array[]
     */
    protected $innerJoins;

    /**
     * Left outer join table clause.
     *
     * @var array[]
     */
    protected $leftOuterJoins;

    /**
     * Right outer join table clause.
     *
     * @var array[]
     */
    protected $rightOuterJoins;

    /**
     * Full outer join table clause.
     *
     * @var array[]
     */
    protected $fullOuterJoins;

    /**
     * Construct a new empty select query.
     *
     * @param string $database database name
     * @param bool   $critical if true, will be executed on write server
     */
    public function __construct($database, $critical = false)
    {
        parent::__construct($database);
        $this->isCritical = $critical;
        $this->innerJoins = array();
        $this->leftOuterJoins = array();
        $this->rightOuterJoins = array();
        $this->fullOuterJoins = array();
    }

    /**
     * Execute the constructed query.
     *
     * @throws AppException on SQL error
     * @return bool         true if the query is successfully executed
     */
    public function execute()
    {
        if ($this->statement == null) {
            $this->statement = Database::get($this->database)->{($this->isCritical === true ? 'getMasterLink' : 'getLink')}()->prepare($this->toSql());
        }
        foreach ($this->parameters as $name => $value) {
            $type = \PDO::PARAM_STR;
            if (is_int($value) === true) {
                $type = \PDO::PARAM_INT;
            } elseif (is_bool($value) === true) {
                $type = \PDO::PARAM_BOOL;
            } elseif (is_null($value) === true) {
                $type = \PDO::PARAM_NULL;
            }
            $this->statement->bindValue($name, $value, $type);
        }
        $result = $this->statement->execute();
        $this->errorInfo = $this->statement->errorInfo();
        if ($this->getErrorState() != '00000') {
            Logger::get()->error('select query failed : ' . $this->getErrorMessage() . ' (' . $this->toSql() . ')');
            if (constant('STRAY_ENV') === 'development') {
                throw new AppException('select query failed : ' . $this->getErrorMessage() . ' (' . $this->toSql() . ')');
            }
        }

        return $result;
    }

    /**
     * Get the next result row.
     *
     * @return bool|array result data or false if something went wrong
     */
    public function fetch()
    {
        if ($this->statement == null || $this->getErrorState() != '00000') {
            return false;
        }

        return $this->statement->fetch(\PDO::FETCH_ASSOC);
    }

    /**
     * Get all result rows.
     *
     * @return bool|array results data or false if something went wrong
     */
    public function fetchAll()
    {
        if ($this->statement == null || $this->getErrorState() != '00000') {
            return false;
        }

        return $this->statement->fetchAll(\PDO::FETCH_ASSOC);
    }

    /**
     * Extract the corresponding SQL code.
     *
     * @throws BadUse if from clause has not been defined
     * @return string generated SQL code
     */
    public function toSql()
    {
        $sql = 'SELECT ';
        if ($this->distinct != null) {
            $sql .= 'DISTINCT ON (' . $this->distinct . ') ';
        }
        $sql .= ($this->select != null ? $this->select : '*') . ' ';
        if (empty($this->from) === true) {
            throw new BadUse('from clause has not been defined (' . print_r($this, true) . ')');
        }
        $sql .= 'FROM ' . $this->from . ' ';

        foreach ($this->innerJoins as $join) {
            $sql .= 'INNER JOIN ' . $join['table'] . ' ON ' . $join['on']->toSql() . ' ';
        }
        foreach ($this->leftOuterJoins as $join) {
            $sql .= 'LEFT OUTER JOIN ' . $join['table'] . ' ON ' . $join['on']->toSql() . ' ';
        }
        foreach ($this->rightOuterJoins as $join) {
            $sql .= 'RIGHT OUTER JOIN ' . $join['table'] . ' ON ' . $join['on']->toSql() . ' ';
        }
        foreach ($this->fullOuterJoins as $join) {
            $sql .= 'FULL OUTER JOIN ' . $join['table'] . ' ON ' . $join['on']->toSql() . ' ';
        }

        if ($this->where != null) {
            $sql .= 'WHERE ' . $this->where->toSql() . ' ';
        }
        if ($this->groupBy != null) {
            $sql .= 'GROUP BY ' . $this->groupBy . ' ';
        }
        if ($this->having != null) {
            $sql .= 'HAVING ' . $this->having->toSql() . ' ';
        }
        if ($this->orderBy != null) {
            $sql .= 'ORDER BY ' . $this->orderBy . ' ';
        }
        if ($this->limit != null) {
            $sql .= 'LIMIT ' . $this->limit . ' ';
        }
        if ($this->offset != null) {
            $sql .= 'OFFSET ' . $this->offset . ' ';
        }

        return $sql;
    }

    /**
     * Set select clause.
     *
     * @param  array|string $select select clause
     * @return Select       this
     */
    public function select($select)
    {
        if (is_array($select) === true) {
            $this->select = '';
            foreach ($select as $key => $elem) {
                $this->select .= $elem;
                if (is_numeric($key) === false) {
                    $this->select .= ' AS ' . $key;
                }
                $this->select .= ', ';
            }
            $this->select = substr($this->select, 0, -2);
        } elseif (! is_string($select)) {
            throw new InvalidArgumentException(sprintf(
                'Argument 1 passed to %s must be an array or string!',
                __METHOD__
            ));
        } else {
            $this->select = $select;
        }

        return $this;
    }

    /**
     * Set from clause.
     *
     * @param  string $from table real name
     * @return Select this
     */
    public function from($from)
    {
        $this->from = $from;

        return $this;
    }

    /**
     * Set where clause.
     *
     * @param  Condition|mixed $where where clause
     * @return Select          this
     */
    public function where($where)
    {
        $this->where = ($where instanceof Condition ? $where : new Condition($where));

        return $this;
    }

    /**
     * Set group by clause.
     *
     * @param  array|string $groupBy group by clause
     * @return Select       this
     */
    public function groupBy($groupBy)
    {
        if (is_array($groupBy) === true) {
            $this->groupBy = implode(', ', $groupBy);
        } else {
            $this->groupBy = $groupBy;
        }

        return $this;
    }

    /**
     * Set having clause.
     *
     * @param  Condition|string $having having clause
     * @return Select           this
     */
    public function having($having)
    {
        $this->having = ($having instanceof Condition ? $having : new Condition($having));

        return $this;
    }

    /**
     * Set order by clause.
     *
     * @param  array|string $orderBy order by clause
     * @return Select       this
     */
    public function orderBy($orderBy)
    {
        if (is_array($orderBy) === true) {
            $this->orderBy = '';
            foreach ($orderBy as $key => $elem) {
                $this->orderBy .= $key . ' ' . $elem . ', ';
            }
            $this->orderBy = substr($this->orderBy, 0, -2);
        } else {
            $this->orderBy = $orderBy;
        }

        return $this;
    }

    /**
     * Set distinct on clause.
     *
     * @param  array|string $distinct distinct on clause
     * @return Select       this
     */
    public function distinct($distinct)
    {
        if (is_array($distinct) === true) {
            $this->distinct = implode(', ', $distinct);
        } else {
            $this->distinct = $distinct;
        }

        return $this;
    }

    /**
     * Set limit clause.
     *
     * @param  int|null $limit limit clause
     * @return Select this
     */
    public function limit(int $limit = null)
    {
        $this->limit = $limit;

        return $this;
    }

    /**
     * Set offset clause.
     *
     * @param  int|null $offset offset clause
     * @return Select this
     */
    public function offset(int $offset = null)
    {
        $this->offset = $offset;

        return $this;
    }

    /**
     * Add an inner join.
     *
     * @param  string                 $table foreign table real name
     * @param  Condition|array|string $on    join condition
     * @return Select                 this
     */
    public function addInnerJoin($table, $on)
    {
        $this->innerJoins[] = array(
            'table' => $table,
            'on' => ($on instanceof Condition ? $on : new Condition($on))
        );

        return $this;
    }

    /**
     * Add a left outer join.
     *
     * @param  string                 $table foreign table real name
     * @param  Condition|array|string $on    join condition
     * @return Select                 $this
     */
    public function addLeftOuterJoin($table, $on)
    {
        $this->leftOuterJoins[] = array(
            'table' => $table,
            'on' => ($on instanceof Condition ? $on : new Condition($on))
        );

        return $this;
    }

    /**
     * Add a right outer join.
     *
     * @param  string                 $table foreign table real name
     * @param  Condition|array|string $on    join condition
     * @return Select                 $this
     */
    public function addRightOuterJoin($table, $on)
    {
        $this->rightOuterJoins[] = array(
            'table' => $table,
            'on' => ($on instanceof Condition ? $on : new Condition($on))
        );

        return $this;
    }

    /**
     * Add a full outer join.
     *
     * @param  string                 $table foreign table real name
     * @param  Condition|array|string $on    join condition
     * @return Select                 $this
     */
    public function addFullOuterJoin($table, $on)
    {
        $this->fullOuterJoins[] = array(
            'table' => $table,
            'on' => ($on instanceof Condition ? $on : new Condition($on))
        );

        return $this;
    }
}


<?php

namespace RocknRoot\StrayFw\Http;

use RocknRoot\StrayFw\Console\Request;

/**
 * Console actions for Http namespace.
 *
 * @author Nekith <nekith@errant-works.com>
 */
class Console
{
    /**
     * List registered routes.
     *
     * @param Request $request current CLI request
     */
    public function routes(Request $request)
    {
        $table = new \cli\Table();
        $table->setHeaders([ 'Type', 'Subdomain', 'Method', 'Path', 'Action' ]);
        $rows = [];
        $routes = Http::getRoutes();
        usort($routes, function (array $a, array $b) {
            if ($a['subdomain'] != $b['subdomain']) {
                return strcmp($a['subdomain'], $b['subdomain']);
            }
            if ($a['path'] != $a['path']) {
                return strcmp($a['path'], $b['path']);
            }

            return strcmp($a['method'], $b['method']);
        });
        foreach ($routes as $route) {
            $rows[] = [
                $route['type'],
                $route['subdomain'],
                $route['method'],
                empty($route['uri']) === false ? '/' . ltrim(rtrim($route['uri'], '/'), '/') . $route['path'] : $route['path'],
                $route['action'][0] == '\\' ? $route['action'] : rtrim($route['namespace'], '\\') . '\\' . $route['action'],
            ];
        }
        $table->setRows($rows);
        $table->display();
    }
}


<?php

declare(strict_types=1);

/*
 * This file is part of the BkstgNoticeBoardBundle package.
 * (c) Luke Bainbridge <http://www.lukebainbridge.ca/>
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Bkstg\NoticeBoardBundle\Form;

use Bkstg\CoreBundle\Context\ProductionContextProviderInterface;
use Bkstg\NoticeBoardBundle\Entity\Post;
use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

class PostType extends AbstractType
{
    private $context;
    private $auth;

    /**
     * Create a new post form.
     *
     * @param ProductionContextProviderInterface $context The production context service.
     * @param AuthorizationCheckerInterface      $auth    The authorization checker service.
     */
    public function __construct(
        ProductionContextProviderInterface $context,
        AuthorizationCheckerInterface $auth
    ) {
        $this->context = $context;
        $this->auth = $auth;
    }

    /**
     * {@inheritdoc}
     *
     * @param FormBuilderInterface $builder The form builder.
     * @param array                $options The form options.
     *
     * @return void
     */
    public function buildForm(FormBuilderInterface $builder, array $options): void
    {
        $post = $options['data'];
        $builder
            ->add('body', CKEditorType::class, [
                'required' => false,
                'config' => ['toolbar' => 'basic'],
                'label' => 'post.form.body',
            ])
        ;

        // Add admin things if the user is an admin.
        if ($this->auth->isGranted('GROUP_ROLE_EDITOR', $this->context->getContext())) {
            $builder
                ->add('pinned', CheckboxType::class, [
                    'required' => false,
                    'label' => 'post.form.pinned',
                ])
                ->add('active', ChoiceType::class, [
                    // Show "unpublished" instead of active.
                    'choice_loader' => new CallbackChoiceLoader(function () use ($post) {
                        yield 'post.form.status_choices.active' => true;
                        if (!$post->isPublished()) {
                            yield 'post.form.status_choices.unpublished' => false;
                        } else {
                            yield 'post.form.status_choices.archived' => false;
                        }
                    }),
                    'label' => 'post.form.status',
                ])
                ->add('expiry', DateTimeType::class, [
                    'required' => false,
                    'time_widget' => 'single_text',
                    'date_widget' => 'single_text',
                    'label' => 'post.form.expiry',
                ])
            ;
        }
    }

    /**
     * {@inheritdoc}
     *
     * @param OptionsResolver $resolver The option resolver.
     *
     * @return void
     */
    public function configureOptions(OptionsResolver $resolver): void
    {
        $resolver->setDefaults([
            'translation_domain' => 'BkstgNoticeBoardBundle',
            'data_class' => Post::class,
        ]);
    }
}


<?php

namespace RocknRoot\StrayFw\Console;

use RocknRoot\StrayFw\Controllers;

/**
 * Bootstrapping class for CLI requests.
 *
 * @abstract
 *
 * @author Nekith <nekith@errant-works.com>
 */
abstract class Console
{
    /**
     * True if class has already been initialized.
     *
     * @static
     * @var bool
     */
    private static $isInit = false;

    /**
     * Current namespace prefix.
     *
     * @var string
     */
    protected static $namespace;

    /**
     * Registed routes.
     *
     * @var array[]
     */
    protected static $routes;

    /**
     * Current request.
     *
     * @var Request
     */
    protected static $request;

    /**
     * Current controllers.
     *
     * @var object[]
     */
    protected static $controllers;

    /**
     * Initialize inner states according.
     *
     * @static
     */
    public static function init()
    {
        if (self::$isInit === false) {
            self::$routes = array();
            self::$isInit = true;
        }
    }

    /**
     * Launch the logic stuff. Console need to be initialized beforehand.
     *
     * @static
     */
    public static function run()
    {
        if (self::$isInit === true) {
            self::$request = new Request(self::$routes);
            self::$controllers = array();
            try {
                $before = self::$request->getBefore();
                foreach ($before as $b) {
                    $controller = Controllers::get($b['class']);
                    $action = $b['action'];
                    $controller->$action(self::$request);
                }
                if (self::$request->hasEnded() === false) {
                    $controller = Controllers::get(self::$request->getClass());
                    $action = self::$request->getAction();
                    $controller->$action(self::$request);
                    if (self::$request->hasEnded() === false) {
                        $after = self::$request->getAfter();
                        foreach ($after as $a) {
                            $controller = Controllers::get($a['class']);
                            $action = $a['action'];
                            $controller->$action(self::$request);
                        }
                    }
                }
            } catch (\Exception $e) {
                echo 'Exception: ' . $e->getMessage() . PHP_EOL;
                echo $e->getTraceAsString();
            }
        }
    }

    /**
     * Set namespace prefix for incoming routes.
     *
     * @static
     * @param  string           $namespace namespace prefix
     */
    public static function prefix(string $namespace)
    {
        self::$namespace = $namespace;
    }

    /**
     * Add route to be considered.
     *
     * @static
     * @param  string           $path   route path
     * @param  string           $usage  how to use it, for help screen
     * @param  string           $help   route description, for help screen
     * @param  string           $action class and method to call
     */
    public static function route(string $path, string $usage, string $help, string $action)
    {
        if (self::$isInit === true) {
            self::$routes[] = array(
                'type' => 'route',
                'path' => $path,
                'usage' => $usage,
                'help' => $help,
                'action' => $action,
                'namespace' => self::$namespace
            );
        }
    }

    /**
     * Add before hook to be considered.
     *
     * @static
     * @param  string           $path   route path
     * @param  string           $usage  how to use it, for help screen
     * @param  string           $help   route description, for help screen
     * @param  string           $action class and method to call
     */
    public static function before(string $path, string $usage, string $help, string $action)
    {
        if (self::$isInit === true) {
            self::$routes[] = array(
                'type' => 'before',
                'path' => $path,
                'usage' => $usage,
                'help' => $help,
                'action' => $action,
                'namespace' => self::$namespace
            );
        }
    }

    /**
     * Add after hook to be considered.
     *
     * @static
     * @param  string           $path   route path
     * @param  string           $usage  how to use it, for help screen
     * @param  string           $help   route description, for help screen
     * @param  string           $action class and method to call
     */
    public static function after(string $path, string $usage, string $help, string $action)
    {
        if (self::$isInit === true) {
            self::$routes[] = array(
                'type' => 'after',
                'path' => $path,
                'usage' => $usage,
                'help' => $help,
                'action' => $action,
                'namespace' => self::$namespace
            );
        }
    }

    /**
     * Get all registered routes.
     *
     * @return array[] all routes
     */
    public static function getRoutes() : array
    {
        return self::$routes;
    }
}


<?php

namespace RocknRoot\StrayFw;

use Psr\Log\AbstractLogger;
use Psr\Log\InvalidArgumentException as LoggerInvalidArgumentException;
use Psr\Log\LogLevel;

/**
 * General class for logging. PSR-3 compliant.
 *
 * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
 *
 * @author Nekith <nekith@errant-works.com>
 */
class Logger extends AbstractLogger
{
    /**
     * General logger instance.
     *
     * @static
     * @var Logger
     */
    private static $log = null;

    /**
     * Get general logger instance.
     *
     * @return Logger
     */
    public static function get() : Logger
    {
        if (self::$log == null) {
            self::$log = new Logger();
        }

        return self::$log;
    }

    /**
     * Logs with an arbitrary level.
     *
     * @throws LoggerInvalidArgumentException if level is unknown
     * @param  mixed                          $level
     * @param  string                         $message
     * @param  array                          $context
     */
    public function log($level, $message, array $context = array())
    {
        if (! is_string($message)) {
            throw new LoggerInvalidArgumentException(sprintf(
                'Argument 2 passed to %s must be a string!',
                __METHOD__
            ));
        }

        static $levels = array(
            LogLevel::EMERGENCY,
            LogLevel::ALERT,
            LogLevel::CRITICAL,
            LogLevel::ERROR,
            LogLevel::WARNING,
            LogLevel::NOTICE,
            LogLevel::INFO,
            LogLevel::DEBUG
        );
        if (in_array($level, $levels) === false) {
            throw new LoggerInvalidArgumentException('unknown level "' . $level . '"');
        }
        $message = $message;
        foreach ($context as $key => $value) {
            $message = str_replace('{' . $key . '}', $value, $message);
        }
        error_log('[' . $level . '] ' . $message);
        if (defined('STRAY_IS_CLI') === true && STRAY_IS_CLI === true) {
            echo '[' . $level . '] ' . $message . PHP_EOL;
        }
    }
}


<?php

namespace RocknRoot\StrayFw\Database\Postgres;

use RocknRoot\StrayFw\Config;
use RocknRoot\StrayFw\Database\Database;
use RocknRoot\StrayFw\Database\Helper;
use RocknRoot\StrayFw\Database\Postgres\Query\Delete;
use RocknRoot\StrayFw\Database\Postgres\Query\Insert;
use RocknRoot\StrayFw\Database\Postgres\Query\Select;
use RocknRoot\StrayFw\Database\Provider\Migration as ProviderMigration;
use RocknRoot\StrayFw\Exception\Exception;

/**
 * Representation parent class for PostgreSQL migrations.
 *
 * @abstract
 *
 * @author Nekith <nekith@errant-works.com>
 */
abstract class Migration extends ProviderMigration
{
    /**
     * Generate code for migration.
     *
     * @param array  $mapping     mapping definition
     * @param string $mappingName mapping name
     * @param string $name        migration name
     * @return array import, up and down code
     */
    public static function generate(array $mapping, string $mappingName, string $name) : array
    {
        $import = [];
        $up = [];
        $down = [];
        $oldSchema = Config::get(rtrim($mapping['config']['migrations']['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $name . DIRECTORY_SEPARATOR . 'schema.yml');
        $migrations = Config::get(rtrim($mapping['config']['migrations']['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'migrations.yml');
        $imax = count($migrations);
        for ($i = 0; $i < $imax; $i++) {
            if ($migrations[$i]['name'] == $name) {
                break;
            }
        }
        if ($i < $imax - 1) {
            $schema = Config::get(rtrim($mapping['config']['migrations']['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ucfirst($migrations[$i + 1]['name']) . DIRECTORY_SEPARATOR . 'schema.yml');
        } else {
            $schema = Config::get($mapping['config']['schema']);
        }

        $newKeys = array_diff_key($schema, $oldSchema);
        foreach ($newKeys as $key => $table) {
            $tableName = null;
            if (isset($table['name']) === true) {
                $tableName = $table['name'];
            } else {
                $tableName = Helper::codifyName($mappingName) . '_' . Helper::codifyName($key);
            }
            if (isset($table['type']) === false || $table['type'] == 'model') {
                $import[] = 'AddTable';
                $import[] = 'DeleteTable';
                $up[] = 'AddTable::statement($this->database, $this->nextSchema, $this->getMappingName(), \'' . $tableName . '\', \'' . $key . '\')';
                $down[] = 'DeleteTable::statement($this->database, \'' . $tableName . '\')';
                echo 'AddTable: ' . $key . PHP_EOL;
            } else {
                echo 'TODO AddEnum: ' . $key . PHP_EOL;
            }
        }

        $oldKeys = array_diff_key($oldSchema, $schema);
        foreach ($oldKeys as $key => $table) {
            $tableName = null;
            if (isset($table['name']) === true) {
                $tableName = $table['name'];
            } else {
                $tableName = Helper::codifyName($mappingName) . '_' . Helper::codifyName($key);
            }
            if (isset($table['type']) === false || $table['type'] == 'model') {
                $import[] = 'AddTable';
                $import[] = 'DeleteTable';
                $up[] = 'DeleteTable::statement($this->database, \'' . $tableName . '\')';
                $down[] = 'AddTable::statement($this->database, $this->prevSchema, $this->getMappingName(), \'' . $tableName . '\', \'' . $key . '\')';
                echo 'RemoveTable: ' . $key . PHP_EOL;
            } else {
                echo 'TODO RemoveEnum: ' . $key . PHP_EOL;
            }
        }

        $keys = array_intersect_key($oldSchema, $schema);
        foreach ($keys as $modelName => $model) {
            $tableName = null;
            if (isset($table['name']) === true) {
                $tableName = $table['name'];
            } else {
                $tableName = Helper::codifyName($mappingName) . '_' . Helper::codifyName($modelName);
            }
            if (isset($table['type']) === false || $table['type'] == 'model') {
                $newFields = array_diff_key($schema[$modelName]['fields'], $model['fields']);
                foreach ($newFields as $fieldName => $fieldDefinition) {
                    $import[] = 'AddColumn';
                    $import[] = 'DeleteColumn';
                    $up[] = 'AddColumn::statement($this->database, $this->nextSchema, $this->getMappingName(), \'' . $modelName . '\', \'' . $tableName . '\', \'' . $fieldName . '\')';
                    $down[] = 'DeleteColumn::statement($this->database, $this->nextSchema, \'' . $modelName . '\', \'' . $tableName . '\', \'' . $fieldName . '\')';
                    echo 'AddColumn: ' . $modelName . '.' . $fieldName . PHP_EOL;
                }
                $oldFields = array_diff_key($model['fields'], $schema[$modelName]['fields']);
                foreach ($oldFields as $fieldName => $fieldDefinition) {
                    $import[] = 'AddColumn';
                    $import[] = 'DeleteColumn';
                    $up[] = 'DeleteColumn::statement($this->database, $this->prevSchema, \'' . $modelName . '\', \'' . $tableName . '\', \'' . $fieldName . '\')';
                    $down[] = 'AddColumn::statement($this->database, $this->prevSchema, $this->getMappingName(), \'' . $modelName . '\', \'' . $tableName . '\', \'' . $fieldName . '\')';
                    echo 'DeleteColumn: ' . $modelName . '.' . $fieldName . PHP_EOL;
                }
                $fields = array_intersect_key($model['fields'], $schema[$modelName]['fields']);
                foreach ($fields as $fieldName => $fieldDefinition) {
                    echo 'TODO compare fields' . PHP_EOL;
                }
            } else {
                echo 'TODO Compare Enum values' . PHP_EOL;
            }
        }

        return [
            'import' => array_unique($import),
            'up' => $up,
            'down' => $down,
        ];
    }

    /**
     * Ensure the migrations table exist for specified mapping.
     *
     * @param array $mapping mapping definition
     * @return bool true if successful
     */
    public static function ensureTable(array $mapping) : bool
    {
        $database = Database::get($mapping['config']['database']);
        $statement = 'CREATE TABLE IF NOT EXISTS _stray_migration (';
        $statement .= 'date TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, ';
        $statement .= 'migration VARCHAR(255)';
        $statement .= ')';
        $statement = $database->getMasterLink()->prepare($statement);
        if ($statement->execute() === false) {
            echo 'Can\'t create _stray_migration (' . $statement->errorInfo()[2] . ')' . PHP_EOL;
            return false;
        }
        $select = new Select($mapping['config']['database'], true);
        $select->select('COUNT(*) as count')
            ->from('_stray_migration');
        if ($select->execute() === false) {
            echo 'Can\'t fetch from _stray_migration (' . $select->getErrorMessage() . ')' . PHP_EOL;
            return false;
        }
        if ($select->fetch()['count'] == 0) {
            $insert = new Insert($mapping['config']['database']);
            $insert->into('_stray_migration');
            if ($insert->execute() === false) {
                echo 'Can\'t insert into _stray_migration (' . $insert->getErrorMessage() . ')' . PHP_EOL;
                return false;
            }
        }
        return true;
    }

    /**
     * Run migration code for specified mapping.
     *
     * @param array $mapping mapping definition
     */
    public static function migrate(array $mapping)
    {
        $database = Database::get($mapping['config']['database']);
        $database->beginTransaction();
        if (self::ensureTable($mapping) === false) {
            $database->rollBack();
            return;
        }
        $migrations = Config::get(rtrim($mapping['config']['migrations']['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'migrations.yml');
        $select = new Select($mapping['config']['database'], true);
        $select->select('*')
            ->from('_stray_migration')
            ->orderBy('date DESC')
            ->limit(1);
        if ($select->execute() === false) {
            echo 'Can\'t fetch from _stray_migration (' . $select->getErrorMessage() . ')' . PHP_EOL;
            $database->rollBack();
            return;
        }
        $last = $select->fetch();
        $last['date'] = new \DateTime($last['date']);
        $last['date'] = $last['date']->getTimestamp();
        $migrations = array_values(array_filter($migrations, function (array $m) use ($last) {
            return (int) $m['timestamp'] > $last['date'];
        }));
        usort($migrations, function (array $a, array $b) {
            return $a['timestamp'] > $b['timestamp'];
        });
        $imax = count($migrations);
        for ($i = 0; $i < $imax; $i++) {
            echo 'Run ' . $migrations[$i]['name'] . PHP_EOL;
            $cl = '\\' . ltrim(rtrim($mapping['config']['migrations']['namespace'], '\\'), '\\') . '\\' . ucfirst($migrations[$i]['name']) . '\\' . ucfirst($migrations[$i]['name']);
            if ($i < $imax - 1) {
                $schema = Config::get(rtrim($mapping['config']['migrations']['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ucfirst($migrations[$i + 1]['name']) . DIRECTORY_SEPARATOR . 'schema.yml');
            } else {
                $schema = Config::get($mapping['config']['schema']);
            }
            $n = new $cl($schema, rtrim($mapping['config']['migrations']['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ucfirst($migrations[$i]['name']) . DIRECTORY_SEPARATOR);
            try {
                $n->up();
            } catch (Exception $e) {
                $database->rollBack();
                throw $e;
            }
            $insert = new Insert($mapping['config']['database']);
            $insert->into('_stray_migration');
            $insert->bind('migration', $migrations[$i]['name']);
            $insert->values([ 'migration' => ':migration' ]);
            if ($insert->execute() === false) {
                echo 'Can\'t insert into _stray_migration (' . $insert->getErrorMessage() . ')' . PHP_EOL;
                $database->rollBack();
                return;
            }
        }
        $database->commit();
    }

    /**
     * Run reversed migration code for specified mapping.
     *
     * @param array $mapping mapping definition
     */
    public static function rollback(array $mapping)
    {
        $database = Database::get($mapping['config']['database']);
        $database->beginTransaction();
        if (self::ensureTable($mapping) === false) {
            $database->rollBack();
            return;
        }
        $migrations = Config::get(rtrim($mapping['config']['migrations']['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'migrations.yml');
        $select = new Select($mapping['config']['database'], true);
        $select->select('*')
            ->where('migration IS NOT NULL')
            ->from('_stray_migration')
            ->orderBy('date DESC')
            ->limit(1);
        if ($select->execute() === false) {
            echo 'Can\'t fetch from _stray_migration (' . $select->getErrorMessage() . ')' . PHP_EOL;
            $database->rollBack();
            return;
        }
        $last = $select->fetch();
        if (!$last) {
            echo 'There is no executed migration.' . PHP_EOL;
            $database->rollBack();
            return;
        }
        echo 'Last executed migration is: ' . $last['migration'] . '.' . PHP_EOL;
        $last['date'] = new \DateTime($last['date']);
        $last['date'] = $last['date']->getTimestamp();
        $migration = null;
        $i = 0;
        $imax = count($migrations);
        while ($i < $imax) {
            if ($migrations[$i]['name'] == $last['migration']) {
                $migration = $migrations[$i];
                break;
            }
            $i++;
        }
        if ($migration == null) {
            echo 'Can\'t find migration in migrations.yml.' . PHP_EOL;
            return;
        }
        $cl = '\\' . ltrim(rtrim($mapping['config']['migrations']['namespace'], '\\'), '\\') . '\\' . ucfirst($migration['name']) . '\\' . ucfirst($migration['name']);
        if ($i < $imax - 1) {
            $schema = Config::get(rtrim($mapping['config']['migrations']['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ucfirst($migrations[$i + 1]['name']) . DIRECTORY_SEPARATOR . 'schema.yml');
        } else {
            $schema = Config::get($mapping['config']['schema']);
            echo'last';
        }
        $n = new $cl($schema, rtrim($mapping['config']['migrations']['path'], DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ucfirst($migration['name']) . DIRECTORY_SEPARATOR);
        try {
            $n->down();
        } catch (Exception $e) {
            $database->rollBack();
            throw $e;
        }
        $delete = new Delete($mapping['config']['database']);
        $delete->from('_stray_migration');
        $delete->bind('migration', $migration['name']);
        $delete->where([ 'migration' => ':migration' ]);
        if ($delete->execute() === false) {
            echo 'Can\'t delete from _stray_migration (' . $delete->getErrorMessage() . ')' . PHP_EOL;
            $database->rollBack();
            return;
        }
        $database->commit();
    }
}


<?php
/*
 * (c) 2017: 975L <contact@975l.com>
 * (c) 2017: Laurent Marquet <laurent.marquet@laposte.net>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace c975L\ToolbarBundle\Service;

use c975L\ToolbarBundle\Service\ToolbarServiceInterface;

/**
 * Main Services related to Payment
 * @author Laurent Marquet <laurent.marquet@laposte.net>
 * @copyright 2018 975L <contact@975l.com>
 */
class ToolbarService implements ToolbarServiceInterface
{
    /**
     * {@inheritdoc}
     */
    public function defineButton(string $button)
    {
        switch ($button) {
            case 'add_role':
                $icon = 'fas fa-user-check';
                $style = 'btn-info';
                break;
            case 'abuse':
                $icon = 'fas fa-fire';
                $style = 'btn-danger';
                break;
            case 'cancel':
                $icon = 'fas fa-ban';
                $style = 'btn-default';
                break;
            case 'change_password':
                $icon = 'fas fa-sync-alt';
                $style = 'btn-warning';
                break;
            case 'config':
                $icon = 'fas fa-cog';
                $style = 'btn-info';
                break;
            case 'create':
            case 'new':
                $icon = 'fas fa-plus';
                $style = 'btn-default';
                break;
            case 'credits':
                $icon = 'fas fa-gem';
                $style = 'btn-default';
                break;
            case 'dashboard':
                $icon = 'fas fa-hand-point-right';
                $style = 'btn-success';
                break;
            case 'delete':
                $icon = 'fas fa-trash';
                $style = 'btn-danger';
                break;
            case 'delete_role':
                $icon = 'fas fa-user-times';
                $style = 'btn-info';
                break;
            case 'display':
                $icon = 'fas fa-eye';
                $style = 'btn-default';
                break;
            case 'duplicate':
                $icon = 'fas fa-copy';
                $style = 'btn-default';
                break;
            case 'email':
                $icon = 'fas fa-envelope';
                $style = 'btn-default';
                break;
            case 'export_json':
            case 'export_xml':
                $icon = 'fas fa-file-export';
                $style = 'btn-default';
                break;
            case 'forward':
                $icon = 'fas fa-forward';
                $style = 'btn-default';
                break;
            case 'heart':
                $icon = 'fas fa-heart';
                $style = 'btn-default';
                break;
            case 'help':
                $icon = 'fas fa-question';
                $style = 'btn-info';
                break;
            case 'info':
                $icon = 'fas fa-info-circle';
                $style = 'btn-info';
                break;
            case 'public_profile':
                $icon = 'fas fa-user-circle';
                $style = 'btn-default';
                break;
            case 'modify':
                $icon = 'fas fa-pencil-alt';
                $style = 'btn-default';
                break;
            case 'qrcode':
                $icon = 'fas fa-qrcode';
                $style = 'btn-default';
                break;
            case 'pdf':
                $icon = 'far fa-file-pdf';
                $style = 'btn-default';
                break;
            case 'signout':
                $icon = 'fas fa-sign-out-alt';
                $style = 'btn-info';
                break;
            case 'send':
                $icon = 'fas fa-paper-plane';
                $style = 'btn-default';
                break;
            case 'transactions':
                $icon = 'fas fa-exchange-alt';
                $style = 'btn-default';
                break;
            case 'user':
                $icon = 'fas fa-user';
                $style = 'btn-default';
                break;
            case 'users':
                $icon = 'fas fa-users';
                $style = 'btn-warning';
                break;
            default:
                $icon = null;
                $style = null;
                break;
        }

        return compact('icon', 'style');
    }
}


<?php

namespace RocknRoot\StrayFw\Database\Postgres\Query;

use RocknRoot\StrayFw\Database\Database;
use RocknRoot\StrayFw\Exception\AppException;
use RocknRoot\StrayFw\Exception\BadUse;
use RocknRoot\StrayFw\Logger;

/**
 * Representation class for PostgreSQL delete queries.
 *
 * @author Nekith <nekith@errant-works.com>
 */
class Delete extends Query
{
    /**
     * From clause.
     *
     * @var string
     */
    protected $from;

    /**
     * Where clause.
     *
     * @var Condition
     */
    protected $where;

    /**
     * Order by clause.
     *
     * @var string|null
     */
    protected $orderBy;

    /**
     * Limit clause.
     *
     * @var string
     */
    protected $limit;

    /**
     * Execute the constructed query.
     *
     * @throws AppException on SQL error
     * @return bool         true if the query is successfully executed
     */
    public function execute()
    {
        if ($this->statement == null) {
            $this->statement = Database::get($this->database)->getMasterLink()->prepare($this->toSql());
        }
        foreach ($this->parameters as $name => $value) {
            $type = \PDO::PARAM_STR;
            if (is_int($value) === true) {
                $type = \PDO::PARAM_INT;
            } elseif (is_bool($value) === true) {
                $type = \PDO::PARAM_BOOL;
            } elseif (is_null($value) === true) {
                $type = \PDO::PARAM_NULL;
            }
            $this->statement->bindValue($name, $value, $type);
        }
        $result = $this->statement->execute();
        $this->errorInfo = $this->statement->errorInfo();
        if ($this->getErrorState() != '00000') {
            Logger::get()->error('delete query failed : ' . $this->getErrorMessage() . ' (' . $this->toSql() . ')');
            if (constant('STRAY_ENV') === 'development') {
                throw new AppException('delete query failed : ' . $this->getErrorMessage() . ' (' . $this->toSql() . ')');
            }
        }

        return $result;
    }

    /**
     * Extract the corresponding SQL code.
     *
     * @throws BadUse if from clause has not been defined
     * @return string generated SQL code
     */
    public function toSql()
    {
        if (empty($this->from) === true) {
            throw new BadUse('from clause has not been defined (' . print_r($this, true) . ')');
        }
        $sql = 'DELETE FROM ' . $this->from . ' ';

        if ($this->where != null) {
            $sql .= 'WHERE ' . $this->where->toSql() . ' ';
        }
        if ($this->orderBy != null) {
            $sql .= 'ORDER BY ' . $this->orderBy . ' ';
        }
        if ($this->limit != null) {
            $sql .= 'LIMIT ' . $this->limit . ' ';
        }

        return $sql;
    }

    /**
     * Set from clause.
     *
     * @param  string $table table real name
     * @return Delete this
     */
    public function from($table)
    {
        $this->from = $table;

        return $this;
    }

    /**
     * Set where clause.
     *
     * @param  Condition|array|string $where where clause
     * @return Delete                 this
     */
    public function where($where)
    {
        $this->where = ($where instanceof Condition ? $where : new Condition($where));

        return $this;
    }

    /**
     * Set order by clause.
     *
     * @param  array|string $orderBy order by clause
     * @return Delete       this
     */
    public function orderBy($orderBy)
    {
        if (is_array($orderBy) === true) {
            $this->orderBy = '';
            foreach ($orderBy as $key => $elem) {
                $this->orderBy .= $key . ' ' . $elem . ', ';
            }
            $this->orderBy = substr($this->orderBy, 0, -2);
        } else {
            $this->orderBy = $orderBy;
        }

        return $this;
    }

    /**
     * Set limit clause.
     *
     * @param  string $limit limit clause
     * @return Delete this
     */
    public function limit($limit)
    {
        $this->limit = $limit;

        return $this;
    }
}


<?php

namespace RocknRoot\StrayFw\Database\Provider;

use RocknRoot\StrayFw\Config;
use RocknRoot\StrayFw\Database\Mapping;
use RocknRoot\StrayFw\Exception\FileNotReadable;
use RocknRoot\StrayFw\Exception\InvalidDirectory;

/**
 * Schema representation parent class for all providers.
 *
 * @abstract
 *
 * @author Nekith <nekith@errant-works.com>
 */
abstract class Schema
{
    /**
     * Mapping name.
     *
     * @var string
     */
    protected $mapping;

    /**
     * Schema definition.
     *
     * @var array<string, array>
     */
    protected $definition;

    /**
     * Construct a new schema representation class.
     *
     * @throws InvalidDirectory if directory $modelsDir can't be indentified
     * @throws InvalidDirectory if directory Base in $modelsDir can't be indentified
     * @throws FileNotReadable  if schema file is not readable
     * @param  string           $mapping mapping name
     */
    public function __construct(string $mapping)
    {
        $this->mapping = $mapping;
        $data = Mapping::get($mapping);
        $file = $data['config']['schema'];
        $modelsDir = $data['config']['models']['path'];
        if (is_readable($file) === false) {
            throw new FileNotReadable('file "' . $file . '" isn\'t readable');
        }
        if (is_dir($modelsDir) === false) {
            throw new InvalidDirectory('directory "' . $modelsDir . '" can\'t be identified');
        }
        if (is_dir($modelsDir . DIRECTORY_SEPARATOR . 'Base') === false) {
            throw new InvalidDirectory('directory "' . $modelsDir . DIRECTORY_SEPARATOR . 'Base" can\'t be identified');
        }
    }

    /**
     * Build data structures.
     *
     * @abstract
     */
    abstract public function build();

    /**
     * Generate base models.
     *
     * @abstract
     */
    abstract public function generateModels();

    /**
     * Get the schema definition, from schema configuration file.
     *
     * @return array<string, array> schema definition
     */
    public function getDefinition() : array
    {
        if ($this->definition == null) {
            $data = Mapping::get($this->mapping);
            $this->definition = Config::get($data['config']['schema']);
        }

        return $this->definition;
    }

    /**
     * Get mapping name this schema is embedded in.
     *
     * @return string mapping name
     */
    public function getMapping() : string
    {
        return $this->mapping;
    }

    /**
     * Get the schema instance of specified mapping.
     *
     * @param  string $mapping mapping name
     * @return Schema schema instance
     */
    public static function getSchema(string $mapping) : Schema
    {
        $data = Mapping::get($mapping);
        $class = rtrim(ucfirst($data['config']['provider']), '\\') . '\\Schema';

        return new $class($mapping);
    }
}


<?php
/*
 * (c) 2018: 975L <contact@975l.com>
 * (c) 2018: Laurent Marquet <laurent.marquet@laposte.net>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace c975L\ToolbarBundle\Twig;
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

/**
 * Twig extension to provide the xhtml code for the toolbar using `{{ toolbar_display('TOOLS_TEMPLATE', 'TYPE', 'SIZE[lg|md|sm|xs]', OBJECT_IF_NEEDED) }}`
 * @author Laurent Marquet <laurent.marquet@laposte.net>
 * @copyright 2018 975L <contact@975l.com>
 */
class ToolbarDisplay extends AbstractExtension
{
    public function getFunctions()
    {
        return array(
            new TwigFunction(
                'toolbar_display',
                array($this, 'display'),
                array(
                    'needs_environment' => true,
                    'is_safe' => array('html'),
                )
            ),
        );
    }

    /**
     * Returns the xhtml code for the toolbar
     * @return string
     */
    public function display(Environment $environment, $template, $type = null, $size = 'md', $object = null)
    {
        //Defines tools
        $tools = $environment->render($template, array(
                'type' => $type,
                'object' => $object,
            ));

        //Defines toolbar
        return $environment->render('@c975LToolbar/toolbar.html.twig', array(
                'tools' => $tools,
                'size' => $size,
            ));
    }
}


<?php
/*
 * (c) 2018: 975L <contact@975l.com>
 * (c) 2018: Laurent Marquet <laurent.marquet@laposte.net>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace c975L\ToolbarBundle\Twig;

use c975L\ToolbarBundle\Service\ToolbarServiceInterface;
use Twig\Environment;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

/**
 * Twig extension to provide the xhtml code for requested button using toolbar_button_text(path('ROUTE', { 'VARIABLE': object.PROPERTY }), 'BUTTON_NAME', 'SIZE[lg|md|sm|xs](default md)', 'ICON_DISPLAY[true|false](default true)', 'LOCATION[right|bottom|left|top]')
 * @author Laurent Marquet <laurent.marquet@laposte.net>
 * @copyright 2018 975L <contact@975l.com>
 */
class ToolbarButtonText extends AbstractExtension
{
    /**
     * Stores the toolbarService
     * @var ToolbarServiceInterface
     */
    private $toolbarService;

    public function __construct(ToolbarServiceInterface $toolbarService)
    {
        $this->toolbarService = $toolbarService;
    }

    public function getFunctions()
    {
        return array(
            new TwigFunction(
                'toolbar_button_text',
                array($this, 'button'),
                array(
                    'needs_environment' => true,
                    'is_safe' => array('html'),
                )
            ),
        );
    }

    /**
     * Returns the xhtml code for the button with text
     * @return string
     */
    public function button(Environment $environment, $link, $button, $size = 'md', $iconDisplay = 'true', $location = 'right', $label = null, $userStyle = null)
    {
        //Defines $icon and $style
        extract($this->toolbarService->defineButton($button));

        //Defines button
        return $environment->render('@c975LToolbar/buttonText.html.twig', array(
            'link' => $link,
            'style' => $style,
            'size' => $size,
            'button' => $button,
            'icon' => $icon,
            'label' => $label,
            'iconDisplay' => $iconDisplay,
            'location' => $location,
        ));
    }
}


<?php

namespace RocknRoot\StrayFw\Http;

use RocknRoot\StrayFw\Render\RenderInterface;

/**
 * Response class for HTTP requests.
 *
 * @author Nekith <nekith@errant-works.com>
 */
class Response
{
    /**
     * HTTP status.
     *
     * @var int
     */
    public $status;

    /**
     * Response data.
     *
     * @var array
     */
    public $data;

    /**
     * Render object.
     *
     * @var \RocknRoot\StrayFw\Render\RenderInterface|null
     */
    protected $renderInst;

    /**
     * Construct response with default values.
     */
    public function __construct()
    {
        $this->status = 200;
        $this->data = [];
        $this->renderInst = null;
    }

    /**
     * Get set render object.
     *
     * @return \RocknRoot\StrayFw\Render\RenderInterface|null
     */
    public function getRender()
    {
        return $this->renderInst;
    }

    /**
     * Set render and status.
     *
     * @param RenderInterface $render render object
     * @param int $status status code
     */
    public function render(RenderInterface $render, $status = 200)
    {
        $this->renderInst = $render;
        $this->status = $status;
    }
}


<?php

namespace RocknRoot\StrayFw\Http;

use RocknRoot\StrayFw\Exception\InvalidRouteDefinition;
use RocknRoot\StrayFw\Exception\RouteNotFound;
use RocknRoot\StrayFw\Request as BaseRequest;

/**
 * Routed data from raw request.
 *
 * @author Nekith <nekith@errant-works.com>
 */
class Request extends BaseRequest
{
    /**
     * Raw request.
     *
     * @var RawRequest
     */
    protected $rawRequest;

    /**
     * Request data.
     *
     * @var array
     */
    public $data;

    /**
     * Parse raw request and choose a route.
     *
     * @throws InvalidRouteDefinition if there is no route
     * @throws InvalidRouteDefinition if a route has an invalid definition
     * @throws RouteNotFound if no route matches the request
     * @param  RawRequest    $rawRequest base raw request
     * @param  array[]       $routes registered routes
     */
    public function __construct(RawRequest $rawRequest, array $routes)
    {
        $this->rawRequest = $rawRequest;
        $this->before = array();
        $this->after = array();
        $this->hasEnded = false;
        $this->data = [];
        if (count($routes) == 0) {
            throw new InvalidRouteDefinition('there is no route');
        }
        foreach ($routes as $route) {
            if (isset($route['subdomain']) === true) {
                if (in_array($this->rawRequest->getSubDomain(), $route['subdomain']) === false) {
                    continue;
                }
            }
            if (isset($route['path']) === false || isset($route['action']) === false || strpos($route['action'], '.') === false) {
                throw new InvalidRouteDefinition('route "' . $route['path'] . '" has invalid definition');
            }
            if (isset($route['method']) === false || strtolower($route['method']) === 'all' || strtolower($route['method']) == strtolower($this->rawRequest->getMethod())) {
                $path = $route['path'];
                if (empty($route['uri']) === false) {
                    $path = '/' . ltrim(rtrim($route['uri'], '/'), '/') . $path;
                }
                if (strlen($route['path']) > 1) {
                    $path = rtrim($path, '/');
                }
                $matches = null;
                if ($route['type'] == 'before' || $route['type'] == 'after') {
                    if (preg_match('#^' . $path . '#', $this->rawRequest->getQuery(), $matches) === 1) {
                        list($class, $action) = explode('.', $route['action']);
                        if (stripos($class, '\\') !== 0 && isset($route['namespace']) === true) {
                            $class = rtrim($route['namespace'], '\\') . '\\' . $class;
                        }
                        $a = [ 'class' => $class, 'action' => $action ];
                        if ($route['type'] == 'before') {
                            $this->before[] = $a;
                        } else {
                            $this->after[] = $a;
                        }
                    }
                } elseif ($this->class == null) {
                    if (preg_match('#^' . $path . '$#', $this->rawRequest->getQuery(), $matches) === 1) {
                        list($this->class, $this->action) = explode('.', $route['action']);
                        if (stripos($this->class, '\\') !== 0 && isset($route['namespace']) === true) {
                            $this->class = rtrim($route['namespace'], '\\') . '\\' . $this->class;
                        }
                        foreach ($matches as $k => $v) {
                            if (is_numeric($k) === false && $v != null) {
                                $this->args[$k] = $v;
                            }
                        }
                    }
                }
            }
        }
        if ($this->class == null) {
            throw new RouteNotFound('no route matches this : ' . print_r($this->rawRequest, true));
        }
    }

    /**
     * Magic method for object cloning.
     */
    public function __clone()
    {
        $this->rawRequest = clone $this->rawRequest;
    }

    /**
     * Get associated raw request.
     *
     * @return RawRequest
     */
    public function getRawRequest()
    {
        return $this->rawRequest;
    }

    /**
     * Retrieve an input var from, in this order of priority:
     *  * POST vars
     *  * route args
     *  * GET vars
     *  * $default
     *
     * @param string $name input searched
     * @param mixed $default returned value if nothing is found
     * @return mixed found value or default
     */
    public function input($name, $default = null)
    {
        if (isset($this->rawRequest->getPostVars()[$name]) === true) {
            return $this->rawRequest->getPostVars()[$name];
        }
        if (isset($this->args[$name]) === true) {
            return $this->args[$name];
        }
        if (isset($this->rawRequest->getGetVars()[$name]) === true) {
            return $this->rawRequest->getGetVars()[$name];
        }

        return $default;
    }
}


<?php

namespace RocknRoot\StrayFw;

use RocknRoot\StrayFw\Console\Console;
use RocknRoot\StrayFw\Exception\BadUse;
use RocknRoot\StrayFw\Exception\UnknownNamespace;
use RocknRoot\StrayFw\Http\Http;

/**
 * First loaded framework class, taking care of autoloading
 * and registering apps and libs.
 *
 * @abstract
 *
 * @author Nekith <nekith@errant-works.com>
 */
abstract class Bootstrap
{
    /**
     * True if class has already been initialized.
     *
     * @static
     * @var bool
     */
    private static $isInit = false;

    /**
     * Namespace-path hash.
     *
     * @static
     * @var string[]
     */
    protected static $namespaces;

    /**
     * Registered applications.
     *
     * @static
     * @var string[]
     */
    protected static $applications;

    /**
     * Initialize properties and register autoloader static method.
     *
     * @static
     */
    public static function init()
    {
        if (self::$isInit === false) {
            self::$namespaces = array();
            self::$applications = array();
            spl_autoload_register(__CLASS__ . '::loadClass');
            self::$isInit = true;
            Console::init();
            Console::prefix('\\RocknRoot\\StrayFw\\Console');
            Console::route('help', 'help', 'this screen', 'Controller.help');
            Console::prefix('\\RocknRoot\\StrayFw\\Database');
            Console::route('db/list', 'db/list', 'list registered mappings', 'Console.mappings');
            Console::route('db/build', 'db/build mapping_name', 'build data structures', 'Console.build');
            Console::route('db/generate', 'db/generate mapping_name', 'generate base models', 'Console.generate');
            Console::route('db/migration/create', 'db/migration/create mapping_name migration_name', 'create a new migration', 'Migration.create');
            Console::route('db/migration/generate', 'db/migration/generate mapping_name migration_name', 'generate migration code', 'Migration.generate');
            Console::route('db/migration/migrate', 'db/migration/migrate mapping_name', 'migrate', 'Migration.migrate');
            Console::route('db/migration/rollback', 'db/migration/rollback mapping_name', 'rollback last migration', 'Migration.rollback');
            Console::prefix('\\RocknRoot\\StrayFw\\Http');
            Console::route('http/routing/list', 'http/routing/list', 'list registered routes', 'Console.routes');
            Http::init();
            if (defined('STRAY_IS_HTTP') === true && constant('STRAY_IS_HTTP') === true && constant('STRAY_ENV') === 'development') {
                Debug\ErrorPage::init();
            }
        }
    }

    /**
     * Autoloader registered function.
     * Try to require a file according to the needed class.
     *
     * @static
     * @throws BadUse           if bootstrap isn't initialized
     * @throws UnknownNamespace if needed namespace can't be found
     * @param  string           $className needed class name
     */
    public static function loadClass(string $className)
    {
        if (self::$isInit === false) {
            throw new BadUse('bootstrap doesn\'t seem to have been initialized');
        }
        $fileName = null;
        if (($namespacePos = strripos($className, '\\')) !== false) {
            $namespacePos = (int) $namespacePos; // re: https://github.com/phpstan/phpstan/issues/647
            $namespace = substr($className, 0, $namespacePos);
            $subNamespaces = array();
            while ($fileName === null && $namespace != null) {
                if (isset(self::$namespaces[$namespace]) === false) {
                    $subNamespacePos = strripos($namespace, '\\');
                    $subNamespacePos = (int) $subNamespacePos; // re: https://github.com/phpstan/phpstan/issues/647
                    $subNamespaces[] = substr($namespace, $subNamespacePos);
                    $namespace = substr($namespace, 0, $subNamespacePos);
                } else {
                    $fileName = self::$namespaces[$namespace];
                }
            }
            if ($fileName === null) {
                throw new UnknownNamespace('can\'t find namespace "' . substr($className, 0, $namespacePos) . '"');
            }
            $fileName = self::$namespaces[$namespace] . str_replace('\\', DIRECTORY_SEPARATOR, implode('', array_reverse($subNamespaces)));
            $className = substr($className, $namespacePos + 1);
        }
        if ($fileName != null) {
            $fileName .= DIRECTORY_SEPARATOR . str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
            require $fileName;
        }
    }

    /**
     * Add a namespace to the recognized ones.
     * Use this for files in the _apps_ directory.
     *
     * @static
     * @param string $namespace new namespace
     * @param string $path      custom files path if needed
     */
    public static function registerApp(string $namespace, string $path = null)
    {
        $namespace = rtrim($namespace, '\\');
        if ($path == null) {
            $path = constant('STRAY_PATH_APPS') . str_replace(
                '_',
                DIRECTORY_SEPARATOR,
                str_replace('\\', DIRECTORY_SEPARATOR, $namespace)
            );
        }
        self::$namespaces[$namespace] = $path;
        self::$applications[] = $namespace;
    }

    /**
     * Launch the logic stuff. Bootstrap need to be initialized beforehand.
     *
     * @throws BadUse if bootstrap isn't initialized
     * @throws BadUse if no application is registered
     * @throws BadUse if not CLI_IS_CLI nor STRAY_IS_HTTP
     * @static
     */
    public static function run()
    {
        if (self::$isInit === false) {
            throw new BadUse('bootstrap doesn\'t seem to have been initialized');
        }
        foreach (self::$namespaces as $name => $path) {
            if (is_readable($path . DIRECTORY_SEPARATOR . 'init.php') === true) {
                require $path . DIRECTORY_SEPARATOR . 'init.php';
            } elseif (stripos($path, 'vendor') === false || stripos($path, 'vendor') == strlen($path) - strlen('vendor')) {
                Logger::get()->error('namespace "' . $name . '" doesn\'t have an init.php');
            }
        }
        if (defined('STRAY_IS_CLI') === true && constant('STRAY_IS_CLI') === true) {
            Console::run();
        } elseif (defined('STRAY_IS_HTTP') === true && constant('STRAY_IS_HTTP') === true) {
            if (count(self::$applications) == 0) {
                throw new BadUse('no application has been registered');
            }
            Http::run();
        } else {
            throw new BadUse('unknown mode, not CLI_IS_CLI nor STRAY_IS_HTTP');
        }
    }
}


<?php

namespace RocknRoot\StrayFw\Database\Postgres\Mutation;

use RocknRoot\StrayFw\Database\Database;
use RocknRoot\StrayFw\Database\Helper;
use RocknRoot\StrayFw\Database\Postgres\Column;

/**
 * Representation for column deletion operations.
 *
 * @author Nekith <nekith@errant-works.com>
 */
class DeleteColumn extends Mutation
{
    /**
     * Prepare and return according PDO statement.
     *
     * @param  Database                $database        database
     * @param  array                   $schema          schema definition
     * @param  string                  $modelName       model name
     * @param  string                  $tableName       table name
     * @param  string                  $fieldName       field name
     * @return \PDOStatement           $statement       prepared query
     */
    public static function statement(Database $database, array $schema, string $modelName, string $tableName, string $fieldName)
    {
        $fieldDefinition = $schema[$modelName]['fields'][$fieldName];
        $fieldRealName = null;
        if (isset($fieldDefinition['name']) === true) {
            $fieldRealName = $fieldDefinition['name'];
        } else {
            $fieldRealName = Helper::codifyName($modelName) . '_' . Helper::codifyName($fieldName);
        }
        $sql = 'ALTER TABLE ' . $tableName . ' DROP COLUMN ' . $fieldRealName;
        $statement = $database->getMasterLink()->prepare($sql);
        return $statement;
    }
}


<?php
/**
 * This file is part of CMSGears Framework. Please view License file distributed
 * with the source code for license details.
 *
 * @link https://www.cmsgears.org/
 * @copyright Copyright (c) 2015 VulpineCode Technologies Pvt. Ltd.
 */

namespace cmsgears\icons\widgets;

// Yii Imports
use yii\helpers\Html;

// CMG Imports
use cmsgears\core\common\base\Widget;

/**
 * IconChooser widget provide options to choose icon from standard libraries.
 *
 * @since 1.0.0
 */
class IconChooser extends Widget {

	// Variables ---------------------------------------------------

	// Globals -------------------------------

	// Constants --------------

	// Public -----------------

	// Protected --------------

	// Variables -----------------------------

	// Public -----------------

	public $wrap		= true;

	public $class		= null;
	public $model		= null;
	public $attribute	= 'icon';
	public $label		= 'Icon';
	public $icon		= null;

	public $default		= 'icon'; // none

	public $disabled	= false;

	public $template	= 'icon';

	// Protected --------------

	// Private ----------------

	// Traits ------------------------------------------------------

	// Constructor and Initialisation ------------------------------

	// Instance methods --------------------------------------------

	// Yii interfaces ------------------------

	// Yii parent classes --------------------

	// CMG interfaces ------------------------

	// CMG parent classes --------------------

	// cmsgears\core\common\base\Widget

	public function renderWidget( $config = [] ) {

		$widgetHtml = $this->render( $this->template, [
			'name' => $this->getModelName(),
			'attribute' => $this->attribute,
			'label' => $this->label,
			'icon' => $this->getIcon(),
			'disabled' => $this->disabled
		]);

		if( $this->wrap ) {

			return Html::tag( $this->wrapper, $widgetHtml, $this->options );
		}

		return $widgetHtml;
	}

	// IconChooser ---------------------------

	/**
	 * Return the model name used while submitting the form.
	 *
	 * @return string
	 */
	private function getModelName() {

		// Provided name will override
		if( isset( $this->class ) ) {

			return $this->class;
		}

		// Return class name if model is given
		if( isset( $this->model ) ) {

			$rClass = new \ReflectionClass( $this->model );

			return $rClass->getShortName();
		}

		return 'Icon';
	}

	/**
	 * Return the icon to be displayed.
	 *
	 * @return string
	 */
	private function getIcon() {

		// Provided name will override
		if( isset( $this->model ) ) {

			$icon = $this->attribute;

			if( isset( $this->model->$icon ) ) {

				return $this->model->$icon;
			}
		}

		if( isset( $this->icon ) ) {

			return $this->icon;
		}

		return $this->default;
	}

}


<?php

namespace RocknRoot\StrayFw\Http;

/**
 * Wrapper class for cookies.
 *
 * @abstract
 *
 * @author Nekith <nekith@errant-works.com>
 */
abstract class Cookie
{
    /**
     * Get a cookie value by its key.
     *
     * @static
     * @param  string $name key
     * @return mixed
     */
    public static function get($name)
    {
        if (isset($_COOKIE[$name]) === false) {
            return null;
        }

        return $_COOKIE[$name];
    }

    /**
     * Check if a cookie is set.
     *
     * @static
     * @param  string $name key
     * @return bool
     */
    public static function has($name)
    {
        return isset($_COOKIE[$name]);
    }

    /**
     * Set a cookie.
     *
     * @static
     * @param string $name   key
     * @param string $value  new value
     * @param int    $expire expiration timestamp
     * @param string $path   cookie path
     */
    public static function set($name, $value, $expire = 0, $path = null)
    {
        if ($path === null) {
            setcookie($name, $value, $expire);
        } else {
            setcookie($name, $value, $expire, $path);
        }
    }

    /**
     * Unset a cookie.
     *
     * @static
     * @param string $name key
     */
    public static function delete($name)
    {
        setcookie($name, '', time() - 1);
    }

    /**
     * Clear all cookies.
     *
     * @static
     */
    public static function clear()
    {
        $keys = array_keys($_COOKIE);
        foreach ($keys as $key) {
            setcookie($key, '', time() - 1);
        }
    }
}


<?php
/**
 * This file is part of CMSGears Framework. Please view License file distributed
 * with the source code for license details.
 *
 * @link https://www.cmsgears.org/
 * @copyright Copyright (c) 2015 VulpineCode Technologies Pvt. Ltd.
 */

namespace cmsgears\newsletter\frontend\models\forms;

// Yii Imports
use Yii;
use yii\helpers\ArrayHelper;

// CMG Imports
use cmsgears\core\common\config\CoreGlobal;
use cmsgears\newsletter\common\config\NewsletterGlobal;

use cmsgears\core\common\models\forms\BaseForm;

/**
 * SignUpForm to become newsletter member.
 *
 * @since 1.0.0
 */
class SignUpForm extends BaseForm {

	// Variables ---------------------------------------------------

	// Globals -------------------------------

	// Constants --------------

	// Public -----------------

	// Protected --------------

	// Variables -----------------------------

	// Public -----------------

	public $name;
	public $email;

	public $newsletterId;

	// Protected --------------

	// Private ----------------

	// Traits ------------------------------------------------------

	// Constructor and Initialisation ------------------------------

	// Instance methods --------------------------------------------

	// Yii interfaces ------------------------

	// Yii parent classes --------------------

	// yii\base\Component -----

	public function rules() {

        $rules = [
			[ 'email', 'required' ],
			[ 'newsletterId', 'safe' ],
			[ 'name', 'string', 'min' => 1, 'max' => Yii::$app->core->xLargeText ],
			[ 'email', 'email' ]
		];

		if( Yii::$app->core->trimFieldValue ) {

			$trim[] = [ [ 'email', 'name' ], 'filter', 'filter' => 'trim', 'skipOnArray' => true ];

			return ArrayHelper::merge( $trim, $rules );
		}

		return $rules;
	}

	// yii\base\Model ---------

	public function attributeLabels() {

		return [
			'newsletterId' => Yii::$app->newsletterMessage->getMessage( NewsletterGlobal::FIELD_NEWSLETTER ),
			'name' => Yii::$app->coreMessage->getMessage( CoreGlobal::FIELD_NAME ),
			'email' => Yii::$app->coreMessage->getMessage( CoreGlobal::FIELD_EMAIL )
		];
	}

	// CMG interfaces ------------------------

	// CMG parent classes --------------------

	// Validators ----------------------------

	// SignUpForm ----------------------------

}


<?php

namespace RocknRoot\StrayFw\Database;

use RocknRoot\StrayFw\Config;
use RocknRoot\StrayFw\Exception\BadUse;
use RocknRoot\StrayFw\Exception\DatabaseNotFound;
use RocknRoot\StrayFw\Exception\ExternalLink;

/**
 * Database representation class.
 *
 * @author Nekith <nekith@errant-works.com>
 */
class Database
{
    /**
     * Registered databases.
     *
     * @static
     * @var array<string, Database>
     */
    protected static $databases = array();

    /**
     * Database alias.
     *
     * @var string
     */
    protected $alias;

    /**
     * Provider's classes namespace.
     *
     * @var string
     */
    protected $providerNamespace;

    /**
     * Provider's instance.
     *
     * @var Provider\Database
     */
    protected $providerDatabase;

    /**
     * Servers info.
     *
     * @var array
     */
    protected $servers;

    /**
     * Transaction level.
     * If 0, there's no happening transaction.
     * If 1, it's a classic transaction.
     * If >= 2, there's at least one save point.
     *
     * @var int
     */
    protected $transactionLevel;

    /**
     * Construct a new database representation.
     *
     * @throws DatabaseNotFound if database parameters in settings can't be found
     * @throws BadUse           if database parameters in settings aren't well formatted
     * @throws BadUse           if database parameters in settings miss provider
     * @param  string           $alias database alias
     */
    protected function __construct(string $alias)
    {
        $this->alias = $alias;
        $this->transactionLevel = 0;
        $settings = Config::getSettings();
        if (isset($settings['databases']) === false || isset($settings['databases'][$alias]) === false) {
            throw new DatabaseNotFound('database "' . $alias . '" parameters can\'t be found in settings.yml');
        }
        $config = $settings['databases'][$alias];
        if (isset($config['provider']) === false) {
            throw new BadUse('database "' . $alias . '" parameters in settings.yml miss provider');
        }
        $this->providerNamespace = $config['provider'];
        if ($this->providerNamespace[0] != '\\') {
            $this->providerNamespace = __NAMESPACE__ . '\\' . $this->providerNamespace;
        }
        $database = $this->providerNamespace . '\\Database';
        $this->providerDatabase = new $database();
        if (isset($config['name']) === true) {
            $info = array();
            $info['host'] = $config['host'];
            $info['port'] = $config['port'];
            $info['name'] = $config['name'];
            $info['user'] = $config['user'];
            $info['pass'] = $config['pass'];
            $this->servers['all'] = $info;
        } elseif (isset($config['read']) === true && is_array($config['read']) === true && isset($config['write']) === true && is_array($config['write']) === true) {
            $read = $config['read'];
            if (is_array(current($read)) === true) {
                $read = $read[mt_rand(0, count($read) - 1)];
            }
            $info = array();
            $info['host'] = $read['host'];
            $info['port'] = $read['port'];
            $info['name'] = $read['name'];
            $info['user'] = $read['user'];
            $info['pass'] = $read['pass'];
            $this->servers['read'] = $info;
            $write = $config['write'];
            if (is_array(current($write)) === true) {
                $write = $write[mt_rand(0, count($write) - 1)];
            }
            $info = array();
            $info['host'] = $write['host'];
            $info['port'] = $write['port'];
            $info['name'] = $write['name'];
            $info['user'] = $write['user'];
            $info['pass'] = $write['pass'];
            $this->servers['write'] = $info;
        } else {
            throw new BadUse('database "' . $alias . '" parameters in settings.yml aren\'t well formatted');
        }
    }

    /**
     * Ensure that link is disconnected at object destruction.
     */
    public function __destruct()
    {
        $this->disconnect();
    }

    /**
     * Connect to the database.
     *
     * @throws ExternalLink if database connection can't be established
     */
    public function connect()
    {
        if ($this->isConnected() === false) {
            try {
                if (isset($this->servers['all']) === true) {
                    $dsn = $this->providerDatabase->getDsn($this->servers['all']);
                    $this->servers['all']['link'] = new \PDO($dsn, $this->servers['all']['user'], $this->servers['all']['pass']);
                } else {
                    $dsn = $this->providerDatabase->getDsn($this->servers['read']);
                    $this->servers['read']['link'] = new \PDO($dsn, $this->servers['read']['user'], $this->servers['read']['pass']);
                    $dsn = $this->providerDatabase->getDsn($this->servers['write']);
                    $this->servers['write']['link'] = new \PDO($dsn, $this->servers['write']['user'], $this->servers['write']['pass']);
                }
            } catch (\PDOException $e) {
                throw new ExternalLink('can\'t connect to database (' . $e->getMessage() . ')');
            }
        }
    }

    /**
     * Disconnect link to database.
     */
    public function disconnect()
    {
        if (isset($this->servers['all']) === true) {
            unset($this->servers['all']['link']);
        } else {
            unset($this->servers['read']['link']);
            unset($this->servers['write']['link']);
        }
    }

    /**
     * Check if connected to database.
     *
     * @return bool true if connected
     */
    public function isConnected() : bool
    {
        if (isset($this->servers['all']) === true) {
            return isset($this->servers['all']['link']);
        }

        return isset($this->servers['read']['link']) && isset($this->servers['write']['link']);
    }

    /**
     * Get link.
     *
     * @return mixed link info
     */
    public function getLink()
    {
        if ($this->isConnected() === false) {
            $this->connect();
        }
        if (isset($this->servers['all']) === true) {
            return $this->servers['all']['link'];
        }
        if ($this->transactionLevel >= 1) {
            return $this->servers['write']['link'];
        }

        return $this->servers['read']['link'];
    }

    /**
     * Get master server link.
     *
     * @return mixed link info
     */
    public function getMasterLink()
    {
        if ($this->isConnected() === false) {
            $this->connect();
        }
        if (isset($this->servers['all']) === true) {
            return $this->servers['all']['link'];
        }

        return $this->servers['write']['link'];
    }

    /**
     * Begin transaction or create a new save point if already transactionning.
     *
     * @return bool true if successful
     */
    public function beginTransaction() : bool
    {
        if ($this->isConnected() === false) {
            $this->connect();
        }
        ++$this->transactionLevel;
        if ($this->transactionLevel == 1) {
            return $this->providerDatabase->beginTransaction($this->GetMasterLink());
        }

        return $this->providerDatabase->savePoint($this->GetMasterLink(), 'LEVEL' . ($this->transactionLevel - 1));
    }

    /**
     * Commit transaction modifications.
     *
     * @return bool true if successful
     */
    public function commit() : bool
    {
        if ($this->isConnected() === false) {
            $this->connect();
        }
        if ($this->transactionLevel > 0) {
            --$this->transactionLevel;
            if ($this->transactionLevel == 0) {
                return $this->providerDatabase->commit($this->GetMasterLink());
            }

            return $this->providerDatabase->releaseSavePoint($this->GetMasterLink(), 'LEVEL' . $this->transactionLevel);
        }

        return false;
    }

    /**
     * Roll back transaction modifications.
     *
     * @return bool true if successful
     */
    public function rollBack() : bool
    {
        if ($this->isConnected() === false) {
            $this->connect();
        }
        if ($this->transactionLevel > 0) {
            --$this->transactionLevel;
            if ($this->transactionLevel == 0) {
                return $this->providerDatabase->rollBack($this->GetMasterLink());
            }

            return $this->providerDatabase->rollBackSavePoint($this->GetMasterLink(), 'LEVEL' . $this->transactionLevel);
        }

        return false;
    }

    /**
     * Register a new database.
     *
     * @static
     * @param string $alias database alias
     */
    public static function registerDatabase(string $alias)
    {
        if (isset(self::$databases[$alias]) === false) {
            self::$databases[$alias] = new static($alias);
        }
    }

    /**
     * Get a database instance aliased as requested.
     *
     * @static
     * @throws DatabaseNotFound if database isn't registered
     * @param  string           $alias requested database alias
     * @return Database         instance
     */
    public static function get(string $alias)
    {
        if (isset(self::$databases[$alias]) === false) {
            throw new DatabaseNotFound('database "' . $alias . '" doesn\'t seem to be registered');
        }

        return self::$databases[$alias];
    }
}


<?php
/**
 * This file is part of CMSGears Framework. Please view License file distributed
 * with the source code for license details.
 *
 * @link https://www.cmsgears.org/
 * @copyright Copyright (c) 2015 VulpineCode Technologies Pvt. Ltd.
 */

namespace cmsgears\icons\widgets;

// Yii Imports
use yii\helpers\Html;

// CMG Imports
use cmsgears\core\common\base\Widget;

/**
 * TextureChooser widget provide options to choose texture.
 *
 * @since 1.0.0
 */
class TextureChooser extends Widget {

	// Variables ---------------------------------------------------

	// Globals -------------------------------

	// Constants --------------

	// Public -----------------

	// Protected --------------

	// Variables -----------------------------

	// Public -----------------

	public $wrap		= true;

	public $class		= null;
	public $model		= null;
	public $attribute	= 'texture';
	public $label		= 'Texture';
	public $texture		= null;

	public $default		= 'texture'; // none

	public $disabled	= false;

	public $template	= 'texture';

	// Protected --------------

	// Private ----------------

	// Traits ------------------------------------------------------

	// Constructor and Initialisation ------------------------------

	// Instance methods --------------------------------------------

	// Yii interfaces ------------------------

	// Yii parent classes --------------------

	// CMG interfaces ------------------------

	// CMG parent classes --------------------

	// cmsgears\core\common\base\Widget

	public function renderWidget( $config = [] ) {

		$widgetHtml = $this->render( $this->template, [
			'name' => $this->getModelName(),
			'attribute' => $this->attribute,
			'label' => $this->label,
			'texture' => $this->getTexture(),
			'disabled' => $this->disabled
		]);

		if( $this->wrap ) {

			return Html::tag( $this->wrapper, $widgetHtml, $this->options );
		}

		return $widgetHtml;
	}

	// IconChooser ---------------------------

	/**
	 * Return the model name used while submitting the form.
	 *
	 * @return string
	 */
	private function getModelName() {

		// Provided name will override
		if( isset( $this->class ) ) {

			return $this->class;
		}

		// Return class name if model is given
		if( isset( $this->model ) ) {

			$rClass = new \ReflectionClass( $this->model );

			return $rClass->getShortName();
		}

		return 'Icon';
	}

	/**
	 * Return the texture to be displayed.
	 *
	 * @return string
	 */
	private function getTexture() {

		// Provided name will override
		if( isset( $this->model ) ) {

			$texture = $this->attribute;

			if( isset( $this->model->$texture ) ) {

				return $this->model->$texture;
			}
		}

		if( isset( $this->texture ) ) {

			return $this->texture;
		}

		return $this->default;
	}

}