public function getValue()
    {
        $value = $this->value;

        switch ($this->type)
        {
            case self::TOKEN_BOOL_TRUE:
                $value = true;
                break;

            case self::TOKEN_BOOL_FALSE:
                $value = false;
                break;

            case self::TOKEN_STRING:
                $value = str_replace("\\", "", substr($value, 1, -1));
                break;

            case self::TOKEN_NUMBER:
                $value = $value + 0;
                break;

            case self::TOKEN_NULL:
                $value = null;
                break;
        }

        return $value;
    }

public function getValue ( ) { $ value = $ this -> value ; switch ( $ this -> type ) { case self :: TOKEN_BOOL_TRUE : $ value = true ; break ; case self :: TOKEN_BOOL_FALSE : $ value = false ; break ; case self :: TOKEN_STRING : $ value = str_replace ( "\\" , "" , substr ( $ value , 1 , - 1 ) ) ; break ; case self :: TOKEN_NUMBER : $ value = $ value + 0 ; break ; case self :: TOKEN_NULL : $ value = null ; break ; } return $ value ; }

Get the tokens value as php native type.

@return mixed

Get the tokens value as php native type .


public function isValue() : bool
    {
        return
        $this->type === self::TOKEN_STRING ||
        $this->type === self::TOKEN_NUMBER ||
        $this->type === self::TOKEN_NULL ||
        $this->type === self::TOKEN_BOOL_TRUE ||
        $this->type === self::TOKEN_BOOL_FALSE;
    }

public function isValue ( ) : bool { return $ this -> type === self :: TOKEN_STRING || $ this -> type === self :: TOKEN_NUMBER || $ this -> type === self :: TOKEN_NULL || $ this -> type === self :: TOKEN_BOOL_TRUE || $ this -> type === self :: TOKEN_BOOL_FALSE ; }


public function has($key)
    {
        foreach ($this->elements as $element) {
            if ($element->getKey() == $key) {
                return true;
            }
        }

        return false;
    }

public function has ( $ key ) { foreach ( $ this -> elements as $ element ) { if ( $ element -> getKey ( ) == $ key ) { return true ; } } return false ; }

Checks if an element with the given key already exists

@param string|int            $key
@return bool


public function push(AssignableNode $value)
    {
        // count the index up to find a free spot
        while ($this->has($this->index)) {
            $this->index++;
        }

        $this->addElement(new ArrayElementNode($this->index, $value));
    }

Pushes an assignable node to the array elements

@param AssignableNode            $value
@return void


public function convertToNativeArray() : array
    {
        $array = [];

        foreach($this->getElements() as $element)
        {
            $value = $element->getValue();

            if ($value instanceof ValueNode) {
                $array[$element->getKey()] = $value->getRawValue();
            }
            elseif ($value instanceof ArrayNode) {
                $array[$element->getKey()] = $value->convertToNativeArray();
            }
            else {
                throw new LogicalNodeException("You cannot convert a ctn array to PHP that contains a reference to a service or parameter.");
            }
        }

        return $array;
    }

Converts the current array to a PHP array
This will throw an exception when the array contains a reference
to a service or parameter

@return array


protected function next()
    {
        if ($this->offset >= $this->length)
        {
            return false;
        }

        foreach ($this->tokenMap as $regex => $token)
        {
            if (preg_match($regex, substr($this->code, $this->offset), $matches))
            {
                if ($token === T::TOKEN_LINE) {
                    $this->line++;
                }

                $this->offset += strlen($matches[0]);

                return new T($this->line + 1, $token, $matches[0]);
            }
        }

        throw new ContainerLexerException(sprintf('Unexpected character "%s" on line %s', $this->code[$this->offset], $this->line));
    }

protected
function
next
(
)
{
if
(
$
this
->
offset
>=
$
this
->
length
)
{
return
false
;
}
foreach
(
$
this
->
tokenMap
as
$
regex
=>
$
token
)
{
if
(
preg_match
(
$
regex
,
substr
(
$
this
->
code
,
$
this
->
offset
)
,
$
matches
)
)
{
if
(
$
token
===
T
::
TOKEN_LINE
)
{
$
this
->
line
++
;
}
$
this
->
offset
+=
strlen
(
$
matches
[
0
]
)
;
return
new
T
(
$
this
->
line
+
1
,
$
token
,
$
matches
[
0
]
)
;
}
}
throw
new
ContainerLexerException
(
sprintf
(
'Unexpected character "%s" on line %s'
,
$
this
->
code
[
$
this
->
offset
]
,
$
this
->
line
)
)
;
}

Get the next token from our code

@throws ContainerLexerException

@return string|false Returns `false` if everything has been parsed and we are done.


public function tokens() : array
    {
        $tokens = [];

        while ($token = $this->next())
        {
            // skip doublicated linebreaks
            if (
                $token->getType() === T::TOKEN_LINE &&
                isset($tokens[count($tokens) - 1]) &&
                $tokens[count($tokens) - 1]->getType() === T::TOKEN_LINE
            ) {
                continue;
            }

            $tokens[] = $token;
        }

        return $tokens;
    }

public
function
tokens
(
)
:
array
{
$
tokens
=
[
]
;
while
(
$
token
=
$
this
->
next
(
)
)
{
// skip doublicated linebreaks
if
(
$
token
->
getType
(
)
===
T
::
TOKEN_LINE
&&
isset
(
$
tokens
[
count
(
$
tokens
)
1
]
)
&&
$
tokens
[
count
(
$
tokens
)
1
]
->
getType
(
)
===
T
::
TOKEN_LINE
)
{
continue
;
}
$
tokens
[
]
=
$
token
;
}
return
$
tokens
;
}

Start the lexer and retrieve all resulting tokens.

@return array[Token]

Start the lexer and retrieve all resulting tokens .


public function index()
    {
        // set up logging to email
        $this->log = Log::getMonolog();
        if ($to = config('auto-deploy.notify')) {
            $domain = parse_url(config('app.url'), PHP_URL_HOST);
            $msg = \Swift_Message::newInstance('Project Deployed')
                    ->setFrom(["do_not_reply@$domain" => "Laravel Auto-Deploy[$domain]"])
                    ->setTo($to)
                    ->setBody('', 'text/html');
            $handler = new SwiftMailerHandler(Mail::getSwiftMailer(), $msg, Logger::NOTICE);
            $handler->setFormatter(new HtmlFormatter());
            $this->log->pushHandler($handler);
        }

        // check to see if we should execute this event
        if (in_array($this->origin->event(), array_keys(config("auto-deploy.{$this->origin->name}")))) {
            // get the parameters for the event we're handling
            $configKey = "auto-deploy.{$this->origin->name}.{$this->origin->event()}";
            $this->webroot = config("$configKey.webroot");
            $this->installDir = dirname($this->webroot).'/'.date('Y-m-d').'_'.$this->commitId;
            $steps = config("$configKey.steps");

            // execute the configured steps
            $this->result = [
                'Commit_ID' => $this->commitId,
                'Timestamp' => date('r'),
                'output' => '',
            ];
            $whitelist = ['backupDatabase','pull','copyEnv','composer','npm','migrate','seed','deploy'];
            foreach ($steps as $step) {
                if (in_array($step, $whitelist) && !$this->{$step}()) {
                    $this->log->error('Deploy failed.', $this->result);

                    return;
                }
            }
            $this->log->notice('Deploy succeeded!', $this->result);
        } else {
            $this->log->error('Deploy failed.', ['Reason' => 'This event was not configured.']);
        }
    }


private function ex(CommandInterface $cmd)
    {
        // try to run the command
        $this->shell->run($cmd);
        $output = $this->shell->getOutput();
        $returnValue = $this->shell->getReturnValue();

        // record the result
        $output = count($output) ? implode("\n", $output)."\n" : '';
        $this->result['output'] .= "$cmd\n$output";

        // return a boolean
        return 0 === $returnValue;
    }

private
function
ex
(
CommandInterface
$
cmd
)
{
// try to run the command
$
this
->
shell
->
run
(
$
cmd
)
;
$
output
=
$
this
->
shell
->
getOutput
(
)
;
$
returnValue
=
$
this
->
shell
->
getReturnValue
(
)
;
// record the result
$
output
=
count
(
$
output
)
implode
(
"\n"
,
$
output
)
.
"\n"
:
''
;
$
this
->
result
[
'output'
]
.=
"$cmd\n$output"
;
// return a boolean
return
0
===
$
returnValue
;
}

Runs a shell command, logs, and handles the result.

@param AdamBrett\ShellWrapper\CommandInterface $cmd The text of the command to be run

@return bool True if the command was successful, false on error

Runs a shell command logs and handles the result .


private function backupDatabase()
    {
        // get the name of the DB to backed up and the connection to use
        $dbdir = database_path();
        $dbconn = config('database.default');
        $dbname = config("database.connections.$dbconn.database");

        // make a directory for the backup file and switch into that directory
        $cmd = new Command('cd');
        $cmd->addParam($dbdir)
            ->addSubCommand('&&')
            ->addSubCommand('mkdir')
            ->addParam('backups');
        if ($this->ex($cmd)) {
            $cmd = new Command('cd');
            $cmd->addParam($dbdir.'/backups')
                ->addSubCommand('&&');
            switch ($dbconn) {
                case 'sqlite':
                    $cmd->addSubCommand('cp');
                    $cmd->addParam($dbname)
                        ->addParam('.');

                    return $this->ex($cmd);
                case 'mysql':
                    $cmd->addSubCommand('mysqldump');
                    $cmd->addParam($dbname)
                        ->addParam('>')
                        ->addParam("$dbname.sql");

                    return $this->ex($cmd);
                case 'pgsql':
                    $cmd->addSubCommand('pg_dump');
                    $cmd->addParam($dbname)
                        ->addParam('>')
                        ->addParam("$dbname.sql");

                    return $this->ex($cmd);
            }
        }

        return false;
    }

Backup the database.

@return bool True if the database was successfully backed up. False on error.


private function pull()
    {
        if (is_writable(dirname($this->installDir))) {
            $cmd = new Command('mkdir');
            $cmd->addFlag('p')
                ->addParam($this->installDir);
            if ($this->ex($cmd)) {
                $cmd = new Command('cd');
                $cmd->addParam($this->installDir)
                    ->addSubCommand('&&')
                    ->addSubCommand('git')
                    ->addSubCommand('clone')
                    ->addParam($this->repoUrl)
                    ->addParam('.');

                return $this->ex($cmd);
            }
        }

        return false;
    }

private function pull ( ) { if ( is_writable ( dirname ( $ this -> installDir ) ) ) { $ cmd = new Command ( 'mkdir' ) ; $ cmd -> addFlag ( 'p' ) -> addParam ( $ this -> installDir ) ; if ( $ this -> ex ( $ cmd ) ) { $ cmd = new Command ( 'cd' ) ; $ cmd -> addParam ( $ this -> installDir ) -> addSubCommand ( '&&' ) -> addSubCommand ( 'git' ) -> addSubCommand ( 'clone' ) -> addParam ( $ this -> repoUrl ) -> addParam ( '.' ) ; return $ this -> ex ( $ cmd ) ; } } return false ; }

Create a new directory parallel to the webroot and clone the project into that directory.

@return bool True if the clone is successful. False otherwise.

Create a new directory parallel to the webroot and clone the project into that directory .


private function copyEnv()
    {
        $cmd = new Command('cp');
        $cmd->addParam($this->webroot.'./env')
            ->addParam($this->installDir.'/.env');

        return $this->ex($cmd);
    }

private function copyEnv ( ) { $ cmd = new Command ( 'cp' ) ; $ cmd -> addParam ( $ this -> webroot . './env' ) -> addParam ( $ this -> installDir . '/.env' ) ; return $ this -> ex ( $ cmd ) ; }

Copy the .env file from the new deploy directory.

@return bool True if the update is successful. False otherwise.

Copy the . env file from the new deploy directory .


private function composer()
    {
        $cmd = new Command('cd');
        $cmd->addParam($this->installDir)
            ->addSubCommand('&&')
            ->addSubCommand('composer')
            ->addParam('self-update')
            ->addSubCommand('&&')
            ->addSubCommand('composer')
            ->addParam('update')
            ->addArgument('no-interaction');

        return $this->ex($cmd);
    }

private function composer ( ) { $ cmd = new Command ( 'cd' ) ; $ cmd -> addParam ( $ this -> installDir ) -> addSubCommand ( '&&' ) -> addSubCommand ( 'composer' ) -> addParam ( 'self-update' ) -> addSubCommand ( '&&' ) -> addSubCommand ( 'composer' ) -> addParam ( 'update' ) -> addArgument ( 'no-interaction' ) ; return $ this -> ex ( $ cmd ) ; }

Update composer and run composer update.

@return bool True if the update is successful. False otherwise.

Update composer and run composer update .


private function npm()
    {
        $cmd = new Command('cd');
        $cmd->addParam($this->installDir)
            ->addSubCommand('&&')
            ->addSubCommand('npm')
            ->addParam('update');

        return $this->ex($cmd);
    }

private function npm ( ) { $ cmd = new Command ( 'cd' ) ; $ cmd -> addParam ( $ this -> installDir ) -> addSubCommand ( '&&' ) -> addSubCommand ( 'npm' ) -> addParam ( 'update' ) ; return $ this -> ex ( $ cmd ) ; }

Run npm update.

@return bool True if npm is successful. False otherwise.


private function seed()
    {
        $cmd = new Command('cd');
        $cmd->addParam($this->installDir)
            ->addSubCommand('&&')
            ->addSubCommand('php')
            ->addSubCommand('artisan')
            ->addParam('db:seed');

        return $this->ex($cmd);
    }

private function seed ( ) { $ cmd = new Command ( 'cd' ) ; $ cmd -> addParam ( $ this -> installDir ) -> addSubCommand ( '&&' ) -> addSubCommand ( 'php' ) -> addSubCommand ( 'artisan' ) -> addParam ( 'db:seed' ) ; return $ this -> ex ( $ cmd ) ; }

Run any necessary database migrations.

@return bool True if the migration is successful. False otherwise.


private function deploy()
    {
        $cmd = new Command('cd');
        $cmd->addParam(dirname($this->webroot))
            ->addSubCommand('&&')
            ->addSubCommand('ln')
            ->addFlag('fs')
            ->addParam($this->installDir)
            ->addParam($this->webroot);

        return $this->ex($cmd);
    }

private function deploy ( ) { $ cmd = new Command ( 'cd' ) ; $ cmd -> addParam ( dirname ( $ this -> webroot ) ) -> addSubCommand ( '&&' ) -> addSubCommand ( 'ln' ) -> addFlag ( 'fs' ) -> addParam ( $ this -> installDir ) -> addParam ( $ this -> webroot ) ; return $ this -> ex ( $ cmd ) ; }

Symlinks the new deploy directory to the webroot.

@return bool True if the symlink is successful. False otherwise.

Symlinks the new deploy directory to the webroot .


public function resolve(string $serviceName, Container $container) : array
    {
        if (!isset($this->services[$serviceName]))
        {
            throw new UnknownServiceException('The service provider "' . get_class($this) . '" does not support service resolving of the service "' . $serviceName . '"');
        }

        $serviceConfiguration = $this->services[$serviceName];

        // create the factory
        $factory = ServiceFactory::fromArray($serviceConfiguration);

        // resolve the service
        $service = $factory->create($container);

        // if the service is not shared skip the store
        if ((!isset($serviceConfiguration['shared'])) || $serviceConfiguration['shared'] !== false)
        {
            return [$service, true];
        }

        return [$service, false];
    }

Resolve a service with the given name

@param string                    $serviceName
@param Container                 $container
@return array[mixed, bool]


public function setCacheDirecotry(string $cacheDirectory)
    {
        if (substr($cacheDirectory, -1) !== DIRECTORY_SEPARATOR)
        {
            $cacheDirectory .= DIRECTORY_SEPARATOR;
        }

        $this->cacheDirectory = $cacheDirectory;
    }

public function setCacheDirecotry ( string $ cacheDirectory ) { if ( substr ( $ cacheDirectory , - 1 ) !== DIRECTORY_SEPARATOR ) { $ cacheDirectory .= DIRECTORY_SEPARATOR ; } $ this -> cacheDirectory = $ cacheDirectory ; }

Set the cache directory

@param string        $cacheDirectory
@return void


public function create(string $containerName, callable $builderCallback, array $initalParameters = []) : Container
    {
        if (class_exists($containerName))
        {
            return new $containerName;
        }

        $fileName = basename(str_replace("\\", '/', $containerName));
        $cacheFile = $this->cacheDirectory . $fileName . '.php';

        if ((!(file_exists($cacheFile) && is_readable($cacheFile))) || $this->isDebugMode())
        {
            $builder = new ContainerBuilder($containerName);

            // run the builder callback
            $builderCallback($builder);

            // store the cache file
            $cacheDir = dirname($cacheFile);

            if (!is_dir($cacheDir) || !is_writable($cacheDir)) {
                throw new ContainerException("The directory \"{$cacheDir}\" is not writable. Cannot generate container class.");
            } elseif (is_file($cacheFile) && !is_writable($cacheFile)) {
                throw new ContainerException("The file \"{$cacheFile}\" is not writable. Cannot generate container class.");
            }

            file_put_contents($cacheFile, $builder->generate());
        }

        // require the generated cache file
        require_once $cacheFile;

        // create an instance of the generated container
        return new $containerName($initalParameters);
    }

Create a container with the given name. You can pass an
array with services

@param string                $containerName
@param callable              $builderCallback
@param array                 $initalParameters

@return Container The generated container instnace.

Create a container with the given name . You can pass an array with services


public function handle($request, Closure $next)
    {
        if ($request->path() === config('auto-deploy.route')) {
            if (!config('auto-deploy.require-ssl') || $request->secure()) {
                $origin = $this->determineOrigin();
                if (null !== $origin) {
                    if ($origin->isAuthentic()) {
                        // set the origin type in the controller
                        $request->offsetSet('origin', $origin);

                        return $next($request);
                    } else {
                        abort(403, 'Forbidden. Could not verify the origin of the request.');
                    }
                } else {
                    abort(403, 'Forbidden. Could not determine the origin of the request.');
                }
            } else {
                abort(403, 'Forbidden. Webhook requests must be sent using SSL.');
            }
        }
        // Passthrough if it's not our specific route
        return $next($request);
    }

Handles the HTTP request.

@param Illuminate\Http\Request $request The request
@param Closure                 $next    Mechanism for passing the result down the pipeline to the next piece of middleware

@return Illuminate\Http\Response A Response object that is passed to the next piece of middleware


public function importFromVendor(string $vendorDir)
    {
        $mappingFile = $vendorDir . '/container_map.php';

        if (!(file_exists($mappingFile) && is_readable($mappingFile)))
        {
            throw new ContainerNamespaceException("Could not find the the container map file at: " . $mappingFile);
        }

        $vendorPaths = require $mappingFile;
        $this->paths = array_merge($vendorPaths, $this->paths);
    }

Import paths from vendor container map

@param string                $vendorDir
@return void


public function has(string $name) : bool
    {
        return isset($this->paths[$name]) && is_string($this->paths[$name]);
    }

public function has ( string $ name ) : bool { return isset ( $ this -> paths [ $ name ] ) && is_string ( $ this -> paths [ $ name ] ) ; }

Is the given path name binded?

@param string            $name The container files path key.
@return bool


protected function getCodeFromFile(string $containerFilePath) : string
    {
        if (!file_exists($containerFilePath) || !is_readable($containerFilePath))
        {
            throw new ContainerNamespaceException("The file '" . $containerFilePath . "' is not readable or does not exist.");
        }

        return file_get_contents($containerFilePath);
    }

protected
function
getCodeFromFile
(
string
$
containerFilePath
)
:
string
{
if
(
!
file_exists
(
$
containerFilePath
)
||
!
is_readable
(
$
containerFilePath
)
)
{
throw
new
ContainerNamespaceException
(
"The file '"
.
$
containerFilePath
.
"' is not readable or does not exist."
)
;
}
return
file_get_contents
(
$
containerFilePath
)
;
}

Simply returns the contents of the given file

@param return string         $containerFilePath The path to a container file.
@return string


public function getCode(string $name) : string
    {
        if (!$this->has($name))
        {
            throw new ContainerNamespaceException("There is no path named '" . $name . "' binded to the namespace.");
        }

        return $this->getCodeFromFile($this->paths[$name]);
    }

public
function
getCode
(
string
$
name
)
:
string
{
if
(
!
$
this
->
has
(
$
name
)
)
{
throw
new
ContainerNamespaceException
(
"There is no path named '"
.
$
name
.
"' binded to the namespace."
)
;
}
return
$
this
->
getCodeFromFile
(
$
this
->
paths
[
$
name
]
)
;
}

Returns the code of in the current namespace binded file.

@return string           $name The container files path key.

Returns the code of in the current namespace binded file .


public function parse(string $containerFilePath)
    {
        // create a lexer from the given file
        $lexer = new ContainerLexer($this->getCodeFromFile($containerFilePath));

        // parse the file
        $parser = new ScopeParser($lexer->tokens());

        // interpret the parsed node
        $interpreter = new ContainerInterpreter($this);
        $interpreter->handleScope($parser->parse());
    }

public
function
parse
(
string
$
containerFilePath
)
{
// create a lexer from the given file
$
lexer
=
new
ContainerLexer
(
$
this
->
getCodeFromFile
(
$
containerFilePath
)
)
;
// parse the file
$
parser
=
new
ScopeParser
(
$
lexer
->
tokens
(
)
)
;
// interpret the parsed node
$
interpreter
=
new
ContainerInterpreter
(
$
this
)
;
$
interpreter
->
handleScope
(
$
parser
->
parse
(
)
)
;
}

Parse the given container file with the current namespace

@param string        $containerFilePath The path to a container file.


public function handleScope(ScopeNode $scope)
    {
    	foreach($scope->getNodes() as $node)
    	{
    		if ($node instanceof ScopeImportNode)
    		{
    			$this->handleScopeImport($node);
    		}
            elseif ($node instanceof ParameterDefinitionNode)
            {
                $this->handleParameterDefinition($node);
            }
            elseif ($node instanceof ServiceDefinitionNode)
            {
                $this->handleServiceDefinition($node);
            }
    		else
    		{
    			throw new ContainerInterpreterException("Unexpected node in scope found.");
    		}
    	}
    }

public
function
handleScope
(
ScopeNode
$
scope
)
{
foreach
(
$
scope
->
getNodes
(
)
as
$
node
)
{
if
(
$
node
instanceof
ScopeImportNode
)
{
$
this
->
handleScopeImport
(
$
node
)
;
}
elseif
(
$
node
instanceof
ParameterDefinitionNode
)
{
$
this
->
handleParameterDefinition
(
$
node
)
;
}
elseif
(
$
node
instanceof
ServiceDefinitionNode
)
{
$
this
->
handleServiceDefinition
(
$
node
)
;
}
else
{
throw
new
ContainerInterpreterException
(
"Unexpected node in scope found."
)
;
}
}
}

Handle a container file scope

@param ScopeNode 			$scope
@return void


public function handleScopeImport(ScopeImportNode $import)
    {
        $path = $import->getPath();

        if (is_null($path) || empty($path))
        {
            throw new ContainerInterpreterException("An import statement cannot be empty.");
        }

        $code = $this->namespace->getCode($path);

        // after retrieving new code we have
        // to start a new lexer & and parser
        $lexer = new ContainerLexer($code);
        $parser = new ScopeParser($lexer->tokens());
        $scopeNode = $parser->parse();

        unset($lexer, $parser);

        // and continue handling the importet scope
        $this->handleScope($scopeNode);
    }

Handle a scope import statement

@param ScopeImportNode           $import
@return void


public function handleParameterDefinition(ParameterDefinitionNode $definition)
    {
        if ($this->namespace->hasParameter($definition->getName()) && $definition->isOverride() === false)
        {
            throw new ContainerInterpreterException("A parameter named \"{$definition->getName()}\" is already defined, you can prefix the definition with \"override\" to get around this error.");
        }

        if ($definition->getValue() instanceof ValueNode) {
            $this->namespace->setParameter($definition->getName(), $definition->getValue()->getRawValue());
        }
        elseif ($definition->getValue() instanceof ArrayNode) {
            $this->namespace->setParameter($definition->getName(), $definition->getValue()->convertToNativeArray());
        }
        else {
            throw new ContainerInterpreterException("Invalid parameter value given for key \"{$definition->getName()}\".");
        }
    }

Handle a parameter definition

@param ParameterDefinitionNode 			$definition
@return void


protected function createServiceArgumentsFromNode(ArgumentArrayNode $argumentsNode) : ServiceArguments
    {
        $arguments = $argumentsNode
            ->getArguments();

        $definition = new ServiceArguments();

        foreach($arguments as $argument)
        {
            if ($argument instanceof ServiceReferenceNode)
            {
                $definition->addDependency($argument->getName());
            }
            elseif ($argument instanceof ParameterReferenceNode)
            {
                $definition->addParameter($argument->getName());
            }
            elseif ($argument instanceof ArrayNode)
            {
                $definition->addRaw($argument->convertToNativeArray());
            }
            elseif ($argument instanceof ValueNode)
            {
                $definition->addRaw($argument->getRawValue());
            }
            else
            {
                throw new ContainerInterpreterException("Unable to handle argument node of type \"" . get_class($argument) . "\".");
            }
        }

        return $definition;
    }

Create final service arguments from an arguments array node

@param ArgumentArrayNode         $argumentsNode
@return ServiceArguments


public function handleServiceDefinition(ServiceDefinitionNode $definition)
    {
        if ($this->namespace->hasService($definition->getName()) && $definition->isOverride() === false)
        {
            throw new ContainerInterpreterException("A service named \"{$definition->getName()}\" is already defined, you can prefix the definition with \"override\" to get around this error.");
        }

        // create a service definition from the node
        $service = new ServiceDefinition($definition->getClassName());

        if ($definition->hasArguments())
        {
            $arguments = $definition
                ->getArguments() // get the definitions arguments
                ->getArguments(); // and the argument array from the object

            foreach($arguments as $argument)
            {
                if ($argument instanceof ServiceReferenceNode)
                {
                    $service->addDependencyArgument($argument->getName());
                }
                elseif ($argument instanceof ParameterReferenceNode)
                {
                    $service->addParameterArgument($argument->getName());
                }
                elseif ($argument instanceof ArrayNode)
                {
                    $service->addRawArgument($argument->convertToNativeArray());
                }
                elseif ($argument instanceof ValueNode)
                {
                    $service->addRawArgument($argument->getRawValue());
                }
                else
                {
                    throw new ContainerInterpreterException("Unable to handle argument node of type \"" . get_class($argument) . "\".");
                }
            }
        }

        // handle construction actions
        foreach($definition->getConstructionActions() as $action)
        {
            if ($action instanceof ServiceMethodCallNode)
            {
                if ($action->hasArguments())
                {
                    $service->addMethodCall($action->getName(), $this->createServiceArgumentsFromNode($action->getArguments()));
                } else {
                    $service->calls($action->getName());
                }
            }
            else
            {
                throw new ContainerInterpreterException("Invalid construction action of type \"" . get_class($action) . "\" given.");
            }
        }

        // handle meta data
        foreach($definition->getMetaDataAssignemnts() as $meta)
        {
            if ($meta instanceof MetaDataAssignmentNode)
            {
                if ($meta->hasData())
                {
                    $service->addMetaData($meta->getKey(), $meta->getData()->convertToNativeArray());
                } else {
                    $service->addMetaData($meta->getKey(), []);
                }
            }
            else
            {
                throw new ContainerInterpreterException("Invalid meta data assignment \"" . get_class($meta) . "\" given.");
            }
        }

        // add the node to the namespace
        $this->namespace->setService($definition->getName(), $service);
    }

Handle a service definition

@param ParameterDefinitionNode           $definition
@return void


public static function fromArray(array $serviceConfiguration)
    {
        if (!isset($serviceConfiguration['class']))
        {
            throw new InvalidServiceException('The service configuration must define a "class" attribute.');
        }

        // construct the service definition
        $defintion = new static($serviceConfiguration['class'], $serviceConfiguration['arguments'] ?? []);

        // add service method calls if configured
        if (isset($serviceConfiguration['calls']))
        {
            foreach($serviceConfiguration['calls'] as $call)
            {
                if (isset($call['method']) && isset($call['arguments']))
                {
                    $defintion->calls($call['method'], $call['arguments']);
                }
                else
                {
                    throw new InvalidServiceException('Every service call must have the attributes "method" and "arguments".');
                }
            }
        }

        return $defintion;
    }

Construct a single service definition object from an array

ServiceDefinition::fromArray([
'class' => '\Acme\Demo',
'arguments' => ['@foo', ':bar'],
'calls' => [
['method' => 'setName', [':demo.name']]
]
])

@param array             $serviceConfiguration
@return static


public function calls(string $method, array $arguments = []) : ServiceDefinition
    {
        return $this->addMethodCall($method, new ServiceArguments($arguments));
    }

public function calls ( string $ method , array $ arguments = [ ] ) : ServiceDefinition { return $ this -> addMethodCall ( $ method , new ServiceArguments ( $ arguments ) ) ; }

Adds a method call to the service definition, the arguments should be set as an array.

@param string            $method The name of the method to be called.
@param array             $arguments The method arguments as array.
@return self

Adds a method call to the service definition the arguments should be set as an array .


public function addMethodCall(string $methodName, ServiceArguments $arguments) : ServiceDefinition
    {
        $this->methodCallers[] = [$methodName, $arguments]; return $this;
    }

public function addMethodCall ( string $ methodName , ServiceArguments $ arguments ) : ServiceDefinition { $ this -> methodCallers [ ] = [ $ methodName , $ arguments ] ; return $ this ; }

Adds a method call to the service definition, the arguments must be set with a ServiceArguments instance.

@param string                    $methodName The name of the method to be called.
@param ServiceArguments          $arguments An `ServiceArguments` instance for the method call.
@return self

Adds a method call to the service definition the arguments must be set with a ServiceArguments instance .


public function addMetaData(string $key, array $values)
    {
        if (!isset($this->metaData[$key])) {
            $this->metaData[$key] = [];
        }

        $this->metaData[$key][] = $values; return $this;
    }

public function addMetaData ( string $ key , array $ values ) { if ( ! isset ( $ this -> metaData [ $ key ] ) ) { $ this -> metaData [ $ key ] = [ ] ; } $ this -> metaData [ $ key ] [ ] = $ values ; return $ this ; }

Sets meta data for the given key

@param string        $key
@param array         $values
@return self


public function isOrigin()
    {
        // Correct IP range for Github maintained here:
        // https://help.github.com/articles/what-ip-addresses-does-github-use-that-i-should-whitelist/
        $hasGithubHeader = false !== strpos($this->request->header('User-Agent'), 'GitHub-Hookshot');
        $hasGithubIp = $this->isIpInRange($this->request->server('REMOTE_ADDR'), '192.30.252.0', 22);

        return $hasGithubHeader && $hasGithubIp;
    }

Determines whether or not the Request originated from Github.

@return bool Returns true if the request originated from Github. False otherwise.

Determines whether or not the Request originated from Github .


public function isAuthentic()
    {
        // get the Github signature
        $xhub = $this->request->header('X-Hub-Signature') ?: 'nothing';

        // reconstruct the hash on this side
        $hash = 'sha1='.hash_hmac('sha1', $this->request->getContent(), config('auto-deploy.secret'));

        // securely compare them
        return hash_equals($xhub, $hash);
    }

public
function
isAuthentic
(
)
{
// get the Github signature
$
xhub
=
$
this
->
request
->
header
(
'X-Hub-Signature'
)
:
'nothing'
;
// reconstruct the hash on this side
$
hash
=
'sha1='
.
hash_hmac
(
'sha1'
,
$
this
->
request
->
getContent
(
)
,
config
(
'auto-deploy.secret'
)
)
;
// securely compare them
return
hash_equals
(
$
xhub
,
$
hash
)
;
}

Verifies the authenticity of a webhook request from Github.

Follows the procedure described here: https://developer.github.com/webhooks/securing/

@return bool Returns true if the request is authentic. False otherwise.

Verifies the authenticity of a webhook request from Github .


public function setValue(AssignableNode $value)
    {
        // we currently only allow Arrays & scalar values
        // it not yet possible assign a reference to a parameter
        if (!($value instanceof ValueNode || $value instanceof ArrayNode)) {
            throw new LogicalNodeException("It is not possible to pass a reference of a parameter or service to a parameter definition.");
        }

        $this->value = $value;
    }

Set the parameters value

@param ValueNode             $value
@return void


static function getName($id)
    {
        try {
            return self::TYPES_NAMES[$id];
        } catch (\Exception $e) {
            throw new EndomondoWorkoutException('Unknown workout type', $e->getCode(), $e->getPrevious());
        }
    }

static
function
getName
(
$
id
)
{
try
{
return
self
::
TYPES_NAMES
[
$
id
]
;
}
catch
(
\
Exception
$
e
)
{
throw
new
EndomondoWorkoutException
(
'Unknown workout type'
,
$
e
->
getCode
(
)
,
$
e
->
getPrevious
(
)
)
;
}
}

Get name of workot in human readable time.

@param $id int Workout type id
@return string Name of workout
@throws EndomondoWorkoutException when workout type is not defined

Get name of workot in human readable time .


public function toString()
    {
        if ($this->getTime() !== null) {
            $time = $this->getTime()->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d H:i:s \U\T\C');
        } else {
            $time = '';
        }
        return $time . ';' .
            $this->getInstruction() . ';' .
            $this->getLatitude() . ';' .
            $this->getLongitude() . ';' .
            $this->getDistance() . ';' .
            $this->getSpeed() . ';' .
            $this->getAltitude() . ';' .
            $this->getHeartRate() . ';' .
            $this->getCadence() . ';' .
            "\n";
    }

public
function
toString
(
)
{
if
(
$
this
->
getTime
(
)
!==
)
{
$
time
=
$
this
->
getTime
(
)
->
setTimezone
(
new
\
DateTimeZone
(
'UTC'
)
)
->
format
(
'Y-m-d H:i:s \U\T\C'
)
;
}
else
{
$
time
=
''
;
}
return
$
time
.
';'
.
$
this
->
getInstruction
(
)
.
';'
.
$
this
->
getLatitude
(
)
.
';'
.
$
this
->
getLongitude
(
)
.
';'
.
$
this
->
getDistance
(
)
.
';'
.
$
this
->
getSpeed
(
)
.
';'
.
$
this
->
getAltitude
(
)
.
';'
.
$
this
->
getHeartRate
(
)
.
';'
.
$
this
->
getCadence
(
)
.
';'
.
"\n"
;
}

Convert point to string readable by Endomondo

@return string


public function send(): bool
    {
        $response = $this->client->request(
            'POST',
            $this->client->getConfig('base_uri')->getPath(),
            $this->buildPayload()
        );

        return $response->getStatusCode() === 200;
    }

public function send ( ) : bool { $ response = $ this -> client -> request ( 'POST' , $ this -> client -> getConfig ( 'base_uri' ) -> getPath ( ) , $ this -> buildPayload ( ) ) ; return $ response -> getStatusCode ( ) === 200 ; }

Send the Webhook

@return bool
@throws GuzzleException


public function setTypeId($id)
    {
        if (!WorkoutType::exist($id)) {
            throw new EndomondoWorkoutException('Unknown workout type');
        };

        $this->typeId = $id;
        return $this;
    }

public
function
setTypeId
(
$
id
)
{
if
(
!
WorkoutType
::
exist
(
$
id
)
)
{
throw
new
EndomondoWorkoutException
(
'Unknown workout type'
)
;
}
;
$
this
->
typeId
=
$
id
;
return
$
this
;
}

Set workout type id.

@param $id integer
@return $this
@throws EndomondoWorkoutException when workout type is unknown.


public function getEnd()
    {
        // if end property is defined, use it
        if ($this->end) {
            return clone $this->end;
        }

        $numberOfPosts = count($this->getPoints());

        // try to find last time of point and use it as end date
        if ($this->haveGPSData()) {
            return $this->getPoints()[$numberOfPosts - 1]->getTime();
        }

        // if there are no points, calculate end date from duration
        return $this->getStart()->add(new \DateInterval('PT' . $this->getDuration() . 'S'));
    }

Get time of end of workout. It can be manual set or it is counted based on start and duration.

@return \DateTime

Get time of end of workout . It can be manual set or it is counted based on start and duration .


public function getPointsAsString()
    {
        $points = '';

        foreach ($this->getPoints() as $point) {
            $points .= $point->toString();
        }

        return $points;
    }

public function getPointsAsString ( ) { $ points = '' ; foreach ( $ this -> getPoints ( ) as $ point ) { $ points .= $ point -> toString ( ) ; } return $ points ; }

Get array of points as single string.

@return string


public function getGPX()
    {
        // @TODO use some library to generate GPX files
        $xml = new \SimpleXMLElement(
            '<gpx xmlns="http://www.topografix.com/GPX/1/1" '
            . 'xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" '
            . '/>'
        );
        $trk = $xml->addChild('trk');
        $trk->addChild('type', str_replace(', ', '_', strtoupper($this->getTypeName())));
        $trkseg = $trk->addChild('trkseg');

        foreach ($this->getPoints() as $point) {
            $trkpt = $trkseg->addChild('trkpt');
            $trkpt->addChild('time', $point->getTime()->setTimezone(new \DateTimeZone('UTC'))->format('Y-m-d\TH:i:s\Z'));
            $trkpt->addAttribute('lat', $point->getLatitude());
            $trkpt->addAttribute('lon', $point->getLongitude());

            if ($point->getAltitude() !== null) {
                $trkpt->addChild('ele', $point->getAltitude());
            }

            if ($point->getHeartRate() !== null) {
                $ext = $trkpt->addChild('extensions');
                $trackPoint = $ext->addChild('gpxtpx:TrackPointExtension', '', 'gpxtpx');
                $trackPoint->addChild('gpxtpx:hr', $point->getHeartRate(), 'gpxtpx');
            }
        }

        return $xml->asXML();
    }


function collect()
    {
        return [
            'content-type' => $this->response->header('Content-Type'),
            'status_code' => $this->response->getStatus(),
            'headers' => $this->getDataFormatter()->formatVar($this->response->headers->all()),
            'cookies' => $this->getDataFormatter()->formatVar($this->response->cookies->all()),
        ];
    }

function collect ( ) { return [ 'content-type' => $ this -> response -> header ( 'Content-Type' ) , 'status_code' => $ this -> response -> getStatus ( ) , 'headers' => $ this -> getDataFormatter ( ) -> formatVar ( $ this -> response -> headers -> all ( ) ) , 'cookies' => $ this -> getDataFormatter ( ) -> formatVar ( $ this -> response -> cookies -> all ( ) ) , ] ; }

Called by the DebugBar when data needs to be collected

@return array Collected data


public function getModels($columns = ['*'])
    {
        $results = $this->query->get($columns);

        $connection = $this->model->getConnectionName();

        // Check for joined relations
        if (!empty($this->joined)) {
            foreach ($results as $key => $result) {
                $relation_values = [];

                foreach ($result as $column => $value) {
                    Arr::set($relation_values, $column, $value);
                }

                foreach ($this->joined as $relationName) {
                    $relation = $this->getRelation($relationName);

                    $relation_values[$relationName] = $relation->getRelated()->newFromBuilder(
                        Arr::pull($relation_values, $relationName),
                        $connection
                    );
                }

                $results[$key] = $relation_values;
            }
        }

        return $this->model->hydrate($results, $connection)->all();
    }

public
function
getModels
(
$
columns
=
[
'*'
]
)
{
$
results
=
$
this
->
query
->
get
(
$
columns
)
;
$
connection
=
$
this
->
model
->
getConnectionName
(
)
;
// Check for joined relations
if
(
!
empty
(
$
this
->
joined
)
)
{
foreach
(
$
results
as
$
key
=>
$
result
)
{
$
relation_values
=
[
]
;
foreach
(
$
result
as
$
column
=>
$
value
)
{
Arr
::
set
(
$
relation_values
,
$
column
,
$
value
)
;
}
foreach
(
$
this
->
joined
as
$
relationName
)
{
$
relation
=
$
this
->
getRelation
(
$
relationName
)
;
$
relation_values
[
$
relationName
]
=
$
relation
->
getRelated
(
)
->
newFromBuilder
(
Arr
::
pull
(
$
relation_values
,
$
relationName
)
,
$
connection
)
;
}
$
results
[
$
key
]
=
$
relation_values
;
}
}
return
$
this
->
model
->
hydrate
(
$
results
,
$
connection
)
->
all
(
)
;
}

Get the hydrated models without eager loading.

@param array $columns

@return \Illuminate\Database\Eloquent\Model[]

Get the hydrated models without eager loading .


public static function get_ajax_payload( $handle = '' ) {
		$payload = null;

		if ( ! empty( $_POST['payload'] ) ) {
			$payload = $_POST['payload']; // Could be either a string or an array.
		}

		/**
		 * Filter the Ajax payload.
		 *
		 * @param mixed  $payload The ajax payload.
		 * @param string $handle  The current handler's handle.
		 */
		$payload = apply_filters( 'WP_Ajax_Helper\ajax_payload', $payload, $handle );

		return $payload;
	}

Gets the AJAX payload from the POST request.

@param string $handle The current handler's handle.

@return mixed The Ajax payload.

Gets the AJAX payload from the POST request .


public static function get_callback_response( $handle, $callback, $callback_args ) {

		$ajax_payload = static::get_ajax_payload( $handle );

		$response = static::run_callback(
			$callback,
			array(
				$ajax_payload,
				$callback_args,
			)
		);

		/**
		 * Filter the callback response.
		 *
		 * @param mixed  $response      The callback response.
		 * @param string $handle        The current handle's name.
		 * @param array  $callback_args The arguments passed to the callback function.
		 * @param mixed  $ajax_payload  The Ajax payload.
		 */
		$response = apply_filters( 'WP_Ajax_Helper\callback_response', $response, $handle, $callback_args, $ajax_payload );

		return $response;
	}

Retrieves the response from the handle's callback function.

@param string $handle        The current handler's handle.
@param mixed  $callback      The callback function.
@param array  $callback_args The arguments to be passed to the callback function.

@return mixed The callback response.

Retrieves the response from the handle s callback function .


public static function run_callback( $callback = '', $callback_args = array() ) {

		if ( ! is_callable( $callback ) ) {
			return null;
		}

		try {
			$result = call_user_func_array( $callback, $callback_args );

		} catch ( \Exception $caught_exception ) {
			$result = $caught_exception;
		}

		return $result;
	}

public static function run_callback ( $ callback = '' , $ callback_args = array ( ) ) { if ( ! is_callable ( $ callback ) ) { return null ; } try { $ result = call_user_func_array ( $ callback , $ callback_args ) ; } catch ( \ Exception $ caught_exception ) { $ result = $ caught_exception ; } return $ result ; }

Executes the specified callback function, passing in with the supplied arguments.

@param mixed $callback      The callback function to run.
@param array $callback_args The arguments to be passed to the callback function.

@return mixed The callback result, or null if the callback was not callable, or \Exception if the callback threw an exception.

Executes the specified callback function passing in with the supplied arguments .


public static function sanitize_handle( $handle = null ) {

		$handle = sanitize_key( $handle );
		$handle = str_replace( '-', '_', $handle );

		return $handle;
	}

public static function sanitize_handle ( $ handle = null ) { $ handle = sanitize_key ( $ handle ) ; $ handle = str_replace ( '-' , '_' , $ handle ) ; return $ handle ; }

Sanitizes and validates a handle name.

@param string $handle The provided handle name.

@return string The sanitized handle name.


public function validate_all() {

		foreach ( (array) $this->registered_validations as $condition => $value ) {

			if ( ! $this->validate_single( $condition, $value ) ) {
				return false;
			}
		}

		return true;
	}

public function validate_all ( ) { foreach ( ( array ) $ this -> registered_validations as $ condition => $ value ) { if ( ! $ this -> validate_single ( $ condition , $ value ) ) { return false ; } } return true ; }

Determines whether all validations have passed.

@return bool

Determines whether all validations have passed .


private function validate_single( $condition, $value ) {

		$validator = array( $this->validations_class, $condition );

		if ( is_callable( $validator ) ) {
			$result = call_user_func( $validator, $value );
		} else {
			$result = false;
		}

		return (bool) $result;
	}

private function validate_single ( $ condition , $ value ) { $ validator = array ( $ this -> validations_class , $ condition ) ; if ( is_callable ( $ validator ) ) { $ result = call_user_func ( $ validator , $ value ) ; } else { $ result = false ; } return ( bool ) $ result ; }

Runs a single validation.

@param string $condition The name of the condition.
@param mixed  $value     The value to validate.

@return bool Whether the validation passes.


public function forDevice($device, $width, $offset = null, $push = null, $resets = false)
    {
        $this->sizes[$device] = array('width' => $width, 'offset' => $offset, 'push' => $push);

        if ($resets) {
            $this->addReset($device);
        }

        return $this;
    }

public function forDevice ( $ device , $ width , $ offset = null , $ push = null , $ resets = false ) { $ this -> sizes [ $ device ] = array ( 'width' => $ width , 'offset' => $ offset , 'push' => $ push ) ; if ( $ resets ) { $ this -> addReset ( $ device ) ; } return $ this ; }

Create a column for a device.

@param string   $device The device name.
@param int      $width  The column width.
@param int|null $offset Optional offset.
@param int|null $push   Optional push.
@param bool     $resets Reset columns.

@return $this


public function addReset($device)
    {
        if (!in_array($device, $this->resets)) {
            $this->resets[] = $device;
        }

        return $this;
    }

public function addReset ( $ device ) { if ( ! in_array ( $ device , $ this -> resets ) ) { $ this -> resets [ ] = $ device ; } return $ this ; }

Add a reset for a device.

@param string $device The device.

@return $this


public function getSize($device)
    {
        if (isset($this->sizes[$device])) {
            return $this->sizes[$device];
        }

        return null;
    }

public function getSize ( $ device ) { if ( isset ( $ this -> sizes [ $ device ] ) ) { return $ this -> sizes [ $ device ] ; } return null ; }

Get a size for a device.

@param string $device The device.

@return null|array


public function build()
    {
        $classes = array();

        foreach ($this->sizes as $device => $size) {
            if ($size['width']) {
                $classes[] = sprintf('col-%s-%s', $device, $size['width']);
            } else {
                $classes[] = 'hidden-' . $device;
            }

            if ($size['offset'] !== null) {
                $classes[] = sprintf('col-%s-offset-%s', $device, $size['offset']);
            }

            if ($size['push'] !== null) {
                if (is_numeric($size['push'])) {
                    $push      = ($size['push'] < 0) ? 'pull' : 'push';
                    $classes[] = sprintf('col-%s-%s-%s', $device, $push, $size['push']);
                } else {
                    $classes[] = sprintf('col-%s-%s', $device, $size['push']);
                }
            }
        }

        if ($this->class) {
            $classes[] = $this->class;
        }

        return $classes;
    }

public function build ( ) { $ classes = array ( ) ; foreach ( $ this -> sizes as $ device => $ size ) { if ( $ size [ 'width' ] ) { $ classes [ ] = sprintf ( 'col-%s-%s' , $ device , $ size [ 'width' ] ) ; } else { $ classes [ ] = 'hidden-' . $ device ; } if ( $ size [ 'offset' ] !== null ) { $ classes [ ] = sprintf ( 'col-%s-offset-%s' , $ device , $ size [ 'offset' ] ) ; } if ( $ size [ 'push' ] !== null ) { if ( is_numeric ( $ size [ 'push' ] ) ) { $ push = ( $ size [ 'push' ] < 0 ) ? 'pull' : 'push' ; $ classes [ ] = sprintf ( 'col-%s-%s-%s' , $ device , $ push , $ size [ 'push' ] ) ; } else { $ classes [ ] = sprintf ( 'col-%s-%s' , $ device , $ size [ 'push' ] ) ; } } } if ( $ this -> class ) { $ classes [ ] = $ this -> class ; } return $ classes ; }

Build css classes.

@return array classes


public function user_is( $role ) {

		if ( ! is_user_logged_in() ) {
			return false;
		}

		$user = wp_get_current_user();
		return in_array( $role, $user->roles );
	}

public function user_is ( $ role ) { if ( ! is_user_logged_in ( ) ) { return false ; } $ user = wp_get_current_user ( ) ; return in_array ( $ role , $ user -> roles ) ; }

Tests whether the current user has the specified role.

@param string $role The role to test.

@return bool

Tests whether the current user has the specified role .


public function begin()
    {
        $this->index = 0;
        $this->infiniteIndex++;

        if ($this->classesOnly) {
            return $this->grid->getColumnAsString($this->index);
        }

        return sprintf(
            '%s%s%s<div class="%s">%s',
            $this->beginRow(),
            PHP_EOL,
            $this->grid->getColumnResetsAsString($this->index),
            $this->grid->getColumnAsString($this->index),
            PHP_EOL
        );
    }

public
function
begin
(
)
{
$
this
->
index
=
0
;
$
this
->
infiniteIndex
++
;
if
(
$
this
->
classesOnly
)
{
return
$
this
->
grid
->
getColumnAsString
(
$
this
->
index
)
;
}
return
sprintf
(
'%s%s%s<div class="%s">%s'
,
$
this
->
beginRow
(
)
,
PHP_EOL
,
$
this
->
grid
->
getColumnResetsAsString
(
$
this
->
index
)
,
$
this
->
grid
->
getColumnAsString
(
$
this
->
index
)
,
PHP_EOL
)
;
}

Start a new row.

If classesOnly is set, only the first column is returned.

@return string


public function column()
    {
        $this->index++;
        $this->infiniteIndex++;

        if (!$this->grid->hasColumn($this->index)) {
            $this->index = 0;
        }

        if ($this->classesOnly) {
            return $this->grid->getColumnAsString($this->index);
        }

        $buffer = sprintf(
            '%s
%s%s
%s',
            PHP_EOL,
            PHP_EOL,
            $this->grid->getColumnResetsAsString($this->index),
            $this->grid->getColumnAsString($this->index),
            PHP_EOL
        );

        return $buffer;
    }

public
function
column
(
)
{
$
this
->
index
++
;
$
this
->
infiniteIndex
++
;
if
(
!
$
this
->
grid
->
hasColumn
(
$
this
->
index
)
)
{
$
this
->
index
=
0
;
}
if
(
$
this
->
classesOnly
)
{
return
$
this
->
grid
->
getColumnAsString
(
$
this
->
index
)
;
}
$
buffer
=
sprintf
(
'%s
%s%s
%s'
,
PHP_EOL
,
PHP_EOL
,
$
this
->
grid
->
getColumnResetsAsString
(
$
this
->
index
)
,
$
this
->
grid
->
getColumnAsString
(
$
this
->
index
)
,
PHP_EOL
)
;
return
$
buffer
;
}


public function walk()
    {
        if ($this->index < 0) {
            return $this->begin();
        }

        if (!$this->grid->hasColumn($this->index + 1)) {
            return $this->end() . $this->begin();
        }

        return $this->column();
    }

public function walk ( ) { if ( $ this -> index < 0 ) { return $ this -> begin ( ) ; } if ( ! $ this -> grid -> hasColumn ( $ this -> index + 1 ) ) { return $ this -> end ( ) . $ this -> begin ( ) ; } return $ this -> column ( ) ; }

Automatically walk throw the grid.

@return string


public function beginRow()
    {
        if ($this->classesOnly) {
            return trim('row ' . $this->grid->getRowClass());
        }

        return sprintf('<div class="%s">', trim('row ' . $this->grid->getRowClass()));
    }

public
function
beginRow
(
)
{
if
(
$
this
->
classesOnly
)
{
return
trim
(
'row '
.
$
this
->
grid
->
getRowClass
(
)
)
;
}
return
sprintf
(
'<div class="%s">'
,
trim
(
'row '
.
$
this
->
grid
->
getRowClass
(
)
)
)
;
}


public function getColumnResets($tag = null)
    {
        if (!$this->infinite || $this->infiniteIndex === 0 || $this->grid->hasColumn($this->infiniteIndex)) {
            return $this->grid->getColumnResetsAsString($this->index, $tag);
        }

        $number = count($this->grid->getColumns());

        return $this->grid->getColumnResetsAsString(($this->infiniteIndex % $number), $tag);
    }

public function getColumnResets ( $ tag = null ) { if ( ! $ this -> infinite || $ this -> infiniteIndex === 0 || $ this -> grid -> hasColumn ( $ this -> infiniteIndex ) ) { return $ this -> grid -> getColumnResetsAsString ( $ this -> index , $ tag ) ; } $ number = count ( $ this -> grid -> getColumns ( ) ) ; return $ this -> grid -> getColumnResetsAsString ( ( $ this -> infiniteIndex % $ number ) , $ tag ) ; }

Get the column resets for the current position, always as html.

@param string|null $tag Custom html tag.

@return string

Get the column resets for the current position always as html .


public function getIndex($ignoreInfinite = false)
    {
        if ($this->infinite && !$ignoreInfinite) {
            return $this->infiniteIndex;
        }

        return $this->index;
    }

public function getIndex ( $ ignoreInfinite = false ) { if ( $ this -> infinite && ! $ ignoreInfinite ) { return $ this -> infiniteIndex ; } return $ this -> index ; }

Get index.

@param bool $ignoreInfinite If true the infinite index is ignored and the regular column index is returned.

@return int


private function migrateFromLegacy()
    {
        if (!$this->database->fieldExists('bootstrap_grid', 'tl_content')
            && $this->database->fieldExists('columnset_id', 'tl_content')
        ) {
            $this->database->query(
                'ALTER TABLE tl_content ADD bootstrap_grid int(10) unsigned NOT NULL default \'0\';'
            );
            $this->database->query('UPDATE tl_content SET bootstrap_grid=columnset_id WHERE bootstrap_grid = 0');
        }
    }

Migrate form legacy column set editor.

@return void


public function handle( $handle ) {

		// Sanitize the handle name.
		$this->handle = $this->utility->sanitize_handle( $handle );

		// Register this handle with the frontend class.
		$this->frontend->register_handle( $this->handle );

		// Register the Ajax handler in the WordPress hook system.
		add_action( 'wp_ajax_'        . $this->handle, array( $this, 'ajax_handler' ) );
		add_action( 'wp_ajax_nopriv_' . $this->handle, array( $this, 'ajax_handler' ) );

		return $this;
	}

The main handler for the specfied handle.

@param string $handle The instance handle.

@return Handler

The main handler for the specfied handle .


public function ajax_handler() {

		if ( $this->utility->validate_nonce( $this->handle ) && $this->validator->validate_all() ) {

			$callback_response = $this->utility->get_callback_response( $this->handle, $this->handle_callback, $this->handle_callback_args );
			$this->responder->handle_response( $callback_response );

		} else {

			http_response_code( 403 ); // Forbidden.
		}

		die();
	}

public
function
ajax_handler
(
)
{
if
(
$
this
->
utility
->
validate_nonce
(
$
this
->
handle
)
&&
$
this
->
validator
->
validate_all
(
)
)
{
$
callback_response
=
$
this
->
utility
->
get_callback_response
(
$
this
->
handle
,
$
this
->
handle_callback
,
$
this
->
handle_callback_args
)
;
$
this
->
responder
->
handle_response
(
$
callback_response
)
;
}
else
{
http_response_code
(
403
)
;
// Forbidden.
}
die
(
)
;
}


public function with_callback( $callback = '', $callback_args = array() ) {

		$this->handle_callback      = $callback;
		$this->handle_callback_args = $callback_args;

		return $this;
	}

public function with_callback ( $ callback = '' , $ callback_args = array ( ) ) { $ this -> handle_callback = $ callback ; $ this -> handle_callback_args = $ callback_args ; return $ this ; }

Registers the callback function to handle the request.

@param mixed $callback      The callback function (function name, class method, or closure).
@param array $callback_args Arguments to be passed to the callback.

@return Handler

Registers the callback function to handle the request .


public function with_validation( $validations = array() ) {

		foreach ( (array) $validations as $condition => $value ) {
			$this->validator->add_validation( $condition, $value );
		}

		return $this;
	}

public function with_validation ( $ validations = array ( ) ) { foreach ( ( array ) $ validations as $ condition => $ value ) { $ this -> validator -> add_validation ( $ condition , $ value ) ; } return $ this ; }

Registers the validation settings.

@param array $validations The validation settings.

@return Handler


public function handle_response( $callback_response ) {

		$this->callback_response = $callback_response;
		$this->response_type = $this->get_response_type();

		$this->send_response_headers();
		$this->send_response_body();
	}

public function handle_response ( $ callback_response ) { $ this -> callback_response = $ callback_response ; $ this -> response_type = $ this -> get_response_type ( ) ; $ this -> send_response_headers ( ) ; $ this -> send_response_body ( ) ; }

Handles a response.

@param mixed $callback_response The response from the callback function.


protected function get_response_type() {

		if ( is_array( $this->callback_response ) ) {
			$response_type = 'json';

		} elseif ( is_string( $this->callback_response ) ) {
			$response_type = 'plain';

		} else {
			// For everything else, i.e. null, WP_Error object, caught exception, etc.
			$response_type = 'error';
		}

		return $response_type;
	}

Determines the type of response to return.

@return string The response type.

Determines the type of response to return .


protected function send_response_headers() {

		$http_content_type = 'text/plain';

		// Set an HTTP error code if the response type is an error.
		if ( 'error' === $this->response_type ) {
			http_response_code( 500 ); // Internal server error.
		}

		// Set the content type to JSON if the callback response is an array.
		if ( 'json' === $this->response_type ) {
			$http_content_type = 'application/json';
		}

		header( sprintf( 'Content-Type: %s; charset=%s',
			$http_content_type,
			get_option( 'blog_charset' )
		) );
	}

Sends the appropriate HTTP headers for the response type.

Sends the appropriate HTTP headers for the response type .


protected function send_response_body() {

		if ( 'json' === $this->response_type ) {

			$response_json = wp_json_encode( $this->callback_response );

			if ( false !== $response_json ) {
				echo $response_json;
			}

		} elseif ( 'plain' === $this->response_type ) {
			echo $this->callback_response;
		}
	}

protected function send_response_body ( ) { if ( 'json' === $ this -> response_type ) { $ response_json = wp_json_encode ( $ this -> callback_response ) ; if ( false !== $ response_json ) { echo $ response_json ; } } elseif ( 'plain' === $ this -> response_type ) { echo $ this -> callback_response ; } }

Sends the response body in the appropriate format.

Sends the response body in the appropriate format .


public function getContent(string $url): string
    {
        if (false === filter_var($url, FILTER_VALIDATE_URL)) {
            throw new InvalidArgument(
                sprintf('"%s" must be called with a valid url. Got "%s" instead.', __METHOD__, $url)
            );
        }

        $ipAddress = parse_url($url, PHP_URL_QUERY);

        if (false === filter_var($ipAddress, FILTER_VALIDATE_IP)) {
            throw new InvalidArgument('URL must contain a valid query-string (an IP address, 127.0.0.1 for instance)');
        }

        $result = $this->geoIp2Provider
            ->{$this->geoIP2Model}($ipAddress)
            ->jsonSerialize();

        return json_encode($result);
    }

Returns the content fetched from a given resource.

@param string $url (e.g. file://database?127.0.0.1)

@return string

Returns the content fetched from a given resource .


protected function isSupportedGeoIP2Model(string $method): bool
    {
        $availableMethods = [
            self::GEOIP2_MODEL_CITY,
            self::GEOIP2_MODEL_COUNTRY,
        ];

        return in_array($method, $availableMethods);
    }

protected function isSupportedGeoIP2Model ( string $ method ) : bool { $ availableMethods = [ self :: GEOIP2_MODEL_CITY , self :: GEOIP2_MODEL_COUNTRY , ] ; return in_array ( $ method , $ availableMethods ) ; }

Returns whether method is supported by GeoIP2.

@param string $method

@return bool

Returns whether method is supported by GeoIP2 .


private function toggleVisibility($recordId, $newState)
    {
        if (!$this->hasAccess()) {
            $this->log(
                sprintf('Not enough permission to show/shide record ID "%s"', $recordId),
                __METHOD__,
                TL_ERROR
            );

            $this->redirect('contao/main.php?act=error');
        }

        $versions = new \Versions($this->table, $recordId);

        if (isset($GLOBALS['TL_DCA'][$this->table]['fields'][$this->column]['save_callback'])) {
            foreach ((array) $GLOBALS['TL_DCA'][$this->table]['fields'][$this->column]['save_callback'] as $callback) {
                $instance = new $callback[0];
                $instance->{$callback[1]}($newState, $this);
            }
        }

        $this->database
            ->prepare(sprintf('UPDATE %s %s WHERE id=?', $this->table, '%s'))
            ->set(array('tstamp' => time(), $this->column => $newState ? '1' : ''))
            ->execute($recordId);

        $versions->create();
    }

Toggle the visibility state.

@param int  $recordId Record id.
@param bool $newState New state.

@return void

@SuppressWarnings(PHPMD.Superglobals)


private function hasAccess()
    {
        if ($this->user instanceof \BackendUser) {
            return $this->user->hasAccess($this->table . '::' . $this->column, 'alexf');
        }

        return false;
    }

private function hasAccess ( ) { if ( $ this -> user instanceof \ BackendUser ) { return $ this -> user -> hasAccess ( $ this -> table . '::' . $ this -> column , 'alexf' ) ; } return false ; }


public function build()
    {
        $grid = new Grid();

        foreach ($this->columns as $index => $column) {
            $grid->addColumn($column->build());
            $grid->addColumnResets($index, $column->getResets());
        }

        return $grid;
    }

public function build ( ) { $ grid = new Grid ( ) ; foreach ( $ this -> columns as $ index => $ column ) { $ grid -> addColumn ( $ column -> build ( ) ) ; $ grid -> addColumnResets ( $ index , $ column -> getResets ( ) ) ; } return $ grid ; }


public function getColumnAsString($index)
    {
        if (isset($this->columns[$index])) {
            return implode(' ', $this->columns[$index]);
        }

        return '';
    }

public
function
getColumnAsString
(
$
index
)
{
if
(
isset
(
$
this
->
columns
[
$
index
]
)
)
{
return
implode
(
' '
,
$
this
->
columns
[
$
index
]
)
;
}
return
''
;
}

Get column as class string.

@param int $index Column index.

@return string


public function addColumnReset($column, $size)
    {
        if (!isset($this->columnResets[$column])) {
            $this->columnResets[$column] = array();
        }

        if (!in_array($size, $this->columnResets[$column])) {
            $this->columnResets[$column][] = $size;
        }

        return $this;
    }

public function addColumnReset ( $ column , $ size ) { if ( ! isset ( $ this -> columnResets [ $ column ] ) ) { $ this -> columnResets [ $ column ] = array ( ) ; } if ( ! in_array ( $ size , $ this -> columnResets [ $ column ] ) ) { $ this -> columnResets [ $ column ] [ ] = $ size ; } return $ this ; }

Add column clear fix for a specific column and size.

@param int    $column The column index.
@param string $size   The grid size.

@return $this

Add column clear fix for a specific column and size .


public function addColumnResets($column, array $sizes)
    {
        if (!isset($this->columnResets[$column])) {
            $this->columnResets[$column] = $sizes;
        } else {
            $this->columnResets[$column] = array_unique(array_merge($this->columnResets[$column], $sizes));
        }

        return $this;
    }

public function addColumnResets ( $ column , array $ sizes ) { if ( ! isset ( $ this -> columnResets [ $ column ] ) ) { $ this -> columnResets [ $ column ] = $ sizes ; } else { $ this -> columnResets [ $ column ] = array_unique ( array_merge ( $ this -> columnResets [ $ column ] , $ sizes ) ) ; } return $ this ; }

Add clear fix for a column.

@param int   $column The column index.
@param array $sizes  The grid sizes.

@return $this


public function getColumnResets($index)
    {
        $index = intval($index);

        if (isset($this->columnResets[$index])) {
            return $this->columnResets[$index];
        }

        return array();
    }

public function getColumnResets ( $ index ) { $ index = intval ( $ index ) ; if ( isset ( $ this -> columnResets [ $ index ] ) ) { return $ this -> columnResets [ $ index ] ; } return array ( ) ; }

Get resets for a column.

@param int $index The column index.

@return array


public function hasColumnResetForSize($column, $size)
    {
        if (!isset($this->columnResets[$column])) {
            return false;
        }

        return in_array($size, $this->columnResets[$column]);
    }

public function hasColumnResetForSize ( $ column , $ size ) { if ( ! isset ( $ this -> columnResets [ $ column ] ) ) { return false ; } return in_array ( $ size , $ this -> columnResets [ $ column ] ) ; }

Check if column as a clear fix for a specific size.

@param int    $column The column index.
@param string $size   The grid column size.

@return bool

Check if column as a clear fix for a specific size .


public function getColumnResetsAsString($index, $tag = null)
    {
        $tag = $tag ?: 'div';

        return implode(
            PHP_EOL,
            array_map(
                function ($item) use ($tag) {
                    return sprintf(
                        '<%s class="clearfix visible-%s-block"></%s>' . PHP_EOL,
                        $tag,
                        $item,
                        $tag
                    );
                },
                $this->getColumnResets($index)
            )
        );
    }

Get column resets as string.

@param int         $index Column index.
@param string|null $tag   Custom html tag. Default divs are created.

@return string


public function register_handle( $handle = '' ) {

		$this->registered_handles[] = $handle;

		// Only call add_actions() the first time a handle is registered, as the actions will still be registered for
		// subsequent handles.
		if ( 1 === count( $this->registered_handles ) ) {
			$this->add_actions();
		}
	}

Registers an instance handle.

@param string $handle The handle name.


public function enqueue_scripts() {

		if ( empty( $this->registered_handles ) ) {
			return;
		}

		$script_url = plugin_dir_url( trailingslashit( __DIR__ ) . '../../../' ) . 'assets/js/wp-ajax-helper.js';

		wp_enqueue_script( 'wp-ajax-helper', $script_url, array( 'jquery' ), null, true );

		wp_localize_script(
			'wp-ajax-helper',
			'wpAjaxHelper',
			array(
				'ajaxUrl' => admin_url( 'admin-ajax.php' ),
				'handles' => $this->get_nonces(),
			)
		);
	}

public function enqueue_scripts ( ) { if ( empty ( $ this -> registered_handles ) ) { return ; } $ script_url = plugin_dir_url ( trailingslashit ( __DIR__ ) . '../../../' ) . 'assets/js/wp-ajax-helper.js' ; wp_enqueue_script ( 'wp-ajax-helper' , $ script_url , array ( 'jquery' ) , null , true ) ; wp_localize_script ( 'wp-ajax-helper' , 'wpAjaxHelper' , array ( 'ajaxUrl' => admin_url ( 'admin-ajax.php' ) , 'handles' => $ this -> get_nonces ( ) , ) ) ; }


protected function get_nonces() {
		$nonces = array();

		foreach ( (array) $this->registered_handles as $handle ) {
			$nonces[ $handle ] = wp_create_nonce( $handle );
		}

		return $nonces;
	}

protected function get_nonces ( ) { $ nonces = array ( ) ; foreach ( ( array ) $ this -> registered_handles as $ handle ) { $ nonces [ $ handle ] = wp_create_nonce ( $ handle ) ; } return $ nonces ; }

Generates nonces for each of the registered handles.

@return array The handles with their associated nonces.

Generates nonces for each of the registered handles .


public static function getGrids(GetGridsEvent $event)
    {
        $model = $event->getModel();
        $grids = $event->getGrids();

        if ($model->type == 'semantic_html5') {
            $query  = 'SELECT * FROM tl_columnset WHERE published=1 ORDER BY title';
            $result = \Database::getInstance()->query($query);

            while ($result->next()) {
                $key = sprintf($GLOBALS['TL_LANG']['tl_content']['bootstrap_columns'], $result->columns);

                $grids[$key][$result->id] = $result->title;
            }
        }
    }

Get grids from the database.

@param GetGridsEvent $event The subscribed event.

@return void

@SuppressWarnings(PHPMD.Superglobals)


public function hookParseTemplate(\Template $template)
    {
        if (substr($template->getName(), 0, 3) != 'ce_'
            || $template->type != 'semantic_html5'
            || $template->sh5_tag != 'start'
        ) {
            return;
        }

        $this->createRow($template);
        $this->createColumn($template);
    }

public function hookParseTemplate ( \ Template $ template ) { if ( substr ( $ template -> getName ( ) , 0 , 3 ) != 'ce_' || $ template -> type != 'semantic_html5' || $ template -> sh5_tag != 'start' ) { return ; } $ this -> createRow ( $ template ) ; $ this -> createColumn ( $ template ) ; }

Use the parse template hook to inject column and row classes.

@param \Template $template The template.

@return void

Use the parse template hook to inject column and row classes .


public function hookGetContentElement($model, $buffer)
    {
        if ($model->type === 'semantic_html5'
            && $model->sh5_tag === 'start'
            && $model->bootstrap_isGridElement === 'column'
            && static::$grids[$model->bootstrap_gridRow]
        ) {
            $row  = $model->bootstrap_gridRow;
            $grid = static::$grids[$row];

            // Index is already incremented, so go back
            $index = (static::$count[$row] - 1);

            $buffer = $grid->getColumnResetsAsString($index) . $buffer;
        }

        return $buffer;
    }

Add clear fixes for a column.

@param \ContentModel $model  The content model.
@param string        $buffer The content element output.

@return string


public function getGridElements($dataContainer)
    {
        $elements = array();

        if ($dataContainer->activeRecord) {
            $query = <<<SQL
SELECT
    c.*, g.title as gridTitle, g.columns as gridColumns
FROM
    tl_content c
LEFT JOIN
    tl_columnset g
ON
    g.id = c.bootstrap_grid
WHERE
    (c.ptable=? OR c.ptable=?)
    AND c.pid=?
    AND c.type=?
    AND c.sh5_tag=?
    AND c.bootstrap_isGridElement=?
    AND c.sorting < ?
ORDER BY
    sorting
SQL;

            $ptable = $GLOBALS['TL_DCA'][$dataContainer->table]['config']['ptable'];
            $result = \Database::getInstance()
                ->prepare($query)
                ->execute(
                    $ptable,
                    $ptable == 'tl_article' ? '' : $ptable,
                    $dataContainer->activeRecord->pid,
                    'semantic_html5',
                    'start',
                    'row',
                    $dataContainer->activeRecord->sorting
                );

            while ($result->next()) {
                $headline              = deserialize($result->headline, true);
                $elements[$result->id] = ($headline['value'] ?: ('ID ' . $result->id)) . ' [' .
                    $result->gridColumns . ' - ' . $result->gridTitle . ']';
            }
        }

        return $elements;
    }

Get all grid elements.

@param \DataContainer $dataContainer The data container driver.

@return array

@SuppressWarnings(PHPMD.Superglobals)


private function createRow($template)
    {
        // semantic html5 element is marked as beginning of new grid row
        if ($template->bootstrap_isGridElement == 'row') {
            try {
                static::$grids[$template->id] = Factory::createById($template->bootstrap_grid);
                static::$count[$template->id] = 0;
            } catch (\InvalidArgumentException $e) {
                echo $e->getMessage();

                return;
            }

            $class = ($template->class ? ' ' : '') . 'row';

            if (static::$grids[$template->id]->getRowClass()) {
                $class .= ' ' . static::$grids[$template->id]->getRowClass();
            }

            $template->class .= $class;
        }
    }

Create the row class.

@param \Template $template The template.

@return void


private function createColumn($template)
    {
        // semantic html5 element is marked as an grid column
        if ($template->bootstrap_isGridElement == 'column') {
            if (static::$grids[$template->bootstrap_gridRow]) {
                $row   = $template->bootstrap_gridRow;
                $grid  = static::$grids[$row];
                $index = static::$count[$row];

                $template->class .= ($template->class ? ' ' : '') . $grid->getColumnAsString($index);
                static::$count[$row]++;
            }
        }
    }

Create the column classes.

@param \Template $template The template.

@return void


private static function buildGridColumns($builder, $result, $classes)
    {
        $columns = $result->columns;
        $sizes   = deserialize($result->sizes, true);

        for ($i = 0; $i < $columns; $i++) {
            $column = $builder->addColumn();

            foreach ($sizes as $size) {
                $key    = 'columnset_' . $size;
                $values = deserialize($result->$key, true);

                $column->forDevice(
                    $size,
                    $values[$i]['width'],
                    ($values[$i]['offset']) ? ($values[$i]['offset'] == 'null' ? 0 : $values[$i]['offset']): null,
                    $values[$i]['order'] ?: null
                );

                $index = ($i + 1);

                if (!empty($classes[$index])) {
                    $column->setClass($classes[$index]);
                }
            }
        }

        return $builder->build();
    }

private static function buildGridColumns ( $ builder , $ result , $ classes ) { $ columns = $ result -> columns ; $ sizes = deserialize ( $ result -> sizes , true ) ; for ( $ i = 0 ; $ i < $ columns ; $ i ++ ) { $ column = $ builder -> addColumn ( ) ; foreach ( $ sizes as $ size ) { $ key = 'columnset_' . $ size ; $ values = deserialize ( $ result -> $ key , true ) ; $ column -> forDevice ( $ size , $ values [ $ i ] [ 'width' ] , ( $ values [ $ i ] [ 'offset' ] ) ? ( $ values [ $ i ] [ 'offset' ] == 'null' ? 0 : $ values [ $ i ] [ 'offset' ] ) : null , $ values [ $ i ] [ 'order' ] ? : null ) ; $ index = ( $ i + 1 ) ; if ( ! empty ( $ classes [ $ index ] ) ) { $ column -> setClass ( $ classes [ $ index ] ) ; } } } return $ builder -> build ( ) ; }

Build columns.

@param GridBuilder      $builder The grid builder.
@param \Database\Result $result  The database result.
@param array            $classes Custom css classes.

@return Grid


private static function fetchResult($gridId, $ignoreError = false)
    {
        $result = \Database::getInstance()
            ->prepare('SELECT * FROM tl_columnset WHERE id=? AND published=1')
            ->limit(1)
            ->execute($gridId);

        if (!$ignoreError && $result->numRows < 1) {
            throw new \InvalidArgumentException(sprintf('Could not find columnset with ID "%s"', $gridId));
        }

        return $result;
    }

Fetch the database result.

@param int  $gridId      The grid id.
@param bool $ignoreError If true no exception is thrown. An empty grid is used instead.

@return \Database\Result
@throws \InvalidArgumentException If grid is not found.


private static function prepareClasses($result)
    {
        $classes = array();

        foreach (deserialize($result->customClasses, true) as $class) {
            $classes[$class['column']] = $class['class'];
        }

        return $classes;
    }

private static function prepareClasses ( $ result ) { $ classes = array ( ) ; foreach ( deserialize ( $ result -> customClasses , true ) as $ class ) { $ classes [ $ class [ 'column' ] ] = $ class [ 'class' ] ; } return $ classes ; }

Prepare the css classes.

@param \Database\Result $result The database result.

@return array


private static function buildColumnResets($result, $grid)
    {
        foreach (deserialize($result->resets, true) as $row) {
            foreach (array('xs', 'sm', 'md', 'lg') as $size) {
                if (isset($row[$size]) && $row[$size]) {
                    $grid->addColumnReset(($row['column'] - 1), $size);
                }
            }
        }
    }

private static function buildColumnResets ( $ result , $ grid ) { foreach ( deserialize ( $ result -> resets , true ) as $ row ) { foreach ( array ( 'xs' , 'sm' , 'md' , 'lg' ) as $ size ) { if ( isset ( $ row [ $ size ] ) && $ row [ $ size ] ) { $ grid -> addColumnReset ( ( $ row [ 'column' ] - 1 ) , $ size ) ; } } } }

Build the column resets.

@param \Database\Result $result The database result.
@param Grid             $grid   The grid being built.

@return void


public static function createById($gridId, $ignoreError = false)
    {
        if (isset(static::$cache[$gridId])) {
            return static::$cache[$gridId];
        }

        $result = self::fetchResult($gridId, $ignoreError);

        if ($result) {
            $builder = GridBuilder::create();
            $classes = self::prepareClasses($result);
            $grid    = self::buildGridColumns($builder, $result, $classes);
            $grid->setRowClass($result->rowClass);

            self::buildColumnResets($result, $grid);
        } else {
            $grid = new Grid();
        }

        static::$cache[$gridId] = $grid;

        return static::$cache[$gridId];
    }

public static function createById ( $ gridId , $ ignoreError = false ) { if ( isset ( static :: $ cache [ $ gridId ] ) ) { return static :: $ cache [ $ gridId ] ; } $ result = self :: fetchResult ( $ gridId , $ ignoreError ) ; if ( $ result ) { $ builder = GridBuilder :: create ( ) ; $ classes = self :: prepareClasses ( $ result ) ; $ grid = self :: buildGridColumns ( $ builder , $ result , $ classes ) ; $ grid -> setRowClass ( $ result -> rowClass ) ; self :: buildColumnResets ( $ result , $ grid ) ; } else { $ grid = new Grid ( ) ; } static :: $ cache [ $ gridId ] = $ grid ; return static :: $ cache [ $ gridId ] ; }

Create the grid by id.

@param int  $gridId      The grid id.
@param bool $ignoreError If true no exception is thrown. An empty grid is used instead.

@return Grid
@throws \InvalidArgumentException If grid is not found.


public function hookParseTemplate(\Template $template)
    {
        if (TL_MODE == 'BE'
            && $template->getName() == 'be_subcolumns'
            && Bootstrap::getConfigVar('grid-editor.backend.replace-subcolumns-template')
        ) {
            $template->setName('be_subcolumns_bootstrap');
        }
    }

ParseTemplate hook being used to beatify the backend view.

@param \Template $template The template.

@return void

ParseTemplate hook being used to beatify the backend view .


public function hookIsVisibleElement(\Model $model, $isVisible)
    {
        if (static::isActive() && (
            ($model->getTable() == 'tl_module' && $model->type == 'subcolumns') ||
            $model->getTable() == 'tl_content' && ($model->type == 'colsetStart' ||
            $model->type == 'colsetPart'
        ))) {
            if ($model->type == 'colsetPart') {
                $modelClass = get_class($model);
                $parent     = $modelClass::findByPk($model->sc_parent);
                $type       = $parent->sc_type;
                $gridId     = $parent->bootstrap_grid;
            } else {
                $type   = $model->sc_type;
                $gridId = $model->bootstrap_grid;
            }

            try {
                $this->updateSubcolumnsDefinition($gridId, $type);
            } catch (\Exception $e) {
                // Do not throw the exception in the frontend. If nothing could fetched the fallback is used.
            }
        }

        return $isVisible;
    }

The isVisibleElement hook is used to dynamically load the grid definitions from the database.

Known limitation: If being logged in in the backend and frontend preview is used with show all elements
it does not work!

@param \Model $model     The row model.
@param bool   $isVisible The current visible state.

@return bool

@SuppressWarnings(PHPMD.Superglobals)

The isVisibleElement hook is used to dynamically load the grid definitions from the database .


public function hookLoadFormField($widget)
    {
        if ($widget->type === 'formcolstart') {
            $type   = $widget->fsc_type;
            $gridId = $widget->bootstrap_grid;
            $grid   = Factory::createById($gridId);

            $GLOBALS['TL_SUBCL'][static::$name]['sets'][$type] = $this->prepareContainer($grid);

        } elseif ($widget->type === 'formcolpart' || $widget->type === 'formcolend') {
            $parent = \FormFieldModel::findByPk($widget->fsc_parent);

            $this->updateSubcolumnsDefinition($parent->bootstrap_grid, $parent->fsc_type);
        }

        return $widget;
    }

public function hookLoadFormField ( $ widget ) { if ( $ widget -> type === 'formcolstart' ) { $ type = $ widget -> fsc_type ; $ gridId = $ widget -> bootstrap_grid ; $ grid = Factory :: createById ( $ gridId ) ; $ GLOBALS [ 'TL_SUBCL' ] [ static :: $ name ] [ 'sets' ] [ $ type ] = $ this -> prepareContainer ( $ grid ) ; } elseif ( $ widget -> type === 'formcolpart' || $ widget -> type === 'formcolend' ) { $ parent = \ FormFieldModel :: findByPk ( $ widget -> fsc_parent ) ; $ this -> updateSubcolumnsDefinition ( $ parent -> bootstrap_grid , $ parent -> fsc_type ) ; } return $ widget ; }

Load columnset definition for the form field.

@param \Widget $widget The form widget.

@return \Widget

@SuppressWarnings(PHPMD.Superglobals)

Load columnset definition for the form field .


public static function getGrids(GetGridsEvent $event)
    {
        $model = $event->getModel();
        $grids = $event->getGrids();

        if ($model->type == 'colsetStart' || $model->type == 'subcolumns') {
            $query   = 'SELECT * FROM tl_columnset WHERE published=1 AND columns=? ORDER BY title';
            $columns = $model->sc_type;
            $result  = \Database::getInstance()
                ->prepare($query)
                ->execute($columns);

            while ($result->next()) {
                $grids[$result->id] = $result->title;
            }
        } elseif ($model->type == 'formcolstart') {
            $query   = 'SELECT * FROM tl_columnset WHERE published=1 AND columns=? ORDER BY title';
            $columns = $model->fsc_type;
            $result  = \Database::getInstance()
                ->prepare($query)
                ->execute($columns);

            while ($result->next()) {
                $grids[$result->id] = $result->title;
            }
        }
    }

Load all grids from the database.

@param GetGridsEvent $event The subscribed event.

@return void


protected function prepareContainer(Grid $grid)
    {
        $container = array();

        foreach ($grid->getColumns() as $column) {
            $container[] = array(implode(' ', $column));
        }

        return $container;
    }

protected
function
prepareContainer
(
Grid
$
grid
)
{
$
container
=
array
(
)
;
foreach
(
$
grid
->
getColumns
(
)
as
$
column
)
{
$
container
[
]
=
array
(
implode
(
' '
,
$
column
)
)
;
}
return
$
container
;
}

Prepare the container by loading the grid and parse it as subcolumns definition.

@param Grid $grid The grid object.

@return array

Prepare the container by loading the grid and parse it as subcolumns definition .


private function updateSubcolumnsDefinition($gridId, $type)
    {
        $grid = Factory::createById($gridId);

        $GLOBALS['TL_SUBCL'][static::$name]['sets'][$type] = $this->prepareContainer($grid);

        if ($grid->getRowClass()) {
            $GLOBALS['TL_SUBCL'][static::$name]['scclass'] = 'row ' . $grid->getRowClass();
        } else {
            $GLOBALS['TL_SUBCL'][static::$name]['scclass'] = 'row';
        }
    }

private
function
updateSubcolumnsDefinition
(
$
gridId
,
$
type
)
{
$
grid
=
Factory
::
createById
(
$
gridId
)
;
$
GLOBALS
[
'TL_SUBCL'
]
[
static
::
$
name
]
[
'sets'
]
[
$
type
]
=
$
this
->
prepareContainer
(
$
grid
)
;
if
(
$
grid
->
getRowClass
(
)
)
{
$
GLOBALS
[
'TL_SUBCL'
]
[
static
::
$
name
]
[
'scclass'
]
=
'row '
.
$
grid
->
getRowClass
(
)
;
}
else
{
$
GLOBALS
[
'TL_SUBCL'
]
[
static
::
$
name
]
[
'scclass'
]
=
'row'
;
}
}

Update the subcolumns definition.

@param int    $gridId The grid id.
@param string $type   The subcolumns type.

@return void
@SuppressWarnings(PHPMD.Superglobals)


public function appendColumnsetIdToPalette($dataContainer)
    {
        if ($GLOBALS['TL_CONFIG']['subcolumns'] != 'bootstrap_customizable') {
            return;
        }

        if ($dataContainer->table == 'tl_content') {
            $model = \ContentModel::findByPK($dataContainer->id);

            if ($model->sc_type > 0) {
                \MetaPalettes::appendFields($dataContainer->table, 'colsetStart', 'colset', array('columnset_id'));
            }
        } else {
            $model = \ModuleModel::findByPk($dataContainer->id);

            if ($model->sc_type > 0) {
                if ($model->sc_type > 0) {
                    $GLOBALS['TL_DCA']['tl_module']['palettes']['subcolumns'] = str_replace(
                        'sc_type,',
                        'sc_type,columnset_id,',
                        $GLOBALS['TL_DCA']['tl_module']['palettes']['subcolumns']
                    );
                }
            }
        }
    }

public function appendColumnsetIdToPalette ( $ dataContainer ) { if ( $ GLOBALS [ 'TL_CONFIG' ] [ 'subcolumns' ] != 'bootstrap_customizable' ) { return ; } if ( $ dataContainer -> table == 'tl_content' ) { $ model = \ ContentModel :: findByPK ( $ dataContainer -> id ) ; if ( $ model -> sc_type > 0 ) { \ MetaPalettes :: appendFields ( $ dataContainer -> table , 'colsetStart' , 'colset' , array ( 'columnset_id' ) ) ; } } else { $ model = \ ModuleModel :: findByPk ( $ dataContainer -> id ) ; if ( $ model -> sc_type > 0 ) { if ( $ model -> sc_type > 0 ) { $ GLOBALS [ 'TL_DCA' ] [ 'tl_module' ] [ 'palettes' ] [ 'subcolumns' ] = str_replace ( 'sc_type,' , 'sc_type,columnset_id,' , $ GLOBALS [ 'TL_DCA' ] [ 'tl_module' ] [ 'palettes' ] [ 'subcolumns' ] ) ; } } } }

Add column set field to the colsetStart content element.

We need to do it dynamically because subcolumns creates its palette dynamically.

@param \DataContainer $dataContainer The data container driver.

@return void

@SuppressWarnings(PHPMD.Superglobals)

Add column set field to the colsetStart content element .


public function appendColumnSizesToPalette($dataContainer)
    {
        $model = \Database::getInstance()
            ->prepare('SELECT * FROM tl_columnset WHERE id=?')
            ->limit(1)
            ->execute($dataContainer->id);

        $sizes = array_merge(deserialize($model->sizes, true));

        foreach ($sizes as $size) {
            $field = 'columnset_' . $size;

            \MetaPalettes::appendFields('tl_columnset', 'columnset', array($field));
        }
    }

public
function
appendColumnSizesToPalette
(
$
dataContainer
)
{
$
model
=
\
Database
::
getInstance
(
)
->
prepare
(
'SELECT * FROM tl_columnset WHERE id=?'
)
->
limit
(
1
)
->
execute
(
$
dataContainer
->
id
)
;
$
sizes
=
array_merge
(
deserialize
(
$
model
->
sizes
,
true
)
)
;
foreach
(
$
sizes
as
$
size
)
{
$
field
=
'columnset_'
.
$
size
;
\
MetaPalettes
::
appendFields
(
'tl_columnset'
,
'columnset'
,
array
(
$
field
)
)
;
}
}

Append column sizes fields dynamically to the palettes.

@param \DataContainer $dataContainer The data container driver.

@return void

Append column sizes fields dynamically to the palettes .


public function getAllTypes()
    {
        if ($GLOBALS['TL_CONFIG']['subcolumns'] != 'bootstrap_customizable') {
            return array_keys($GLOBALS['TL_SUBCL'][$GLOBALS['TL_CONFIG']['subcolumns']]['sets']);
        }

        $this->import('Database');
        $collection = $this->Database->execute('SELECT columns FROM tl_columnset GROUP BY columns ORDER BY columns');

        $types = array();

        while ($collection->next()) {
            $types[] = $collection->columns;
        }

        return $types;
    }

Replace subcolumns getAllTypes method to load all created columnsets.

There is a fallback provided if not bootstrap_customizable is used.

@return array

@SuppressWarnings(PHPMD.Superglobals)

Replace subcolumns getAllTypes method to load all created columnsets .


public function getGrids($dataContainer)
    {
        if ($dataContainer->activeRecord) {
            $dispatcher = $GLOBALS['container']['event-dispatcher'];
            $event      = new GetGridsEvent($dataContainer->activeRecord);
            $dispatcher->dispatch(GetGridsEvent::NAME, $event);

            return $event->getGrids()->getArrayCopy();
        }

        return array();
    }

public function getGrids ( $ dataContainer ) { if ( $ dataContainer -> activeRecord ) { $ dispatcher = $ GLOBALS [ 'container' ] [ 'event-dispatcher' ] ; $ event = new GetGridsEvent ( $ dataContainer -> activeRecord ) ; $ dispatcher -> dispatch ( GetGridsEvent :: NAME , $ event ) ; return $ event -> getGrids ( ) -> getArrayCopy ( ) ; } return array ( ) ; }

Get grids.

@param \DataContainer $dataContainer The data container driver.

@return array

@SuppressWarnings(PHPMD.Superglobals)


public function getColumnsForModule($dataContainer)
    {
        if ($GLOBALS['TL_CONFIG']['subcolumns'] != 'bootstrap_customizable') {
            $subcolumns = new \tl_module_sc();

            return $subcolumns->getColumns($dataContainer);
        }

        $model = \ModuleModel::findByPK($dataContainer->currentRecord);
        $cols  = array();

        $translate = array('first', 'second', 'third', 'fourth', 'fith');

        for ($i = 0; $i < $model->sc_type; $i++) {
            if (!array_key_exists($i, $translate)) {
                break;
            }

            $key        = $translate[$i];
            $cols[$key] = $GLOBALS['TL_LANG']['MSC']['sc_' . $key];
        }

        return $cols;
    }

public function getColumnsForModule ( $ dataContainer ) { if ( $ GLOBALS [ 'TL_CONFIG' ] [ 'subcolumns' ] != 'bootstrap_customizable' ) { $ subcolumns = new \ tl_module_sc ( ) ; return $ subcolumns -> getColumns ( $ dataContainer ) ; } $ model = \ ModuleModel :: findByPK ( $ dataContainer -> currentRecord ) ; $ cols = array ( ) ; $ translate = array ( 'first' , 'second' , 'third' , 'fourth' , 'fith' ) ; for ( $ i = 0 ; $ i < $ model -> sc_type ; $ i ++ ) { if ( ! array_key_exists ( $ i , $ translate ) ) { break ; } $ key = $ translate [ $ i ] ; $ cols [ $ key ] = $ GLOBALS [ 'TL_LANG' ] [ 'MSC' ] [ 'sc_' . $ key ] ; } return $ cols ; }

Get columns for a a specific module.

@param \DataContainer $dataContainer The data container driver.

@return array

@SuppressWarnings(PHPMD.Superglobals)


public function getColumnOrders()
    {
        $columns = Bootstrap::getConfigVar('grid-editor.columns');
        $values  = array();

        for ($i = 0; $i <= $columns; $i++) {
            $values['push'][] = 'push-' . $i;
            $values['pull'][] = 'pull-' . $i;
        }

        return $values;
    }

public function getColumnOrders ( ) { $ columns = Bootstrap :: getConfigVar ( 'grid-editor.columns' ) ; $ values = array ( ) ; for ( $ i = 0 ; $ i <= $ columns ; $ i ++ ) { $ values [ 'push' ] [ ] = 'push-' . $ i ; $ values [ 'pull' ] [ ] = 'pull-' . $ i ; } return $ values ; }


public function getColumnNumbers($dataContainer)
    {
        if ($dataContainer->activeRecord) {
            $columns = $dataContainer->activeRecord->columns;
        } else {
            $columns = Bootstrap::getConfigVar('grid-editor.columns');
        }

        $values = range(1, $columns);

        return $values;
    }

public function getColumnNumbers ( $ dataContainer ) { if ( $ dataContainer -> activeRecord ) { $ columns = $ dataContainer -> activeRecord -> columns ; } else { $ columns = Bootstrap :: getConfigVar ( 'grid-editor.columns' ) ; } $ values = range ( 1 , $ columns ) ; return $ values ; }

Get column numbers.

@param \DataContainer $dataContainer Data container driver.

@return array


public function get(string $key, $default = null)
    {
        if (array_key_exists($key, $this->data)) {
            return $this->data[$key];
        }

        return array_key_exists($key, $this->session) ? $this->session[$key] : $default;
    }

public function get ( string $ key , $ default = null ) { if ( array_key_exists ( $ key , $ this -> data ) ) { return $ this -> data [ $ key ] ; } return array_key_exists ( $ key , $ this -> session ) ? $ this -> session [ $ key ] : $ default ; }

Read a value

@param string $key Key
@param mixed|null $default Default value

@return  mixed


public function has(string $key): bool
    {
        return array_key_exists($key, $this->data) || array_key_exists($key, $this->session);
    }

public function has ( string $ key ) : bool { return array_key_exists ( $ key , $ this -> data ) || array_key_exists ( $ key , $ this -> session ) ; }

Check if a key exists

@param string $key Key
@return boolean


public function delete(string $key): self
    {
        unset($this->data[$key]);
        unset($this->session[$key]);
        return $this;
    }

public function delete ( string $ key ) : self { unset ( $ this -> data [ $ key ] ) ; unset ( $ this -> session [ $ key ] ) ; return $ this ; }

Remove specified key

@param string $key Key
@return  Flash


public function load(string $key, callable $callback)
    {
        if (!$this->has($key)) {
            $this->set($key, $callback($key));
        }

        return $this->get($key);
    }

public function load ( string $ key , callable $ callback ) { if ( ! $ this -> has ( $ key ) ) { $ this -> set ( $ key , $ callback ( $ key ) ) ; } return $ this -> get ( $ key ) ; }

Read the value associated with the specified key or associate
the specified key with the value returned by invoking the callback.

@param string $key Key
@param callable $callback Callback

@return mixed

Read the value associated with the specified key or associate the specified key with the value returned by invoking the callback .


public function reflash(array $keys = null): self
    {
        if ($keys === null) {
            return $this->clear($this->data + $this->session);
        }

        $session = array_intersect_key($this->session, array_flip($keys));
        return $this->clear($this->data + $session);
    }

public function reflash ( array $ keys = null ) : self { if ( $ keys === null ) { return $ this -> clear ( $ this -> data + $ this -> session ) ; } $ session = array_intersect_key ( $ this -> session , array_flip ( $ keys ) ) ; return $ this -> clear ( $ this -> data + $ session ) ; }

Re-flash data

@param array|null $keys Data

@return Flash