Spade
Mini Shell
| Directory:~$ /home/lmsyaran/public_html/joomla4/ |
| [Home] [System Details] [Kill Me] |
PKk�[��fk�3�3ComponentHelper.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Access\Access;
use Joomla\CMS\Component\Exception\MissingComponentException;
use Joomla\Registry\Registry;
/**
* Component helper class
*
* @since 1.5
*/
class ComponentHelper
{
/**
* The component list cache
*
* @var ComponentRecord[]
* @since 1.6
*/
protected static $components = array();
/**
* Get the component information.
*
* @param string $option The component option.
* @param boolean $strict If set and the component does not exist, the
enabled attribute will be set to false.
*
* @return ComponentRecord An object with the information for the
component.
*
* @since 1.5
*/
public static function getComponent($option, $strict = false)
{
$components = static::getComponents();
if (isset($components[$option]))
{
return $components[$option];
}
$result = new ComponentRecord;
$result->enabled = $strict ? false : true;
$result->setParams(new Registry);
return $result;
}
/**
* Checks if the component is enabled
*
* @param string $option The component option.
*
* @return boolean
*
* @since 1.5
*/
public static function isEnabled($option)
{
$components = static::getComponents();
return isset($components[$option]) &&
$components[$option]->enabled;
}
/**
* Checks if a component is installed
*
* @param string $option The component option.
*
* @return integer
*
* @since 3.4
*/
public static function isInstalled($option)
{
$components = static::getComponents();
return isset($components[$option]) ? 1 : 0;
}
/**
* Gets the parameter object for the component
*
* @param string $option The option for the component.
* @param boolean $strict If set and the component does not exist,
false will be returned
*
* @return Registry A Registry object.
*
* @see Registry
* @since 1.5
*/
public static function getParams($option, $strict = false)
{
return static::getComponent($option, $strict)->getParams();
}
/**
* Applies the global text filters to arbitrary text as per settings for
current user groups
*
* @param string $text The string to filter
*
* @return string The filtered string
*
* @since 2.5
*/
public static function filterText($text)
{
// Punyencoding utf8 email addresses
$text = \JFilterInput::getInstance()->emailToPunycode($text);
// Filter settings
$config = static::getParams('com_config');
$user = \JFactory::getUser();
$userGroups = Access::getGroupsByUser($user->get('id'));
$filters = $config->get('filters');
$blackListTags = array();
$blackListAttributes = array();
$customListTags = array();
$customListAttributes = array();
$whiteListTags = array();
$whiteListAttributes = array();
$whiteList = false;
$blackList = false;
$customList = false;
$unfiltered = false;
// Cycle through each of the user groups the user is in.
// Remember they are included in the Public group as well.
foreach ($userGroups as $groupId)
{
// May have added a group by not saved the filters.
if (!isset($filters->$groupId))
{
continue;
}
// Each group the user is in could have different filtering properties.
$filterData = $filters->$groupId;
$filterType = strtoupper($filterData->filter_type);
if ($filterType === 'NH')
{
// Maximum HTML filtering.
}
elseif ($filterType === 'NONE')
{
// No HTML filtering.
$unfiltered = true;
}
else
{
// Blacklist or whitelist.
// Preprocess the tags and attributes.
$tags = explode(',', $filterData->filter_tags);
$attributes = explode(',',
$filterData->filter_attributes);
$tempTags = array();
$tempAttributes = array();
foreach ($tags as $tag)
{
$tag = trim($tag);
if ($tag)
{
$tempTags[] = $tag;
}
}
foreach ($attributes as $attribute)
{
$attribute = trim($attribute);
if ($attribute)
{
$tempAttributes[] = $attribute;
}
}
// Collect the blacklist or whitelist tags and attributes.
// Each list is cumulative.
if ($filterType === 'BL')
{
$blackList = true;
$blackListTags = array_merge($blackListTags, $tempTags);
$blackListAttributes = array_merge($blackListAttributes,
$tempAttributes);
}
elseif ($filterType === 'CBL')
{
// Only set to true if Tags or Attributes were added
if ($tempTags || $tempAttributes)
{
$customList = true;
$customListTags = array_merge($customListTags, $tempTags);
$customListAttributes = array_merge($customListAttributes,
$tempAttributes);
}
}
elseif ($filterType === 'WL')
{
$whiteList = true;
$whiteListTags = array_merge($whiteListTags, $tempTags);
$whiteListAttributes = array_merge($whiteListAttributes,
$tempAttributes);
}
}
}
// Remove duplicates before processing (because the blacklist uses both
sets of arrays).
$blackListTags = array_unique($blackListTags);
$blackListAttributes = array_unique($blackListAttributes);
$customListTags = array_unique($customListTags);
$customListAttributes = array_unique($customListAttributes);
$whiteListTags = array_unique($whiteListTags);
$whiteListAttributes = array_unique($whiteListAttributes);
if (!$unfiltered)
{
// Custom blacklist precedes Default blacklist
if ($customList)
{
$filter = \JFilterInput::getInstance(array(), array(), 1, 1);
// Override filter's default blacklist tags and attributes
if ($customListTags)
{
$filter->tagBlacklist = $customListTags;
}
if ($customListAttributes)
{
$filter->attrBlacklist = $customListAttributes;
}
}
// Blacklists take second precedence.
elseif ($blackList)
{
// Remove the whitelisted tags and attributes from the black-list.
$blackListTags = array_diff($blackListTags, $whiteListTags);
$blackListAttributes = array_diff($blackListAttributes,
$whiteListAttributes);
$filter = \JFilterInput::getInstance($blackListTags,
$blackListAttributes, 1, 1);
// Remove whitelisted tags from filter's default blacklist
if ($whiteListTags)
{
$filter->tagBlacklist = array_diff($filter->tagBlacklist,
$whiteListTags);
}
// Remove whitelisted attributes from filter's default blacklist
if ($whiteListAttributes)
{
$filter->attrBlacklist = array_diff($filter->attrBlacklist,
$whiteListAttributes);
}
}
// Whitelists take third precedence.
elseif ($whiteList)
{
// Turn off XSS auto clean
$filter = \JFilterInput::getInstance($whiteListTags,
$whiteListAttributes, 0, 0, 0);
}
// No HTML takes last place.
else
{
$filter = \JFilterInput::getInstance();
}
$text = $filter->clean($text, 'html');
}
return $text;
}
/**
* Render the component.
*
* @param string $option The component option.
* @param array $params The component parameters
*
* @return string
*
* @since 1.5
* @throws MissingComponentException
*/
public static function renderComponent($option, $params = array())
{
$app = \JFactory::getApplication();
// Load template language files.
$template = $app->getTemplate(true)->template;
$lang = \JFactory::getLanguage();
$lang->load('tpl_' . $template, JPATH_BASE, null, false,
true)
|| $lang->load('tpl_' . $template, JPATH_THEMES .
"/$template", null, false, true);
if (empty($option))
{
throw new
MissingComponentException(\JText::_('JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND'),
404);
}
if (JDEBUG)
{
\JProfiler::getInstance('Application')->mark('beforeRenderComponent
' . $option);
}
// Record the scope
$scope = $app->scope;
// Set scope to component name
$app->scope = $option;
// Build the component path.
$option = preg_replace('/[^A-Z0-9_\.-]/i', '',
$option);
$file = substr($option, 4);
// Define component path.
if (!defined('JPATH_COMPONENT'))
{
/**
* Defines the path to the active component for the request
*
* Note this constant is application aware and is different for each
application (site/admin).
*
* @var string
* @since 1.5
*/
define('JPATH_COMPONENT', JPATH_BASE .
'/components/' . $option);
}
if (!defined('JPATH_COMPONENT_SITE'))
{
/**
* Defines the path to the site element of the active component for the
request
*
* @var string
* @since 1.5
*/
define('JPATH_COMPONENT_SITE', JPATH_SITE .
'/components/' . $option);
}
if (!defined('JPATH_COMPONENT_ADMINISTRATOR'))
{
/**
* Defines the path to the admin element of the active component for the
request
*
* @var string
* @since 1.5
*/
define('JPATH_COMPONENT_ADMINISTRATOR', JPATH_ADMINISTRATOR .
'/components/' . $option);
}
$path = JPATH_COMPONENT . '/' . $file . '.php';
// If component is disabled throw error
if (!static::isEnabled($option) || !file_exists($path))
{
throw new
MissingComponentException(\JText::_('JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND'),
404);
}
// Load common and local language files.
$lang->load($option, JPATH_BASE, null, false, true) ||
$lang->load($option, JPATH_COMPONENT, null, false, true);
// Handle template preview outlining.
$contents = null;
// Execute the component.
$contents = static::executeComponent($path);
// Revert the scope
$app->scope = $scope;
if (JDEBUG)
{
\JProfiler::getInstance('Application')->mark('afterRenderComponent
' . $option);
}
return $contents;
}
/**
* Execute the component.
*
* @param string $path The component path.
*
* @return string The component output
*
* @since 1.7
*/
protected static function executeComponent($path)
{
ob_start();
require_once $path;
return ob_get_clean();
}
/**
* Load the installed components into the components property.
*
* @param string $option The element value for the extension
*
* @return boolean True on success
*
* @since 1.5
* @deprecated 4.0 Use JComponentHelper::load() instead
*/
protected static function _load($option)
{
return static::load($option);
}
/**
* Load the installed components into the components property.
*
* @param string $option The element value for the extension
*
* @return boolean True on success
*
* @since 3.2
* @note As of 4.0 this method will be restructured to only load the
data into memory
*/
protected static function load($option)
{
$loader = function ()
{
$db = \JFactory::getDbo();
$query = $db->getQuery(true)
->select($db->quoteName(array('extension_id',
'element', 'params', 'enabled'),
array('id', 'option', null, null)))
->from($db->quoteName('#__extensions'))
->where($db->quoteName('type') . ' = ' .
$db->quote('component'))
->where($db->quoteName('state') . ' = 0')
->where($db->quoteName('enabled') . ' = 1');
$db->setQuery($query);
return $db->loadObjectList('option',
'\JComponentRecord');
};
/** @var \JCacheControllerCallback $cache */
$cache = \JFactory::getCache('_system', 'callback');
try
{
static::$components = $cache->get($loader, array(), __METHOD__);
}
catch (\JCacheException $e)
{
static::$components = $loader();
}
// Core CMS will use '*' as a placeholder for required
parameter in this method. In 4.0 this will not be passed at all.
if (isset($option) && $option != '*')
{
// Log deprecated warning and display missing component warning only if
using deprecated format.
try
{
\JLog::add(
sprintf(
'Passing a parameter into %s() is deprecated and will be removed
in 4.0. Read %s::$components directly after loading the data.',
__METHOD__,
__CLASS__
),
\JLog::WARNING,
'deprecated'
);
}
catch (\RuntimeException $e)
{
// Informational log only
}
if (empty(static::$components[$option]))
{
/*
* Fatal error
*
* It is possible for this error to be reached before the global
\JLanguage instance has been loaded so we check for its presence
* before logging the error to ensure a human friendly message is
always given
*/
if (\JFactory::$language)
{
$msg =
\JText::sprintf('JLIB_APPLICATION_ERROR_COMPONENT_NOT_LOADING',
$option,
\JText::_('JLIB_APPLICATION_ERROR_COMPONENT_NOT_FOUND'));
}
else
{
$msg = sprintf('Error loading component: %1$s, %2$s',
$option, 'Component not found.');
}
\JLog::add($msg, \JLog::WARNING, 'jerror');
return false;
}
}
return true;
}
/**
* Get installed components
*
* @return ComponentRecord[] The components property
*
* @since 3.6.3
*/
public static function getComponents()
{
if (empty(static::$components))
{
static::load('*');
}
return static::$components;
}
}
PKk�[�3��
�
ComponentRecord.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component;
defined('JPATH_PLATFORM') or die;
use Joomla\Registry\Registry;
/**
* Object representing a component extension record
*
* @since 3.7.0
* @note As of 4.0 this class will no longer extend JObject
*/
class ComponentRecord extends \JObject
{
/**
* Primary key
*
* @var integer
* @since 3.7.0
*/
public $id;
/**
* The component name
*
* @var integer
* @since 3.7.0
*/
public $option;
/**
* The component parameters
*
* @var string|Registry
* @since 3.7.0
* @note This field is protected to require reading this field to proxy
through the getter to convert the params to a Registry instance
*/
protected $params;
/**
* Indicates if this component is enabled
*
* @var integer
* @since 3.7.0
*/
public $enabled;
/**
* Class constructor
*
* @param array $data The component record data to load
*
* @since 3.7.0
*/
public function __construct($data = array())
{
foreach ((array) $data as $key => $value)
{
$this->$key = $value;
}
}
/**
* Method to get certain otherwise inaccessible properties from the form
field object.
*
* @param string $name The property name for which to get the value.
*
* @return mixed The property value or null.
*
* @since 3.7.0
* @deprecated 4.0 Access the item parameters through the `getParams()`
method
*/
public function __get($name)
{
if ($name === 'params')
{
return $this->getParams();
}
return $this->get($name);
}
/**
* Method to set certain otherwise inaccessible properties of the form
field object.
*
* @param string $name The property name for which to set the value.
* @param mixed $value The value of the property.
*
* @return void
*
* @since 3.7.0
* @deprecated 4.0 Set the item parameters through the `setParams()`
method
*/
public function __set($name, $value)
{
if ($name === 'params')
{
$this->setParams($value);
return;
}
$this->set($name, $value);
}
/**
* Returns the menu item parameters
*
* @return Registry
*
* @since 3.7.0
*/
public function getParams()
{
if (!($this->params instanceof Registry))
{
$this->params = new Registry($this->params);
}
return $this->params;
}
/**
* Sets the menu item parameters
*
* @param Registry|string $params The data to be stored as the
parameters
*
* @return void
*
* @since 3.7.0
*/
public function setParams($params)
{
$this->params = $params;
}
}
PKk�[��5d��'Exception/MissingComponentException.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Exception;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Router\Exception\RouteNotFoundException;
/**
* Exception class defining an error for a missing component
*
* @since 3.7.0
*/
class MissingComponentException extends RouteNotFoundException
{
/**
* Constructor
*
* @param string $message The Exception message to throw.
* @param integer $code The Exception code.
* @param \Exception $previous The previous exception used for the
exception chaining.
*
* @since 3.7.0
*/
public function __construct($message = '', $code = 404,
\Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
PKk�[u�(zzRouter/RouterBase.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router;
defined('JPATH_PLATFORM') or die;
/**
* Base component routing class
*
* @since 3.3
*/
abstract class RouterBase implements RouterInterface
{
/**
* Application object to use in the router
*
* @var \JApplicationCms
* @since 3.4
*/
public $app;
/**
* Menu object to use in the router
*
* @var \JMenu
* @since 3.4
*/
public $menu;
/**
* Class constructor.
*
* @param \JApplicationCms $app Application-object that the router
should use
* @param \JMenu $menu Menu-object that the router should
use
*
* @since 3.4
*/
public function __construct($app = null, $menu = null)
{
if ($app)
{
$this->app = $app;
}
else
{
$this->app = \JFactory::getApplication('site');
}
if ($menu)
{
$this->menu = $menu;
}
else
{
$this->menu = $this->app->getMenu();
}
}
/**
* Generic method to preprocess a URL
*
* @param array $query An associative array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.3
*/
public function preprocess($query)
{
return $query;
}
}
PKk�[�M�6��Router/RouterInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Router;
interface RouterInterface
{
public function dispatch();
}
PKk�[�2L ��Router/RouterLegacy.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router;
defined('JPATH_PLATFORM') or die;
/**
* Default routing class for missing or legacy component routers
*
* @since 3.3
*/
class RouterLegacy implements RouterInterface
{
/**
* Name of the component
*
* @var string
* @since 3.3
*/
protected $component;
/**
* Constructor
*
* @param string $component Component name without the com_ prefix
this router should react upon
*
* @since 3.3
*/
public function __construct($component)
{
$this->component = $component;
}
/**
* Generic preprocess function for missing or legacy component router
*
* @param array $query An associative array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.3
*/
public function preprocess($query)
{
return $query;
}
/**
* Generic build function for missing or legacy component router
*
* @param array &$query An array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.3
*/
public function build(&$query)
{
$function = $this->component . 'BuildRoute';
if (function_exists($function))
{
$segments = $function($query);
$total = count($segments);
for ($i = 0; $i < $total; $i++)
{
$segments[$i] = str_replace(':', '-',
$segments[$i]);
}
return $segments;
}
return array();
}
/**
* Generic parse function for missing or legacy component router
*
* @param array &$segments The segments of the URL to parse.
*
* @return array The URL attributes to be used by the application.
*
* @since 3.3
*/
public function parse(&$segments)
{
$function = $this->component . 'ParseRoute';
if (function_exists($function))
{
$total = count($segments);
for ($i = 0; $i < $total; $i++)
{
$segments[$i] = preg_replace('/-/', ':',
$segments[$i], 1);
}
return $function($segments);
}
return array();
}
}
PKk�[�`��Router/RouterView.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\Router\Rules\RulesInterface;
/**
* View-based component routing class
*
* @since 3.5
*/
abstract class RouterView extends RouterBase
{
/**
* Name of the router of the component
*
* @var string
* @since 3.5
*/
protected $name;
/**
* Array of rules
*
* @var RulesInterface[]
* @since 3.5
*/
protected $rules = array();
/**
* Views of the component
*
* @var RouterViewConfiguration[]
* @since 3.5
*/
protected $views = array();
/**
* Register the views of a component
*
* @param RouterViewConfiguration $view View configuration object
*
* @return void
*
* @since 3.5
*/
public function registerView(RouterViewConfiguration $view)
{
$this->views[$view->name] = $view;
}
/**
* Return an array of registered view objects
*
* @return RouterViewConfiguration[] Array of registered view objects
*
* @since 3.5
*/
public function getViews()
{
return $this->views;
}
/**
* Get the path of views from target view to root view
* including content items of a nestable view
*
* @param array $query Array of query elements
*
* @return array List of views including IDs of content items
*
* @since 3.5
*/
public function getPath($query)
{
$views = $this->getViews();
$result = array();
// Get the right view object
if (isset($query['view']) &&
isset($views[$query['view']]))
{
$viewobj = $views[$query['view']];
}
// Get the path from the current item to the root view with all IDs
if (isset($viewobj))
{
$path = array_reverse($viewobj->path);
$start = true;
$childkey = false;
foreach ($path as $element)
{
$view = $views[$element];
if ($start)
{
$key = $view->key;
$start = false;
}
else
{
$key = $childkey;
}
$childkey = $view->parent_key;
if (($key || $view->key) && is_callable(array($this,
'get' . ucfirst($view->name) . 'Segment')))
{
if (isset($query[$key]))
{
$result[$view->name] = call_user_func_array(array($this,
'get' . ucfirst($view->name) . 'Segment'),
array($query[$key], $query));
}
elseif (isset($query[$view->key]))
{
$result[$view->name] = call_user_func_array(array($this,
'get' . ucfirst($view->name) . 'Segment'),
array($query[$view->key], $query));
}
else
{
$result[$view->name] = array();
}
}
else
{
$result[$view->name] = true;
}
}
}
return $result;
}
/**
* Get all currently attached rules
*
* @return RulesInterface[] All currently attached rules in an array
*
* @since 3.5
*/
public function getRules()
{
return $this->rules;
}
/**
* Add a number of router rules to the object
*
* @param RulesInterface[] $rules Array of
JComponentRouterRulesInterface objects
*
* @return void
*
* @since 3.5
*/
public function attachRules($rules)
{
foreach ($rules as $rule)
{
$this->attachRule($rule);
}
}
/**
* Attach a build rule
*
* @param RulesInterface $rule The function to be called.
*
* @return void
*
* @since 3.5
*/
public function attachRule(RulesInterface $rule)
{
$this->rules[] = $rule;
}
/**
* Remove a build rule
*
* @param RulesInterface $rule The rule to be removed.
*
* @return boolean Was a rule removed?
*
* @since 3.5
*/
public function detachRule(RulesInterface $rule)
{
foreach ($this->rules as $id => $r)
{
if ($r == $rule)
{
unset($this->rules[$id]);
return true;
}
}
return false;
}
/**
* Generic method to preprocess a URL
*
* @param array $query An associative array of URL arguments
*
* @return array The URL arguments to use to assemble the subsequent
URL.
*
* @since 3.5
*/
public function preprocess($query)
{
// Process the parsed variables based on custom defined rules
foreach ($this->rules as $rule)
{
$rule->preprocess($query);
}
return $query;
}
/**
* Build method for URLs
*
* @param array &$query Array of query elements
*
* @return array Array of URL segments
*
* @since 3.5
*/
public function build(&$query)
{
$segments = array();
// Process the parsed variables based on custom defined rules
foreach ($this->rules as $rule)
{
$rule->build($query, $segments);
}
return $segments;
}
/**
* Parse method for URLs
*
* @param array &$segments Array of URL string-segments
*
* @return array Associative array of query values
*
* @since 3.5
*/
public function parse(&$segments)
{
$vars = array();
// Process the parsed variables based on custom defined rules
foreach ($this->rules as $rule)
{
$rule->parse($segments, $vars);
}
return $vars;
}
/**
* Method to return the name of the router
*
* @return string Name of the router
*
* @since 3.5
*/
public function getName()
{
if (empty($this->name))
{
$r = null;
if (!preg_match('/(.*)Router/i', get_class($this), $r))
{
throw new
\Exception('JLIB_APPLICATION_ERROR_ROUTER_GET_NAME', 500);
}
$this->name = strtolower($r[1]);
}
return $this->name;
}
}
PKk�[���xx"Router/RouterViewConfiguration.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router;
defined('JPATH_PLATFORM') or die;
/**
* View-configuration class for the view-based component router
*
* @since 3.5
*/
class RouterViewConfiguration
{
/**
* Name of the view
*
* @var string
* @since 3.5
*/
public $name;
/**
* Key of the view
*
* @var string
* @since 3.5
*/
public $key = false;
/**
* Parentview of this one
*
* @var RouterViewconfiguration
* @since 3.5
*/
public $parent = false;
/**
* Key of the parent view
*
* @var string
* @since 3.5
*/
public $parent_key = false;
/**
* Is this view nestable?
*
* @var bool
* @since 3.5
*/
public $nestable = false;
/**
* Layouts that are supported by this view
*
* @var array
* @since 3.5
*/
public $layouts = array('default');
/**
* Child-views of this view
*
* @var RouterViewconfiguration[]
* @since 3.5
*/
public $children = array();
/**
* Keys used for this parent view by the child views
*
* @var array
* @since 3.5
*/
public $child_keys = array();
/**
* Path of views from this one to the root view
*
* @var array
* @since 3.5
*/
public $path = array();
/**
* Constructor for the View-configuration class
*
* @param string $name Name of the view
*
* @since 3.5
*/
public function __construct($name)
{
$this->name = $name;
$this->path[] = $name;
}
/**
* Set the name of the view
*
* @param string $name Name of the view
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function setName($name)
{
$this->name = $name;
array_pop($this->path);
$this->path[] = $name;
return $this;
}
/**
* Set the key-identifier for the view
*
* @param string $key Key of the view
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function setKey($key)
{
$this->key = $key;
return $this;
}
/**
* Set the parent view of this view
*
* @param RouterViewconfiguration $parent Parent view object
* @param string $parentKey Key of the parent view in
this context
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function setParent(RouterViewconfiguration $parent, $parentKey =
false)
{
if ($this->parent)
{
$key = array_search($this, $this->parent->children);
if ($key !== false)
{
unset($this->parent->children[$key]);
}
if ($this->parent_key)
{
$child_key = array_search($this->parent_key,
$this->parent->child_keys);
unset($this->parent->child_keys[$child_key]);
}
}
$this->parent = $parent;
$parent->children[] = $this;
$this->path = $parent->path;
$this->path[] = $this->name;
$this->parent_key = $parentKey;
if ($parentKey)
{
$parent->child_keys[] = $parentKey;
}
return $this;
}
/**
* Set if this view is nestable or not
*
* @param bool $isNestable If set to true, the view is nestable
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function setNestable($isNestable = true)
{
$this->nestable = (bool) $isNestable;
return $this;
}
/**
* Add a layout to this view
*
* @param string $layout Layouts that this view supports
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function addLayout($layout)
{
$this->layouts[] = $layout;
$this->layouts = array_unique($this->layouts);
return $this;
}
/**
* Remove a layout from this view
*
* @param string $layout Layouts that this view supports
*
* @return RouterViewconfiguration This object for chaining
*
* @since 3.5
*/
public function removeLayout($layout)
{
$key = array_search($layout, $this->layouts);
if ($key !== false)
{
unset($this->layouts[$key]);
}
return $this;
}
}
PKk�[UA*��Router/Rules/MenuRules.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router\Rules;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Component\Router\RouterView;
/**
* Rule to identify the right Itemid for a view in a component
*
* @since 3.4
*/
class MenuRules implements RulesInterface
{
/**
* Router this rule belongs to
*
* @var RouterView
* @since 3.4
*/
protected $router;
/**
* Lookup array of the menu items
*
* @var array
* @since 3.4
*/
protected $lookup = array();
/**
* Class constructor.
*
* @param RouterView $router Router this rule belongs to
*
* @since 3.4
*/
public function __construct(RouterView $router)
{
$this->router = $router;
$this->buildLookup();
}
/**
* Finds the right Itemid for this query
*
* @param array &$query The query array to process
*
* @return void
*
* @since 3.4
*/
public function preprocess(&$query)
{
$active = $this->router->menu->getActive();
/**
* If the active item id is not the same as the supplied item id or we
have a supplied item id and no active
* menu item then we just use the supplied menu item and continue
*/
if (isset($query['Itemid']) && ($active === null ||
$query['Itemid'] != $active->id))
{
return;
}
// Get query language
$language = isset($query['lang']) ? $query['lang'] :
'*';
if (!isset($this->lookup[$language]))
{
$this->buildLookup($language);
}
// Check if the active menu item matches the requested query
if ($active !== null && isset($query['Itemid']))
{
// Check if active->query and supplied query are the same
$match = true;
foreach ($active->query as $k => $v)
{
if (isset($query[$k]) && $v !== $query[$k])
{
// Compare again without alias
if (is_string($v) && $v == current(explode(':',
$query[$k], 2)))
{
continue;
}
$match = false;
break;
}
}
if ($match)
{
// Just use the supplied menu item
return;
}
}
$needles = $this->router->getPath($query);
$layout = isset($query['layout']) &&
$query['layout'] !== 'default' ? ':' .
$query['layout'] : '';
if ($needles)
{
foreach ($needles as $view => $ids)
{
$viewLayout = $view . $layout;
if ($layout && isset($this->lookup[$language][$viewLayout]))
{
if (is_bool($ids))
{
$query['Itemid'] =
$this->lookup[$language][$viewLayout];
return;
}
foreach ($ids as $id => $segment)
{
if (isset($this->lookup[$language][$viewLayout][(int) $id]))
{
$query['Itemid'] =
$this->lookup[$language][$viewLayout][(int) $id];
return;
}
}
}
if (isset($this->lookup[$language][$view]))
{
if (is_bool($ids))
{
$query['Itemid'] = $this->lookup[$language][$view];
return;
}
foreach ($ids as $id => $segment)
{
if (isset($this->lookup[$language][$view][(int) $id]))
{
$query['Itemid'] =
$this->lookup[$language][$view][(int) $id];
return;
}
}
}
}
}
// Check if the active menuitem matches the requested language
if ($active && $active->component === 'com_' .
$this->router->getName()
&& ($language === '*' ||
in_array($active->language, array('*', $language)) ||
!\JLanguageMultilang::isEnabled()))
{
$query['Itemid'] = $active->id;
return;
}
// If not found, return language specific home link
$default = $this->router->menu->getDefault($language);
if (!empty($default->id))
{
$query['Itemid'] = $default->id;
}
}
/**
* Method to build the lookup array
*
* @param string $language The language that the lookup should be
built up for
*
* @return void
*
* @since 3.4
*/
protected function buildLookup($language = '*')
{
// Prepare the reverse lookup array.
if (!isset($this->lookup[$language]))
{
$this->lookup[$language] = array();
$component = ComponentHelper::getComponent('com_' .
$this->router->getName());
$views = $this->router->getViews();
$attributes = array('component_id');
$values = array((int) $component->id);
$attributes[] = 'language';
$values[] = array($language, '*');
$items = $this->router->menu->getItems($attributes, $values);
foreach ($items as $item)
{
if (isset($item->query['view'],
$views[$item->query['view']]))
{
$view = $item->query['view'];
$layout = '';
if (isset($item->query['layout']))
{
$layout = ':' . $item->query['layout'];
}
if ($views[$view]->key)
{
if (!isset($this->lookup[$language][$view . $layout]))
{
$this->lookup[$language][$view . $layout] = array();
}
if (!isset($this->lookup[$language][$view]))
{
$this->lookup[$language][$view] = array();
}
// If menuitem has no key set, we assume 0.
if (!isset($item->query[$views[$view]->key]))
{
$item->query[$views[$view]->key] = 0;
}
/**
* Here it will become a bit tricky
* language != * can override existing entries
* language == * cannot override existing entries
*/
if (!isset($this->lookup[$language][$view .
$layout][$item->query[$views[$view]->key]]) || $item->language !==
'*')
{
$this->lookup[$language][$view .
$layout][$item->query[$views[$view]->key]] = $item->id;
$this->lookup[$language][$view][$item->query[$views[$view]->key]]
= $item->id;
}
}
else
{
/**
* Here it will become a bit tricky
* language != * can override existing entries
* language == * cannot override existing entries
*/
if (!isset($this->lookup[$language][$view . $layout]) ||
$item->language !== '*')
{
$this->lookup[$language][$view . $layout] = $item->id;
$this->lookup[$language][$view] = $item->id;
}
}
}
}
}
}
/**
* Dummymethod to fullfill the interface requirements
*
* @param array &$segments The URL segments to parse
* @param array &$vars The vars that result from the segments
*
* @return void
*
* @since 3.4
* @codeCoverageIgnore
*/
public function parse(&$segments, &$vars)
{
}
/**
* Dummymethod to fullfill the interface requirements
*
* @param array &$query The vars that should be converted
* @param array &$segments The URL segments to create
*
* @return void
*
* @since 3.4
* @codeCoverageIgnore
*/
public function build(&$query, &$segments)
{
}
}
PKk�[��`TTRouter/Rules/NomenuRules.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router\Rules;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\Router\RouterView;
/**
* Rule to process URLs without a menu item
*
* @since 3.4
*/
class NomenuRules implements RulesInterface
{
/**
* Router this rule belongs to
*
* @var RouterView
* @since 3.4
*/
protected $router;
/**
* Class constructor.
*
* @param RouterView $router Router this rule belongs to
*
* @since 3.4
*/
public function __construct(RouterView $router)
{
$this->router = $router;
}
/**
* Dummymethod to fullfill the interface requirements
*
* @param array &$query The query array to process
*
* @return void
*
* @since 3.4
* @codeCoverageIgnore
*/
public function preprocess(&$query)
{
}
/**
* Parse a menu-less URL
*
* @param array &$segments The URL segments to parse
* @param array &$vars The vars that result from the segments
*
* @return void
*
* @since 3.4
*/
public function parse(&$segments, &$vars)
{
$active = $this->router->menu->getActive();
if (!is_object($active))
{
$views = $this->router->getViews();
if (isset($views[$segments[0]]))
{
$vars['view'] = array_shift($segments);
if (isset($views[$vars['view']]->key) &&
isset($segments[0]))
{
$vars[$views[$vars['view']]->key] =
preg_replace('/-/', ':', array_shift($segments), 1);
}
}
}
}
/**
* Build a menu-less URL
*
* @param array &$query The vars that should be converted
* @param array &$segments The URL segments to create
*
* @return void
*
* @since 3.4
*/
public function build(&$query, &$segments)
{
$menu_found = false;
if (isset($query['Itemid']))
{
$item =
$this->router->menu->getItem($query['Itemid']);
if (!isset($query['option']) || ($item &&
$item->query['option'] === $query['option']))
{
$menu_found = true;
}
}
if (!$menu_found && isset($query['view']))
{
$views = $this->router->getViews();
if (isset($views[$query['view']]))
{
$view = $views[$query['view']];
$segments[] = $query['view'];
if ($view->key && isset($query[$view->key]))
{
if (is_callable(array($this->router, 'get' .
ucfirst($view->name) . 'Segment')))
{
$result = call_user_func_array(array($this->router,
'get' . ucfirst($view->name) . 'Segment'),
array($query[$view->key], $query));
$segments[] = str_replace(':', '-',
array_shift($result));
}
else
{
$segments[] = str_replace(':', '-',
$query[$view->key]);
}
unset($query[$views[$query['view']]->key]);
}
unset($query['view']);
}
}
}
}
PKk�[fnJooRouter/Rules/RulesInterface.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router\Rules;
defined('JPATH_PLATFORM') or die;
/**
* RouterRules interface for Joomla
*
* @since 3.4
*/
interface RulesInterface
{
/**
* Prepares a query set to be handed over to the build() method.
* This should complete a partial query set to work as a complete
non-SEFed
* URL and in general make sure that all information is present and
properly
* formatted. For example, the Itemid should be retrieved and set here.
*
* @param array &$query The query array to process
*
* @return void
*
* @since 3.4
*/
public function preprocess(&$query);
/**
* Parses a URI to retrieve informations for the right route through
* the component.
* This method should retrieve all its input from its method arguments.
*
* @param array &$segments The URL segments to parse
* @param array &$vars The vars that result from the segments
*
* @return void
*
* @since 3.4
*/
public function parse(&$segments, &$vars);
/**
* Builds URI segments from a query to encode the necessary informations
* for a route in a human-readable URL.
* This method should retrieve all its input from its method arguments.
*
* @param array &$query The vars that should be converted
* @param array &$segments The URL segments to create
*
* @return void
*
* @since 3.4
*/
public function build(&$query, &$segments);
}
PKk�[_�Y��Router/Rules/StandardRules.phpnu�[���<?php
/**
* Joomla! Content Management System
*
* @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All
rights reserved.
* @license GNU General Public License version 2 or later; see
LICENSE.txt
*/
namespace Joomla\CMS\Component\Router\Rules;
defined('JPATH_PLATFORM') or die;
use Joomla\CMS\Component\Router\RouterView;
/**
* Rule for the standard handling of component routing
*
* @since 3.4
*/
class StandardRules implements RulesInterface
{
/**
* Router this rule belongs to
*
* @var RouterView
* @since 3.4
*/
protected $router;
/**
* Class constructor.
*
* @param RouterView $router Router this rule belongs to
*
* @since 3.4
*/
public function __construct(RouterView $router)
{
$this->router = $router;
}
/**
* Dummymethod to fullfill the interface requirements
*
* @param array &$query The query array to process
*
* @return void
*
* @since 3.4
*/
public function preprocess(&$query)
{
}
/**
* Parse the URL
*
* @param array &$segments The URL segments to parse
* @param array &$vars The vars that result from the segments
*
* @return void
*
* @since 3.4
*/
public function parse(&$segments, &$vars)
{
// Get the views and the currently active query vars
$views = $this->router->getViews();
$active = $this->router->menu->getActive();
if ($active)
{
$vars = array_merge($active->query, $vars);
}
// We don't have a view or its not a view of this component! We stop
here
if (!isset($vars['view']) ||
!isset($views[$vars['view']]))
{
return;
}
// Copy the segments, so that we can iterate over all of them and at the
same time modify the original segments
$tempSegments = $segments;
// Iterate over the segments as long as a segment fits
foreach ($tempSegments as $segment)
{
// Our current view is nestable. We need to check first if the segment
fits to that
if ($views[$vars['view']]->nestable)
{
if (is_callable(array($this->router, 'get' .
ucfirst($views[$vars['view']]->name) . 'Id')))
{
$key = call_user_func_array(array($this->router, 'get' .
ucfirst($views[$vars['view']]->name) . 'Id'),
array($segment, $vars));
// Did we get a proper key? If not, we need to look in the child-views
if ($key)
{
$vars[$views[$vars['view']]->key] = $key;
array_shift($segments);
continue;
}
}
else
{
// The router is not complete. The get<View>Id() method is
missing.
return;
}
}
// Lets find the right view that belongs to this segment
$found = false;
foreach ($views[$vars['view']]->children as $view)
{
if (!$view->key)
{
if ($view->name === $segment)
{
// The segment is a view name
$parent = $views[$vars['view']];
$vars['view'] = $view->name;
$found = true;
if ($view->parent_key && isset($vars[$parent->key]))
{
$parent_key = $vars[$parent->key];
$vars[$view->parent_key] = $parent_key;
unset($vars[$parent->key]);
}
break;
}
}
elseif (is_callable(array($this->router, 'get' .
ucfirst($view->name) . 'Id')))
{
// Hand the data over to the router specific method and see if there
is a content item that fits
$key = call_user_func_array(array($this->router, 'get' .
ucfirst($view->name) . 'Id'), array($segment, $vars));
if ($key)
{
// Found the right view and the right item
$parent = $views[$vars['view']];
$vars['view'] = $view->name;
$found = true;
if ($view->parent_key && isset($vars[$parent->key]))
{
$parent_key = $vars[$parent->key];
$vars[$view->parent_key] = $parent_key;
unset($vars[$parent->key]);
}
$vars[$view->key] = $key;
break;
}
}
}
if (!$found)
{
return;
}
array_shift($segments);
}
}
/**
* Build a standard URL
*
* @param array &$query The vars that should be converted
* @param array &$segments The URL segments to create
*
* @return void
*
* @since 3.4
*/
public function build(&$query, &$segments)
{
if (!isset($query['Itemid'], $query['view']))
{
return;
}
// Get the menu item belonging to the Itemid that has been found
$item =
$this->router->menu->getItem($query['Itemid']);
if ($item === null
|| $item->component !== 'com_' .
$this->router->getName()
|| !isset($item->query['view']))
{
return;
}
// Get menu item layout
$mLayout = isset($item->query['layout']) ?
$item->query['layout'] : null;
// Get all views for this component
$views = $this->router->getViews();
// Return directly when the URL of the Itemid is identical with the URL
to build
if ($item->query['view'] === $query['view'])
{
$view = $views[$query['view']];
if (!$view->key)
{
unset($query['view']);
if (isset($query['layout']) && $mLayout ===
$query['layout'])
{
unset($query['layout']);
}
return;
}
if (isset($query[$view->key]) &&
$item->query[$view->key] == (int) $query[$view->key])
{
unset($query[$view->key]);
while ($view)
{
unset($query[$view->parent_key]);
$view = $view->parent;
}
unset($query['view']);
if (isset($query['layout']) && $mLayout ===
$query['layout'])
{
unset($query['layout']);
}
return;
}
}
// Get the path from the view of the current URL and parse it to the menu
item
$path = array_reverse($this->router->getPath($query), true);
$found = false;
foreach ($path as $element => $ids)
{
$view = $views[$element];
if ($found === false && $item->query['view'] ===
$element)
{
if ($view->nestable)
{
$found = true;
}
elseif ($view->children)
{
$found = true;
continue;
}
}
if ($found === false)
{
// Jump to the next view
continue;
}
if ($ids)
{
if ($view->nestable)
{
$found2 = false;
foreach (array_reverse($ids, true) as $id => $segment)
{
if ($found2)
{
$segments[] = str_replace(':', '-', $segment);
}
elseif ((int) $item->query[$view->key] === (int) $id)
{
$found2 = true;
}
}
}
elseif ($ids === true)
{
$segments[] = $element;
}
else
{
$segments[] = str_replace(':', '-',
current($ids));
}
}
if ($view->parent_key)
{
// Remove parent key from query
unset($query[$view->parent_key]);
}
}
if ($found)
{
unset($query[$views[$query['view']]->key],
$query['view']);
if (isset($query['layout']) && $mLayout ===
$query['layout'])
{
unset($query['layout']);
}
}
}
}
PKJ[�[�(r��Admin/HtmlController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Admin;
use Gantry\Component\Controller\HtmlController as BaseController;
abstract class HtmlController extends BaseController
{
/**
* @param string|array $file
* @param array $context
* @return string
*/
public function render($file, array $context = [])
{
return
$this->container['admin.theme']->render($file, $context);
}
/**
* @param string $action
* @param string $id
* @return boolean
*/
public function authorize($action, $id = null)
{
return
$this->container['platform']->authorize($action, $id);
}
}
PKJ[�[��p���Admin/JsonController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Admin;
use Gantry\Component\Controller\JsonController as BaseController;
abstract class JsonController extends BaseController
{
/**
* @param string|array $file
* @param array $context
* @return string
*/
public function render($file, array $context = [])
{
return
$this->container['admin.theme']->render($file, $context);
}
/**
* @param string $action
* @param string $id
* @return boolean
*/
public function authorize($action, $id = null)
{
return
$this->container['platform']->authorize($action, $id);
}
}
PKJ[�[ܵ����#Assignments/AbstractAssignments.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Assignments;
use Gantry\Component\Config\CompiledConfig;
use Gantry\Component\Config\ConfigFileFinder;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
abstract class AbstractAssignments
{
/**
* @var string
*/
protected $configuration;
/**
* @var string
*/
protected $className =
'\Gantry\%s\Assignments\Assignments%s';
/**
* @var string
*/
protected $platform;
/**
* @var AssignmentFilter
*/
protected $filter;
/**
* @var array
*/
protected $candidates;
/**
* @var array
*/
protected $page;
/** @var callable */
protected $specialFilterMethod;
/**
* @param string $configuration
*/
public function __construct($configuration = null)
{
$this->configuration = $configuration;
}
/**
* Get list of assignment items.
*/
public function get()
{
return $this->getTypes();
}
/**
* Set (save) assignments.
*
* @param array $data
*/
public function set(array $data)
{
$this->save($data);
}
/**
* Select assigned outline.
*
* @param string $default
* @return string
*/
public function select($default = 'default')
{
$scores = $this->scores();
return key($scores) ?: $default;
}
/**
* List matching outlines sorted by score.
*
* @param array $candidates
* @return array
*/
public function scores(array $candidates = null)
{
$this->init();
$candidates = $candidates ?: $this->candidates;
return $this->filter->scores($candidates, $this->page,
$this->specialFilterMethod);
}
/**
* List matching outlines with matched assignments.
*
* @param array $candidates
* @return array
*/
public function matches(array $candidates = null)
{
$this->init();
$candidates = $candidates ?: $this->candidates;
return $this->filter->matches($candidates, $this->page,
$this->specialFilterMethod);
}
/**
* Load all assignments.
*
* @return array
*/
public function loadAssignments()
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Find all the assignment files.
$paths = $locator->findResources("gantry-config://");
$files = (new
ConfigFileFinder)->locateFileInFolder('assignments', $paths);
// Make sure that base or system outlines aren't in the list.
foreach ($files as $key => $array) {
$key = (string)$key;
if ($key === 'default' || strpos($key, '_')
=== 0) {
unset($files[$key]);
}
}
$cache =
$locator->findResource('gantry-cache://theme/compiled/config',
true, true);
$config = new CompiledConfig($cache, [$files], GANTRY5_ROOT);
return $config->load()->toArray();
}
/**
* Get all assignments for the current page.
*
* @return array
*/
public function getPage()
{
$list = [];
foreach($this->types() as $class => $type) {
$class = is_numeric($class) ? sprintf($this->className,
$this->platform, ucfirst($type)) : $class;
if (!class_exists($class)) {
throw new \RuntimeException("Assignment type {$type}
is missing");
}
/** @var AssignmentsInterface $instance */
$instance = new $class;
$list[$type] = $instance->getRules();
unset($instance);
}
return $list;
}
/**
* Filter assignments data.
*
* @param array $data
* @param bool $minimize
* @return array
*/
public function filter(array $data, $minimize = false)
{
$types = [];
foreach ($this->types() as $type) {
$types[$type] = [];
}
$data = array_replace($types, $data);
foreach ($data as $tname => &$type) {
if (is_array($type)) {
foreach ($type as $gname => &$group) {
if (is_array($group)) {
foreach ($group as $key => $value) {
if (!$value) {
unset($group[$key]);
} else {
$group[$key] = (bool) $value;
}
}
if (empty($group)) {
unset($type[$gname]);
}
} else {
$group = (bool) $group;
}
}
unset($group);
if ($minimize && empty($type)) {
unset($data[$tname]);
}
} else {
$type = (bool) $type;
}
}
return $data;
}
/**
* Save assignments for the configuration.
*
* @param array $data
*/
public function save(array $data)
{
$data = $this->filter($data);
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Save layout into custom directory for the current theme.
$save_dir =
$locator->findResource("gantry-config://{$this->configuration}",
true, true);
$filename = "{$save_dir}/assignments.yaml";
$file = YamlFile::instance($filename);
$file->save($data);
$file->free();
}
/**
* Get list of all assignment types for assignments form.
*
* @return array
*/
public function getTypes()
{
$list = [];
foreach ($this->types() as $class => $type) {
$class = is_numeric($class) ? sprintf($this->className,
$this->platform, ucfirst($type)) : $class;
if (!class_exists($class)) {
throw new \RuntimeException("Assignment type
'{$type}' is missing");
}
/** @var AssignmentsInterface $instance */
$instance = new $class;
$list[$type] =
$instance->listRules($this->configuration);
unset($instance);
}
return $list;
}
/**
* Get selected assignment option.
*
* @return string
*/
public function getAssignment()
{
return 'default';
}
/**
* Set extra options for assignments.
*
* @param $value
*/
public function setAssignment($value)
{
}
/**
* Get extra options for assignments.
*
* @return array
*/
public function assignmentOptions()
{
return [];
}
protected function init()
{
if (!$this->filter) {
$this->filter = new AssignmentFilter;
$this->candidates = $this->loadAssignments();
$this->page = $this->getPage();
}
}
/**
* Return list of assignment types.
*
* @return array
*/
abstract public function types();
}
PKJ[�[�d�//
Assignments/AssignmentFilter.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Assignments;
/**
* Class AssignmentFilter
* @package Gantry\Assignments
*/
class AssignmentFilter
{
protected $method;
/**
* Return all matching candidates with their score. Candidates are
ordered by their scores.
*
* @param array $candidates In format of
candidates[name][section][rule].
* @param array $page In format of page[section][rule].
* @return array
*/
public function scores(array &$candidates, array &$page,
callable $function = null)
{
$matches = $this->matches($candidates, $page, $function);
$scores = [];
foreach ($matches as $type => $candidate) {
$scores[$type] = $this->getScore($candidate) +
(isset($candidate['language']) ? 0.01 : 0);
}
// Always return matches by score in alphabetical order.
ksort($scores, SORT_STRING);
arsort($scores, SORT_NUMERIC);
return $scores;
}
/**
* Returns all matching candidates with matching rules.
*
* @param array $candidates In format of
candidates[name][section][rule].
* @param array $page In format of page[section][rule].
* @return array
*/
public function matches(array $candidates, array &$page, callable
$function = null)
{
$matches = [];
foreach ($candidates as $type => $candidate) {
if (!is_array($candidate)) {
if ($candidate === true && $page) {
$matches[$type] = $page;
}
continue;
}
foreach ($candidate as $section => $list) {
if (!is_array($list)) {
if ($list === true && !empty($page[$section]))
{
$matches[$type][$section] = $page[$section];
}
continue;
}
foreach ($list as $name => $rules) {
if (!empty($page[$section][$name])) {
if (!is_array($rules)) {
$match = $rules === true ?
$page[$section][$name] : [];
} else {
$match =
\array_intersect_key($page[$section][$name], $rules);
}
if ($match) {
$matches[$type][$section][$name] = $match;
}
}
}
}
if (isset($matches[$type]) && $function &&
call_user_func($function, $candidate, $matches[$type], $page) === false) {
unset($matches[$type]);
}
}
return $matches;
}
/**
* Returns the calculated score for the assignment.
*
* @param array $matches
* @param string $method
* @return int
*/
public function getScore(array &$matches, $method =
'max')
{
$this->method = 'calc' . ucfirst($method);
if (!method_exists($this, $this->method)) {
$this->method = 'calcMax';
}
return $this->calcArray(0, $matches);
}
/**
* @param float $carry
* @param float|array $item
* @return float
* @internal
*/
protected function calcArray($carry, $item)
{
if (is_array($item)) {
return array_reduce($item, [$this, 'calcArray'],
$carry);
}
$method = $this->method;
return $this->{$method}($carry, (float) $item);
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcOr($carry, $item)
{
return (float) ($carry || $item);
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcMin($carry, $item)
{
return $carry ? min($carry, $item) : $item;
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcMax($carry, $item)
{
return max($carry, $item);
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcSum($carry, $item)
{
return $carry + $item;
}
/**
* @param float $carry
* @param float $item
* @return float
* @internal
*/
protected function calcMul($carry, $item)
{
return $carry ? $carry * $item : $item;
}
}
PKJ[�[3�U���$Assignments/AssignmentsInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Assignments;
interface AssignmentsInterface
{
/**
* Returns list of rules which apply to the current page.
*
* @return array
*/
public function getRules();
/**
* List all the rules available.
*
* @param string $configuration
* @return array
*/
public function listRules($configuration);
}
PKJ[�[�)!�99Collection/Collection.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Collection;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccess;
use RocketTheme\Toolbox\ArrayTraits\Countable;
use RocketTheme\Toolbox\ArrayTraits\Export;
class Collection implements CollectionInterface
{
use ArrayAccess, Countable, Export;
/**
* @var array
*/
protected $items = [];
public static function __set_state($variables)
{
$instance = new static();
$instance->items = $variables['items'];
return $instance;
}
/**
*
* Create a copy of this collection.
*
* @return static
*/
public function copy()
{
return clone $this;
}
/**
* @param $item
* @return $this
*/
public function add($item)
{
$this->items[] = $item;
return $this;
}
/**
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->items);
}
}
PKJ[�[�?�~~"Collection/CollectionInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Collection;
interface CollectionInterface extends \IteratorAggregate, \ArrayAccess,
\Countable
{
public function toArray();
/**
* @param $item
*/
public function add($item);
/**
* @return \ArrayIterator
*/
public function getIterator();
/**
* @param $offset
*
* @return bool
*/
public function offsetExists($offset);
/**
* @param $offset
* @param $value
*/
public function offsetSet($offset, $value);
/**
* @param $offset
*
* @return mixed
*/
public function offsetGet($offset);
/**
* @param $offset
*/
public function offsetUnset($offset);
/**
* @return int
*/
public function count();
}
PKK[�[�c��9$9$Config/BlueprintForm.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\Blueprints\BlueprintForm as BaseBlueprintForm;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* The Config class contains configuration information.
*
* @author RocketTheme
*/
class BlueprintForm extends BaseBlueprintForm
{
/**
* @var string
*/
protected $context = 'gantry-blueprints://';
/**
* @var BlueprintSchema
*/
protected $schema;
/**
* @param string $filename
* @param string $context
* @return BlueprintForm
*/
public static function instance($filename, $context = null)
{
/** @var BlueprintForm $instance */
$instance = new static($filename);
if ($context) {
$instance->setContext($context);
}
return $instance->load()->init();
}
/**
* Get nested structure containing default values defined in the
blueprints.
*
* Fields without default value are ignored in the list.
*
* @return array
*/
public function getDefaults()
{
return $this->schema()->getDefaults();
}
/**
* Merge two arrays by using blueprints.
*
* @param array $data1
* @param array $data2
* @param string $name Optional
* @param string $separator Optional
* @return array
*/
public function mergeData(array $data1, array $data2, $name = null,
$separator = '.')
{
return $this->schema()->mergeData($data1, $data2, $name,
$separator);
}
/**
* Return data fields that do not exist in blueprints.
*
* @param array $data
* @param string $prefix
* @return array
*/
public function extra(array $data, $prefix = '')
{
return $this->schema()->extra($data, $prefix);
}
/**
* Validate data against blueprints.
*
* @param array $data
* @throws \RuntimeException
*/
public function validate(array $data)
{
$this->schema()->validate($data);
}
/**
* Filter data by using blueprints.
*
* @param array $data
* @return array
*/
public function filter(array $data)
{
return $this->schema()->filter($data);
}
/**
* @return BlueprintSchema
*/
public function schema()
{
if (!isset($this->schema)) {
$this->schema = new BlueprintSchema;
$this->schema->embed('', $this->items);
$this->schema->init();
}
return $this->schema;
}
/**
* @param string $filename
* @return string
*/
protected function loadFile($filename)
{
$file = CompiledYamlFile::instance($filename);
$content = $file->content();
$file->free();
return $content;
}
/**
* @param string|array $path
* @param string $context
* @return array
*/
protected function getFiles($path, $context = null)
{
if (is_string($path) && !strpos($path, '://')) {
// Resolve filename.
if (isset($this->overrides[$path])) {
$path = $this->overrides[$path];
} else {
if ($context === null) {
$context = $this->context;
}
if ($context && $context[strlen($context)-1] !==
'/') {
$context .= '/';
}
$path = $context . $path;
if (!preg_match('/\.yaml$/', $path)) {
$path .= '.yaml';
}
}
}
if (is_string($path) && strpos($path, '://')) {
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
$files = $locator->findResources($path);
} else {
$files = (array) $path;
}
return $files;
}
/**
* @param array $field
* @param string $property
* @param array $call
*/
protected function dynamicData(array &$field, $property, array
&$call)
{
$params = $call['params'];
if (is_array($params)) {
$function = array_shift($params);
} else {
$function = $params;
$params = [];
}
list($o, $f) = preg_split('/::/', $function, 2);
if (!$f) {
if (function_exists($o)) {
$data = call_user_func_array($o, $params);
}
} else {
if (method_exists($o, $f)) {
$data = call_user_func_array(array($o, $f), $params);
}
}
// If function returns a value,
if (isset($data)) {
if (isset($field[$property]) &&
is_array($field[$property]) && is_array($data)) {
// Combine field and @data-field together.
$field[$property] += $data;
} else {
// Or create/replace field with @data-field.
$field[$property] = $data;
}
}
}
/**
* @param array $field
* @param string $property
* @param array $call
*/
protected function dynamicConfig(array &$field, $property, array
&$call)
{
$value = $call['params'];
$default = isset($field[$property]) ? $field[$property] : null;
$config = Gantry::instance()['config']->get($value,
$default);
if (!is_null($config)) {
$field[$property] = $config;
}
}
/**
* Get blueprints by using slash notation for nested arrays/objects.
*
* @param array $path
* @param string $separator
* @return array
*/
public function resolve(array $path, $separator = '/')
{
$fields = false;
$parts = [];
$current = $this['form/fields'];
$result = [null, null, null];
$prefix = '';
while (($field = current($path)) !== false) {
if (!$fields && isset($current['fields'])) {
if (!empty($current['array'])) {
$result = [$current, $parts, $path ?
implode($separator, $path) : null];
// Skip item offset.
$parts[] = array_shift($path);
}
$current = $current['fields'];
$prefix = '';
$fields = true;
} elseif (isset($current[$prefix . $field])) {
$parts[] = array_shift($path);
$current = $current[$prefix . $field];
$prefix = '';
$fields = false;
} elseif (isset($current['.' . $prefix . $field])) {
$parts[] = array_shift($path);
$current = $current['.' . $prefix . $field];
$prefix = '';
$fields = false;
} elseif ($field && $this->fieldExists($prefix .
$field, $current)) {
$parts[] = array_shift($path);
$prefix = "{$prefix}{$field}.";
$fields = false;
} else {
// Check if there's a container with the field.
$current = $this->resolveContainer($current, $prefix,
$field);
// No containers with the field found.
if (!$current) {
break;
}
$prefix = '';
$fields = false;
}
}
if (!$fields && !empty($current['array'])) {
$result = [$current, $parts, $path ? implode($separator, $path)
: null];
}
return $result;
}
protected function resolveContainer($current, $prefix, $fieldName)
{
foreach ($current as $field) {
$type = isset($field['type']) ?
$field['type'] : 'container._implicit';
$container = (0 === strpos($type, 'container.'));
if (!$container || !isset($field['fields'])) {
continue;
}
$current_fields = $field['fields'];
if (isset($current_fields[$prefix . $fieldName]) ||
isset($current_fields['.' . $prefix . $fieldName])
|| $this->fieldExists($prefix . $fieldName,
$current_fields)) {
return $current_fields;
}
$current_fields = $this->resolveContainer($current_fields,
$prefix, $fieldName);
if ($current_fields !== null) {
return $current_fields;
}
}
return null;
}
protected function fieldExists($prefix, $list)
{
foreach ($list as $field => $data) {
$pos = strpos($field, $prefix);
if ($pos === 0 || ($pos === 1 && $field[0] ===
'.')) {
return true;
}
}
return false;
}
}
PKK[�[ù���Config/BlueprintSchema.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\Blueprints\BlueprintSchema as BlueprintSchemaBase;
/**
* Blueprint schema handles the internal logic of blueprints.
*
* @author RocketTheme
* @license MIT
*/
class BlueprintSchema extends BlueprintSchemaBase
{
protected $configuration;
protected $ignoreFormKeys = [
'title' => true,
'help' => true,
'placeholder' => true,
'fields' => true
];
protected $types = [
'container.set' => [
'input@' => false
],
'container.tabs' => [
'input@' => false
],
'separator.note' => [
'input@' => false
],
'separator.separator' => [
'input@' => false
],
'key' => [
'input@' => false
],
'collection.list' => [
'array' => true
]
];
/**
* Constructor.
*
* @param array $serialized Serialized content if available.
*/
public function __construct($serialized = null)
{
parent::__construct($serialized);
$this->configuration = new
Config(isset($serialized['configuration']) ?
$serialized['configuration'] : []);
}
/**
* Convert object into an array.
*
* @return array
*/
public function getState()
{
return parent::getState() + ['configuration' =>
$this->configuration->toArray()];
}
/**
* Get nested structure containing default values defined in the
blueprints.
*
* Fields without default value are ignored in the list.
*
* @return array
*/
public function getDefaults()
{
return array_merge_recursive($this->configuration->toArray(),
$this->buildDefaults($this->nested));
}
/**
* Embed an array to the blueprint.
*
* @param $name
* @param array $value
* @param string $separator
* @param bool $merge Merge fields instead replacing them.
* @return $this
*/
public function embed($name, array $value, $separator = '.',
$merge = false)
{
parent::embed($name, $value, $separator, $merge);
if (isset($value['configuration'])) {
$this->configuration->set($name,
$value['configuration'], $separator);
}
return $this;
}
/**
* Validate data against blueprints.
*
* @param array $data
* @throws \RuntimeException
*/
public function validate(array $data)
{
try {
$messages = $this->validateArray($data, $this->nested);
} catch (\RuntimeException $e) {
throw (new ValidationException($e->getMessage(),
$e->getCode(), $e))->setMessages();
}
if (!empty($messages)) {
throw (new ValidationException())->setMessages($messages);
}
}
/**
* Filter data by using blueprints.
*
* @param array $data
* @return array
*/
public function filter(array $data)
{
return $this->filterArray($data, $this->nested);
}
/**
* @param array $data
* @param array $rules
* @returns array
* @throws \RuntimeException
* @internal
*/
protected function validateArray(array $data, array $rules)
{
$messages = $this->checkRequired($data, $rules);
foreach ($data as $key => $field) {
$val = isset($rules[$key]) ? $rules[$key] :
(isset($rules['*']) ? $rules['*'] : null);
$rule = is_string($val) ? $this->items[$val] : null;
if ($rule) {
// Item has been defined in blueprints.
$messages += Validation::validate($field, $rule);
} elseif (is_array($field) && is_array($val)) {
// Array has been defined in blueprints.
$messages += $this->validateArray($field, $val);
} elseif (isset($rules['validation']) &&
$rules['validation'] == 'strict') {
// Undefined/extra item.
throw new \RuntimeException(sprintf('%s is not defined
in blueprints', $key));
}
}
return $messages;
}
/**
* @param array $data
* @param array $rules
* @return array
* @internal
*/
protected function filterArray(array $data, array $rules)
{
$results = array();
foreach ($data as $key => $field) {
$val = isset($rules[$key]) ? $rules[$key] :
(isset($rules['*']) ? $rules['*'] : null);
$rule = is_string($val) ? $this->items[$val] : null;
if ($rule) {
// Item has been defined in blueprints.
$field = Validation::filter($field, $rule);
} elseif (is_array($field) && is_array($val)) {
// Array has been defined in blueprints.
$field = $this->filterArray($field, $val);
} elseif (isset($rules['validation']) &&
$rules['validation'] == 'strict') {
$field = null;
}
if (isset($field) && (!is_array($field) ||
!empty($field))) {
$results[$key] = $field;
}
}
return $results;
}
/**
* @param array $data
* @param array $fields
* @return array
*/
protected function checkRequired(array $data, array $fields)
{
$messages = [];
foreach ($fields as $name => $field) {
if (!is_string($field)) {
continue;
}
$field = $this->items[$field];
if (isset($field['validate']['required'])
&&
$field['validate']['required'] === true
&& !isset($data[$name])) {
$value = isset($field['label']) ?
$field['label'] : $field['name'];
// TODO: translate
$message = sprintf("Please fill up required field
'%s'.", $value);
$messages[$field['name']][] = $message;
}
}
return $messages;
}
/**
* @param array $field
* @param string $property
* @param array $call
*/
protected function dynamicConfig(array &$field, $property, array
&$call)
{
$value = $call['params'];
$default = isset($field[$property]) ? $field[$property] : null;
$config = Gantry::instance()['config']->get($value,
$default);
if (!is_null($config)) {
$field[$property] = $config;
}
}
}
PKK[�[�-��Config/CompiledBase.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\File\PhpFile;
/**
* The Compiled base class.
*/
abstract class CompiledBase
{
/**
* @var int Version number for the compiled file.
*/
public $version = 1;
/**
* @var string Filename (base name) of the compiled configuration.
*/
public $name;
/**
* @var string|bool Configuration checksum.
*/
public $checksum;
/**
* @var string Cache folder to be used.
*/
protected $cacheFolder;
/**
* @var array List of files to load.
*/
protected $files;
/**
* @var string
*/
protected $path;
/**
* @var mixed Configuration object.
*/
protected $object;
/**
* @param string $cacheFolder Cache folder to be used.
* @param array $files List of files as returned from
ConfigFileFinder class.
* @param string $path Base path for the file list.
* @throws \BadMethodCallException
*/
public function __construct($cacheFolder, array $files, $path =
GANTRY5_ROOT)
{
if (!$cacheFolder) {
throw new \BadMethodCallException('Cache folder not
defined.');
}
$this->cacheFolder = $cacheFolder;
$this->files = $files;
$this->path = $path ? rtrim($path, '\\/') .
'/' : '';
}
/**
* Get filename for the compiled PHP file.
*
* @param string $name
* @return $this
*/
public function name($name = null)
{
if (!$this->name) {
$this->name = $name ?:
md5(json_encode(array_keys($this->files)));
}
return $this;
}
/**
* Function gets called when cached configuration is saved.
*/
public function modified() {}
/**
* Load the configuration.
*
* @return mixed
*/
public function load()
{
if ($this->object) {
return $this->object;
}
$filename = $this->createFilename();
if (!$this->loadCompiledFile($filename) &&
$this->loadFiles()) {
$this->saveCompiledFile($filename);
}
return $this->object;
}
/**
* Returns checksum from the configuration files.
*
* You can set $this->checksum = false to disable this check.
*
* @return bool|string
*/
public function checksum()
{
if (!isset($this->checksum)) {
$this->checksum = md5(json_encode($this->files) .
$this->version);
}
return $this->checksum;
}
protected function createFilename()
{
return
"{$this->cacheFolder}/{$this->name()->name}.php";
}
/**
* Create configuration object.
*
* @param array $data
*/
abstract protected function createObject(array $data = []);
/**
* Finalize configuration object.
*/
abstract protected function finalizeObject();
/**
* Load single configuration file and append it to the correct
position.
*
* @param string $name Name of the position.
* @param string $filename File to be loaded.
*/
abstract protected function loadFile($name, $filename);
/**
* Load and join all configuration files.
*
* @return bool
* @internal
*/
protected function loadFiles()
{
$this->createObject();
$list = array_reverse($this->files);
foreach ($list as $files) {
foreach ($files as $name => $item) {
$this->loadFile($name, $this->path .
$item['file']);
}
}
$this->finalizeObject();
return true;
}
/**
* Load compiled file.
*
* @param string $filename
* @return bool
* @internal
*/
protected function loadCompiledFile($filename)
{
$gantry = Gantry::instance();
/** @var Config $global */
$global = $gantry['global'];
if (!$global->get('compile_yaml', 1)) {
return false;
}
if (!file_exists($filename)) {
return false;
}
$cache = include $filename;
if (
!is_array($cache)
|| !isset($cache['checksum'])
|| !isset($cache['data'])
|| !isset($cache['@class'])
|| $cache['@class'] != get_class($this)
) {
return false;
}
// Load real file if cache isn't up to date (or is invalid).
if ($cache['checksum'] !== $this->checksum()) {
return false;
}
$this->createObject($cache['data']);
$this->finalizeObject();
return true;
}
/**
* Save compiled file.
*
* @param string $filename
* @throws \RuntimeException
* @internal
*/
protected function saveCompiledFile($filename)
{
$gantry = Gantry::instance();
/** @var Config $global */
$global = $gantry['global'];
if (!$global->get('compile_yaml', 1)) {
return;
}
$file = PhpFile::instance($filename);
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will check this in a
bit.
}
if ($file->locked() === false) {
// File was already locked by another process.
return;
}
$cache = [
'@class' => get_class($this),
'timestamp' => time(),
'checksum' => $this->checksum(),
'files' => $this->files,
'data' => $this->getState()
];
$file->save($cache);
$file->unlock();
$file->free();
$this->modified();
}
protected function getState()
{
return $this->object->toArray();
}
}
PKK[�[�ԂDDConfig/CompiledBlueprints.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
/**
* The Compiled Blueprints class.
*/
class CompiledBlueprints extends CompiledBase
{
/**
* @var int Version number for the compiled file.
*/
public $version = 3;
/**
* @var BlueprintSchema Blueprints object.
*/
protected $object;
/**
* Create configuration object.
*
* @param array $data
*/
protected function createObject(array $data = [])
{
$this->object = new BlueprintSchema($data);
}
/**
* Finalize configuration object.
*/
protected function finalizeObject()
{
}
/**
* Load single configuration file and append it to the correct
position.
*
* @param string $name Name of the position.
* @param array $files Files to be loaded.
*/
protected function loadFile($name, $files)
{
// Load blueprint file.
$blueprint = new BlueprintForm($files);
$this->object->embed($name,
$blueprint->load()->toArray(), '/', true);
}
/**
* Load and join all configuration files.
*
* @return bool
* @internal
*/
protected function loadFiles()
{
$this->createObject();
// Convert file list into parent list.
$list = [];
foreach ($this->files as $files) {
foreach ($files as $name => $item) {
$list[$name][] = $this->path . $item['file'];
}
}
// Load files.
foreach ($list as $name => $files) {
$this->loadFile($name, $files);
}
$this->finalizeObject();
return true;
}
protected function getState()
{
return $this->object->getState();
}
}
PKK[�[��ͭ
Config/CompiledConfig.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Component\File\CompiledYamlFile;
/**
* The Compiled Configuration class.
*/
class CompiledConfig extends CompiledBase
{
/**
* @var int Version number for the compiled file.
*/
public $version = 2;
/**
* @var Config Configuration object.
*/
protected $object;
/**
* @var callable Blueprints loader.
*/
protected $callable;
/**
* @var bool
*/
protected $withDefaults;
/**
* Get filename for the compiled PHP file.
*
* @param string $name
* @return $this
*/
public function name($name = null)
{
if (!$this->name) {
$this->name = $name ?:
md5(json_encode(array_keys($this->files)) . (int)
$this->withDefaults);
}
return $this;
}
/**
* Set blueprints for the configuration.
*
* @param callable $blueprints
* @return $this
*/
public function setBlueprints(callable $blueprints)
{
$this->callable = $blueprints;
return $this;
}
/**
* @param bool $withDefaults
* @return mixed
*/
public function load($withDefaults = false)
{
$this->withDefaults = $withDefaults;
return parent::load();
}
/**
* Create configuration object.
*
* @param array $data
*/
protected function createObject(array $data = [])
{
if ($this->withDefaults && empty($data) &&
is_callable($this->callable)) {
$blueprints = $this->callable;
$data = $blueprints()->getDefaults();
}
$this->object = new Config($data, $this->callable);
}
/**
* Finalize configuration object.
*/
protected function finalizeObject()
{
}
/**
* Load single configuration file and append it to the correct
position.
*
* @param string $name Name of the position.
* @param string $filename File to be loaded.
*/
protected function loadFile($name, $filename)
{
$file = CompiledYamlFile::instance($filename);
$this->object->join($name, $file->content(),
'/');
$file->free();
}
}
PKK[�[Ѱ�PddConfig/Config.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
use RocketTheme\Toolbox\ArrayTraits\Iterator;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
/**
* The Config class contains configuration information.
*
* @author RocketTheme
*/
class Config implements \ArrayAccess, \Countable, \Iterator,
ExportInterface
{
use NestedArrayAccessWithGetters, Iterator, Export;
/**
* @var array
*/
protected $items;
/**
* @var BlueprintSchema|BlueprintForm|callable
*/
protected $blueprint;
/**
* Constructor to initialize array.
*
* @param array $items Initial items inside the iterator.
* @param callable $blueprints Function to load Blueprints for the
configuration.
*/
public function __construct(array $items, callable $blueprint = null)
{
$this->items = $items;
$this->blueprint = $blueprint;
}
/**
* Join nested values together by using blueprints.
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $value Value to be joined.
* @param string $separator Separator, defaults to '.'
* @return $this
* @throws \RuntimeException
*/
public function join($name, $value, $separator = '.')
{
$old = $this->get($name, null, $separator);
if ($old !== null) {
if (!is_array($old)) {
throw new \RuntimeException("Value is not array in
{$name}: " . print_r($old, true));
}
if (is_object($value)) {
$value = (array) $value;
} elseif (!is_array($value)) {
throw new \RuntimeException("Value is not array in
{$name}: " . print_r($value, true));
}
$value = $this->blueprint()->mergeData($old, $value,
$name, $separator);
}
$this->set($name, $value, $separator);
return $this;
}
/**
* Get nested structure containing default values defined in the
blueprints.
*
* Fields without default value are ignored in the list.
* @return array
*/
public function getDefaults()
{
return $this->blueprint()->getDefaults();
}
/**
* Set default values by using blueprints.
*
* @param string $name Dot separated path to the requested
value.
* @param mixed $value Value to be joined.
* @param string $separator Separator, defaults to '.'
* @return $this
*/
public function joinDefaults($name, $value, $separator = '.')
{
if (is_object($value)) {
$value = (array) $value;
}
$old = $this->get($name, null, $separator);
if ($old !== null) {
$value = $this->blueprint()->mergeData($value, $old,
$name, $separator);
}
$this->set($name, $value, $separator);
return $this;
}
/**
* Get value from the configuration and join it with given data.
*
* @param string $name Dot separated path to the requested
value.
* @param array $value Value to be joined.
* @param string $separator Separator, defaults to '.'
* @return array
* @throws \RuntimeException
*/
public function getJoined($name, $value, $separator = '.')
{
if (is_object($value)) {
$value = (array) $value;
} elseif (!is_array($value)) {
throw new \RuntimeException("Value is not array in
'{$name}': " . print_r($value, true));
}
$old = $this->get($name, null, $separator);
if ($old === null) {
// No value set; no need to join data.
return $value;
}
if (!is_array($old)) {
throw new \RuntimeException("Value is not array in
'{$name}': " . print_r($value, true));
}
// Return joined data.
return $this->blueprint()->mergeData($old, $value, $name,
$separator);
}
/**
* Merge two configurations together.
*
* @param array $data
* @return $this
*/
public function merge(array $data)
{
$this->items =
$this->blueprint()->mergeData($this->items, $data);
return $this;
}
/**
* Set default values to the configuration if variables were not set.
*
* @param array $data
* @return $this
*/
public function setDefaults(array $data)
{
$this->items = $this->blueprint()->mergeData($data,
$this->items);
return $this;
}
/**
* Make a flat list from the configuration.
*
* @param string $name Dot separated path to the requested value.
* @param string $separator Separator, defaults to '.'
* @param string $prefix Name prefix.
* @return array
*/
public function flatten($name = null, $separator = '.',
$prefix = '')
{
$element = $name ? $this->offsetGet($name) : $this->items;
if (!is_array($element)) {
return [$name, $element];
}
if (strlen($separator) == 2 && in_array($separator,
['][', ')(', '}{'])) {
$separator = [$separator[1], $separator[0]];
}
return $this->flattenNested('', $element, $separator,
$prefix);
}
/**
* @param string $name
* @param array $element
* @param string $separator
* @param string $prefix
* @return array
* @internal
*/
protected function flattenNested($name, &$element, $separator,
$prefix)
{
$list = [];
foreach ($element as $key => $value) {
$new = $name ? $name : $prefix;
if (is_array($separator)) {
$new .= $separator[0] . $key . $separator[1];
} else {
$new .= ($new ? $separator : '') . $key;
}
if (!is_array($value) || empty($value)) {
$list[$new] = $value;
} else {
$list += $this->flattenNested($new, $value, $separator,
$prefix);
}
}
return $list;
}
/**
* Return blueprint.
*
* @return BlueprintSchema|BlueprintForm
* @since 5.4.7
*/
public function blueprint()
{
if (!$this->blueprint){
$this->blueprint = new BlueprintSchema;
} elseif (is_callable($this->blueprint)) {
// Lazy load blueprints.
$blueprint = $this->blueprint;
$this->blueprint = $blueprint();
}
return $this->blueprint;
}
/**
* Return blueprints.
*
* @return BlueprintSchema
* @deprecated 5.4.7
*/
public function blueprints()
{
return $this->blueprint();
}
/**
* Count items in nested array.
*
* @param string $path
* @param string $separator
* @return int
*/
public function count($path = null, $separator = '.')
{
$items = $path ? $this->get($path, null, $separator) :
$this->items;
return is_array($items) ? count($items) : 0;
}
}
PKK[�[ҽ`\!\!Config/ConfigFileFinder.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Gantry\Component\Filesystem\Folder;
/**
* The Configuration & Blueprints Finder class.
*/
class ConfigFileFinder
{
protected $base = '';
/**
* @param string $base
* @return $this
*/
public function setBase($base)
{
$this->base = $base ? "{$base}/" : '';
return $this;
}
/**
* Return all locations for all the files with a timestamp.
*
* @param array $paths List of folders to look from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
*/
public function locateFiles(array $paths, $pattern =
'|\.yaml$|', $levels = -1)
{
$list = [];
foreach ($paths as $folder) {
$list += $this->detectRecursive($folder, $pattern, $levels);
}
return $list;
}
/**
* Return all locations for all the files with a timestamp.
*
* @param array $paths List of folders to look from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
*/
public function getFiles(array $paths, $pattern =
'|\.yaml$|', $levels = -1)
{
$list = [];
foreach ($paths as $folder) {
$path = trim(Folder::getRelativePath($folder), '/');
$files = $this->detectRecursive($folder, $pattern, $levels);
$list += $files[trim($path, '/')];
}
return $list;
}
/**
* Return all paths for all the files with a timestamp.
*
* @param array $paths List of folders to look from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
*/
public function listFiles(array $paths, $pattern =
'|\.yaml$|', $levels = -1)
{
$list = [];
foreach ($paths as $folder) {
$list = array_merge_recursive($list,
$this->detectAll($folder, $pattern, $levels));
}
return $list;
}
/**
* Find filename from a list of folders.
*
* Note: Only finds the last override.
*
* @param string $filename
* @param array $folders
* @return array
*/
public function locateFileInFolder($filename, array $folders)
{
$list = [];
foreach ($folders as $folder) {
$list += $this->detectInFolder($folder, $filename);
}
return $list;
}
/**
* Find filename from a list of folders.
*
* @param array $folders
* @param string $filename
* @return array
*/
public function locateInFolders(array $folders, $filename = null)
{
$list = [];
foreach ($folders as $folder) {
$path = trim(Folder::getRelativePath($folder), '/');
$list[$path] = $this->detectInFolder($folder, $filename);
}
return $list;
}
/**
* Return all existing locations for a single file with a timestamp.
*
* @param array $paths Filesystem paths to look up from.
* @param string $name Configuration file to be located.
* @param string $ext File extension (optional, defaults to
.yaml).
* @return array
*/
public function locateFile(array $paths, $name, $ext =
'.yaml')
{
$filename = preg_replace('|[.\/]+|', '/',
$name) . $ext;
$list = [];
foreach ($paths as $folder) {
$path = trim(Folder::getRelativePath($folder), '/');
if (is_file("{$folder}/{$filename}")) {
$modified = filemtime("{$folder}/{$filename}");
} else {
$modified = 0;
}
$basename = $this->base . $name;
$list[$path] = [$basename => ['file' =>
"{$path}/{$filename}", 'modified' => $modified]];
}
return $list;
}
/**
* Detects all directories with a configuration file and returns them
with last modification time.
*
* @param string $folder Location to look up from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
* @internal
*/
protected function detectRecursive($folder, $pattern, $levels)
{
$path = trim(Folder::getRelativePath($folder), '/');
if (is_dir($folder)) {
// Find all system and user configuration files.
$options = [
'levels' => $levels,
'compare' => 'Filename',
'pattern' => $pattern,
'filters' => [
'pre-key' => $this->base,
'key' => $pattern,
'value' => function
(\RecursiveDirectoryIterator $file) use ($path) {
return ['file' =>
"{$path}/{$file->getSubPathname()}", 'modified'
=> $file->getMTime()];
}
],
'key' => 'SubPathname'
];
$list = Folder::all($folder, $options);
ksort($list);
} else {
$list = [];
}
return [$path => $list];
}
/**
* Detects all directories with the lookup file and returns them with
last modification time.
*
* @param string $folder Location to look up from.
* @param string $lookup Filename to be located (defaults to directory
name).
* @return array
* @internal
*/
protected function detectInFolder($folder, $lookup = null)
{
$folder = rtrim($folder, '/');
$path = trim(Folder::getRelativePath($folder), '/');
$base = $path === $folder ? '' : ($path ? substr($folder,
0, -strlen($path)) : $folder . '/');
$list = [];
if (is_dir($folder)) {
$iterator = new \DirectoryIterator($folder);
/** @var \DirectoryIterator $directory */
foreach ($iterator as $directory) {
if (!$directory->isDir() || $directory->isDot()) {
continue;
}
$name = $directory->getBasename();
$find = ($lookup ?: $name) . '.yaml';
$filename = "{$path}/{$name}/{$find}";
if (file_exists($base . $filename)) {
$basename = $this->base . $name;
$list[$basename] = ['file' => $filename,
'modified' => filemtime($base . $filename)];
}
}
}
return $list;
}
/**
* Detects all plugins with a configuration file and returns them with
last modification time.
*
* @param string $folder Location to look up from.
* @param string $pattern Pattern to match the file. Pattern will
also be removed from the key.
* @param int $levels Maximum number of recursive directories.
* @return array
* @internal
*/
protected function detectAll($folder, $pattern, $levels)
{
$path = trim(Folder::getRelativePath($folder), '/');
if (is_dir($folder)) {
// Find all system and user configuration files.
$options = [
'levels' => $levels,
'compare' => 'Filename',
'pattern' => $pattern,
'filters' => [
'pre-key' => $this->base,
'key' => $pattern,
'value' => function
(\RecursiveDirectoryIterator $file) use ($path) {
return
["{$path}/{$file->getSubPathname()}" =>
$file->getMTime()];
}
],
'key' => 'SubPathname'
];
$list = Folder::all($folder, $options);
ksort($list);
} else {
$list = [];
}
return $list;
}
}
PKK[�[��VVConfig/Validation.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Yaml;
/**
* Data validation.
*
* @author RocketTheme
* @license MIT
*/
class Validation
{
/**
* Validate value against a blueprint field definition.
*
* @param $value
* @param array $field
* @return array
*/
public static function validate($value, array $field)
{
$messages = [];
$validate = isset($field['validate']) ? (array)
$field['validate'] : [];
// If value isn't required, we will stop validation if empty
value is given.
if (empty($validate['required']) && ($value ===
null || $value === '')) {
return $messages;
}
if (!isset($field['type'])) {
$field['type'] = 'input.text';
}
// Special case for files, value is never empty and errors with
code 4 instead.
if (empty($validate['required']) &&
$field['type'] === 'input.file' &&
isset($value['error'])
&& ($value['error'] ===
UPLOAD_ERR_NO_FILE || \in_array(UPLOAD_ERR_NO_FILE,
$value['error'], true))) {
return $messages;
}
// Validate type with fallback type text.
$type = (string)
isset($field['validate']['type']) ?
$field['validate']['type'] : $field['type'];
$method = 'type_'.strtr($type, '-.',
'__');
if (!method_exists(__CLASS__, $method)) {
$method = 'type_Input_Text';
}
$name = ucfirst(isset($field['label']) ?
$field['label'] : $field['name']);
// TODO: translate
$message = (string)
isset($field['validate']['message'])
? sprintf($field['validate']['message'])
: sprintf('Invalid input in field: ') . '
"' . $name . '"';
$success = self::$method($value, $validate, $field);
if (!$success) {
$messages[$field['name']][] = $message;
}
// Check individual rules.
foreach ($validate as $rule => $params) {
$method = 'validate_' . ucfirst(strtr($rule,
'-.', '__'));
if (method_exists(__CLASS__, $method)) {
$success = self::$method($value, $params);
if (!$success) {
$messages[$field['name']][] = $message;
}
}
}
return $messages;
}
/**
* Filter value against a blueprint field definition.
*
* @param mixed $value
* @param array $field
* @return mixed Filtered value.
*/
public static function filter($value, array $field)
{
$validate = isset($field['validate']) ? (array)
$field['validate'] : [];
// If value isn't required, we will return null if empty value
is given.
if (($value === null || $value === '') &&
empty($validate['required'])) {
return null;
}
if (!isset($field['type'])) {
$field['type'] = 'input.text';
}
// Special case for files, value is never empty and errors with
code 4 instead.
if (empty($validate['required']) &&
$field['type'] === 'input.file' &&
isset($value['error'])
&& ($value['error'] === UPLOAD_ERR_NO_FILE ||
\in_array(UPLOAD_ERR_NO_FILE, $value['error'], true))) {
return null;
}
// Validate type with fallback type text.
$type = (string)
isset($field['validate']['type']) ?
$field['validate']['type'] : $field['type'];
$method = 'filter_' . ucfirst(str_replace('-',
'_', $type));
if (!method_exists(__CLASS__, $method)) {
$method = 'filter_Input_Text';
}
return self::$method($value, $validate, $field);
}
/**
* HTML5 input: text
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Text($value, array $params, array
$field)
{
if (!\is_string($value) && !is_numeric($value)) {
return false;
}
$value = (string)$value;
if (isset($params['min']) && \strlen($value) <
$params['min']) {
return false;
}
if (isset($params['max']) && \strlen($value) >
$params['max']) {
return false;
}
$min = isset($params['min']) ? $params['min'] :
0;
if (isset($params['step']) && (strlen($value) -
$min) % $params['step'] === 0) {
return false;
}
if ((!isset($params['multiline']) ||
!$params['multiline']) && preg_match('/\R/um',
$value)) {
return false;
}
return true;
}
protected static function filter_Input_Text($value, array $params,
array $field)
{
return (string) $value;
}
protected static function filter_Input_CommaList($value, array $params,
array $field)
{
return \is_array($value) ? $value :
preg_split('/\s*,\s*/', $value, -1, PREG_SPLIT_NO_EMPTY);
}
protected static function type_Input_CommaList($value, array $params,
array $field)
{
return \is_array($value) ? true : self::type_Input_Text($value,
$params, $field);
}
/**
* HTML5 input: textarea
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Textarea_Textarea($value, array $params,
array $field)
{
if (!isset($params['multiline'])) {
$params['multiline'] = true;
}
return self::type_Input_Text($value, $params, $field);
}
/**
* HTML5 input: password
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Password($value, array $params, array
$field)
{
return self::type_Input_Text($value, $params, $field);
}
/**
* HTML5 input: hidden
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Hidden($value, array $params, array
$field)
{
return self::type_Input_Text($value, $params, $field);
}
/**
* Custom input: checkbox list
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Checkboxes_Checkboxes($value, array
$params, array $field)
{
// Set multiple: true so checkboxes can easily use min/max counts
to control number of options required
$field['multiple'] = true;
return self::typeArray((array) $value, $params, $field);
}
protected static function filter_Checkboxes_Checkboxes($value, array
$params, array $field)
{
return self::filterArray($value, $params, $field);
}
/**
* HTML5 input: checkbox
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Checkbox($value, array $params, array
$field)
{
$value = (string) $value;
if (!isset($field['value'])) {
$field['value'] = 1;
}
if ($value && $value != $field['value']) {
return false;
}
return true;
}
/**
* HTML5 input: radio
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Radio($value, array $params, array
$field)
{
return self::typeArray((array) $value, $params, $field);
}
/**
* Custom input: toggle
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Toggle_Toggle($value, array $params, array
$field)
{
return self::typeArray((array) $value, $params, $field);
}
/**
* Custom input: file
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_File($value, array $params, array
$field)
{
return self::typeArray((array) $value, $params, $field);
}
protected static function filter_Input_File($value, array $params,
array $field)
{
if (isset($field['multiple']) &&
$field['multiple'] === true) {
return (array) $value;
}
if (\is_array($value)) {
return reset($value);
}
return $value;
}
/**
* HTML5 input: select
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Select_Select($value, array $params, array
$field)
{
return self::typeArray((array) $value, $params, $field);
}
/**
* HTML5 input: number
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Number($value, array $params, array
$field)
{
if (!is_numeric($value)) {
return false;
}
if (isset($params['min']) && $value <
$params['min']) {
return false;
}
if (isset($params['max']) && $value >
$params['max']) {
return false;
}
$min = isset($params['min']) ? $params['min'] :
0;
return !(isset($params['step']) && fmod($value -
$min, $params['step']) === 0);
}
protected static function filter_Input_Number($value, array $params,
array $field)
{
return (string)(int)$value !== (string)(float)$value ? (float)
$value : (int) $value;
}
protected static function filter_Input_DateTime($value, array $params,
array $field)
{
$converted = new \DateTime($value);
return $converted->format('Y-m-d H:i:s');
}
/**
* HTML5 input: range
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Range($value, array $params, array
$field)
{
return self::type_Input_Number($value, $params, $field);
}
protected static function filter_Input_Range($value, array $params,
array $field)
{
return self::filter_Input_Number($value, $params, $field);
}
/**
* HTML5 input: color
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Color($value, array $params, array
$field)
{
return preg_match('/^\#[0-9a-fA-F]{3}[0-9a-fA-F]{3}?$/u',
$value);
}
/**
* HTML5 input: email
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Email($value, array $params, array
$field)
{
return self::type_Input_Text($value, $params, $field) &&
filter_var($value, FILTER_VALIDATE_EMAIL);
}
/**
* HTML5 input: url
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Url($value, array $params, array
$field)
{
return self::type_Input_Text($value, $params, $field) &&
filter_var($value, FILTER_VALIDATE_URL);
}
/**
* HTML5 input: datetime
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Datetime($value, array $params, array
$field)
{
if ($value instanceof \DateTime) {
return true;
}
if (!\is_string($value)) {
return false;
}
if (!isset($params['format'])) {
return false !== strtotime($value);
}
$dateFromFormat =
\DateTime::createFromFormat($params['format'], $value);
return $dateFromFormat && $value ===
date($params['format'], $dateFromFormat->getTimestamp());
}
/**
* HTML5 input: datetime-local
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_DatetimeLocal($value, array $params,
array $field)
{
return self::type_Input_Datetime($value, $params, $field);
}
/**
* HTML5 input: date
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Date($value, array $params, array
$field)
{
if (!isset($params['format'])) {
$params['format'] = 'Y-m-d';
}
return self::type_Input_Datetime($value, $params, $field);
}
/**
* HTML5 input: time
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Time($value, array $params, array
$field)
{
if (!isset($params['format'])) {
$params['format'] = 'H:i';
}
return self::type_Input_Datetime($value, $params, $field);
}
/**
* HTML5 input: month
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Month($value, array $params, array
$field)
{
if (!isset($params['format'])) {
$params['format'] = 'Y-m';
}
return self::type_Input_Datetime($value, $params, $field);
}
/**
* HTML5 input: week
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Input_Week($value, array $params, array
$field)
{
if (!isset($params['format']) &&
!preg_match('/^\d{4}-W\d{2}$/u', $value)) {
return false;
}
return self::type_Input_Datetime($value, $params, $field);
}
/**
* Custom input: array
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function typeArray($value, array $params, array $field)
{
if (!\is_array($value)) {
return false;
}
if (isset($field['multiple'])) {
if (isset($params['min']) && \count($value)
< $params['min']) {
return false;
}
if (isset($params['max']) && \count($value)
> $params['max']) {
return false;
}
$min = isset($params['min']) ?
$params['min'] : 0;
if (isset($params['step']) && (\count($value)
- $min) % $params['step'] === 0) {
return false;
}
}
$options = isset($field['options']) ?
array_keys($field['options']) : [];
$values = isset($field['use']) &&
$field['use'] === 'keys' ? array_keys($value) : $value;
return !($options && array_diff($values, $options));
}
protected static function filterArray($value, $params, $field)
{
$values = (array) $value;
$options = isset($field['options']) ?
array_keys($field['options']) : [];
$multi = isset($field['multiple']) ?
$field['multiple'] : false;
if (\count($values) === 1 && isset($values[0]) &&
$values[0] === '') {
return null;
}
if ($options) {
$useKey = isset($field['use']) &&
$field['use'] === 'keys';
foreach ($values as $key => $val) {
$values[$key] = $useKey ? (bool) $val : $val;
}
}
if ($multi) {
foreach ($values as $key => $val) {
if (\is_array($val)) {
$val = implode(',', $val);
}
$values[$key] = array_map('trim',
explode(',', $val));
}
}
return $values;
}
public static function type_Input_Yaml($value, $params)
{
try {
Yaml::parse($value);
return true;
} catch (ParseException $e) {
return false;
}
}
public static function filter_Input_Yaml($value, $params)
{
try {
return (array) Yaml::parse($value);
} catch (ParseException $e) {
return null;
}
}
/**
* Custom input: ignore (will not validate)
*
* @param mixed $value Value to be validated.
* @param array $params Validation parameters.
* @param array $field Blueprint for the field.
* @return bool True if validation succeeded.
*/
public static function type_Novalidate($value, array $params, array
$field)
{
return true;
}
public static function filter_Novalidate($value, array $params, array
$field)
{
return $value;
}
// HTML5 attributes (min, max and range are handled inside the types)
public static function validate_Required($value, $params)
{
if (is_scalar($value)) {
return (bool) $params !== true || $value !== '';
}
return (bool) $params !== true || !empty($value);
}
public static function validate_Pattern($value, $params)
{
return (bool) preg_match("`^{$params}$`u", $value);
}
// Internal types
public static function validate_Alpha($value, $params)
{
return ctype_alpha($value);
}
public static function validate_Alnum($value, $params)
{
return ctype_alnum($value);
}
public static function type_Bool($value, $params)
{
return \is_bool($value) || $value == 1 || $value == 0;
}
public static function validate_Bool($value, $params)
{
return \is_bool($value) || $value == 1 || $value == 0;
}
protected static function filter_Bool($value, $params)
{
return (bool) $value;
}
public static function validate_Digit($value, $params)
{
return ctype_digit($value);
}
public static function validate_Float($value, $params)
{
return \is_float(filter_var($value, FILTER_VALIDATE_FLOAT));
}
protected static function filter_Float($value, $params)
{
return (float) $value;
}
public static function validate_Hex($value, $params)
{
return ctype_xdigit($value);
}
public static function validate_Int($value, $params)
{
return is_numeric($value) && (int) $value == $value;
}
protected static function filter_Int($value, $params)
{
return (int) $value;
}
public static function validate_Array($value, $params)
{
return \is_array($value)
|| ($value instanceof \ArrayAccess
&& $value instanceof \Traversable
&& $value instanceof \Countable);
}
public static function validate_Json($value, $params)
{
return (bool) (@json_decode($value));
}
}
PKK[�[��"Config/ValidationException.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Config;
class ValidationException extends \RuntimeException
{
protected $messages = [];
public function setMessages(array $messages = []) {
$this->messages = $messages;
// TODO: add translation.
$this->message = sprintf('Form validation failed:') .
' ' . $this->message;
foreach ($messages as $variable => &$list) {
$list = array_unique($list);
foreach ($list as $message) {
$this->message .= "<br/>$message";
}
}
return $this;
}
public function getMessages()
{
return $this->messages;
}
}
PKM[�[#NJ���Content/Block/ContentBlock.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Block;
/**
* Class to create nested blocks of content.
*
* $innerBlock = ContentBlock::create();
* $innerBlock->setContent('my inner content');
* $outerBlock = ContentBlock::create();
* $outerBlock->setContent(sprintf('Inside my outer block I have
%s.', $innerBlock->getToken()));
* $outerBlock->addBlock($innerBlock);
* echo $outerBlock;
*
* @package Gantry\Component\Content\Block
* @since 5.4.3
*/
class ContentBlock implements ContentBlockInterface
{
protected $version = 1;
protected $id;
protected $tokenTemplate = '@@BLOCK-%s@@';
protected $content = '';
protected $blocks = [];
/**
* @param string $id
* @return static
* @since 5.4.3
*/
public static function create($id = null)
{
return new static($id);
}
/**
* @param array $serialized
* @return ContentBlockInterface
* @since 5.4.3
*/
public static function fromArray(array $serialized)
{
try {
$type = isset($serialized['_type']) ?
$serialized['_type'] : null;
$id = isset($serialized['id']) ?
$serialized['id'] : null;
if (!$type || !$id || !is_a($type,
'Gantry\Component\Content\Block\ContentBlockInterface', true)) {
throw new \RuntimeException('Bad data');
}
/** @var ContentBlockInterface $instance */
$instance = new $type($id);
$instance->build($serialized);
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('Cannot unserialize
Block: %s', $e->getMessage()), $e->getCode(), $e);
}
return $instance;
}
/**
* Block constructor.
*
* @param string $id
* @since 5.4.3
*/
public function __construct($id = null)
{
$this->id = $id ? (string) $id : $this->generateId();
}
/**
* @return string
* @since 5.4.3
*/
public function getId()
{
return $this->id;
}
/**
* @return string
* @since 5.4.3
*/
public function getToken()
{
return sprintf($this->tokenTemplate, $this->getId());
}
/**
* @return array
* @since 5.4.3
*/
public function toArray()
{
$blocks = [];
/**
* @var string $id
* @var ContentBlockInterface $block
*/
foreach ($this->blocks as $block) {
$blocks[$block->getId()] = $block->toArray();
}
$array = [
'_type' => get_class($this),
'_version' => $this->version,
'id' => $this->id,
];
if ($this->content) {
$array['content'] = $this->content;
}
if ($blocks) {
$array['blocks'] = $blocks;
}
return $array;
}
/**
* @return string
* @since 5.4.3
*/
public function toString()
{
if (!$this->blocks) {
return (string) $this->content;
}
$tokens = [];
$replacements = [];
foreach ($this->blocks as $block) {
$tokens[] = $block->getToken();
$replacements[] = $block->toString();
}
return str_replace($tokens, $replacements, (string)
$this->content);
}
/**
* @return string
* @since 5.4.3
*/
public function __toString()
{
try {
return $this->toString();
} catch (\Exception $e) {
return sprintf('Error while rendering block: %s',
$e->getMessage());
}
}
/**
* @param array $serialized
* @since 5.4.3
*/
public function build(array $serialized)
{
$this->checkVersion($serialized);
$this->id = isset($serialized['id']) ?
$serialized['id'] : $this->generateId();
if (isset($serialized['content'])) {
$this->setContent($serialized['content']);
}
$blocks = isset($serialized['blocks']) ? (array)
$serialized['blocks'] : [];
foreach ($blocks as $block) {
$this->addBlock(self::fromArray($block));
}
}
/**
* @param string $content
* @return $this
* @since 5.4.3
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* @param ContentBlockInterface $block
* @return $this
* @since 5.4.3
*/
public function addBlock(ContentBlockInterface $block)
{
$this->blocks[$block->getId()] = $block;
return $this;
}
/**
* @return string
* @since 5.4.3
*/
public function serialize()
{
return serialize($this->toArray());
}
/**
* @param string $serialized
* @since 5.4.3
*/
public function unserialize($serialized)
{
$array = unserialize($serialized);
$this->build($array);
}
/**
* @return string
* @since 5.4.3
*/
protected function generateId()
{
return uniqid('', true);
}
/**
* @param array $serialized
* @throws \RuntimeException
* @since 5.4.3
*/
protected function checkVersion(array $serialized)
{
$version = isset($serialized['_version']) ? (string)
$serialized['_version'] : 1;
if ($version != $this->version) {
throw new \RuntimeException(sprintf('Unsupported version
%s', $version));
}
}
}PKM[�[{�?:xx'Content/Block/ContentBlockInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Block;
/**
* @since 5.4.3
*/
interface ContentBlockInterface extends \Serializable
{
public static function create($id = null);
public static function fromArray(array $serialized);
public function __construct($id = null);
public function getId();
public function getToken();
public function toArray();
public function build(array $serialized);
public function setContent($content);
public function addBlock(ContentBlockInterface $block);
}PKM[�[��ue�2�2Content/Block/HtmlBlock.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Block;
use Gantry\Framework\Document;
use Gantry\Framework\Gantry;
use Gantry\Framework\Theme;
/**
* Class HtmlBlock
* @package Gantry\Component\Content\Block
* @since 5.4.3
*/
class HtmlBlock extends ContentBlock implements HtmlBlockInterface
{
protected $version = 1;
protected $frameworks = [];
protected $styles = [];
protected $scripts = [];
protected $html = [];
/**
* @return array
* @since 5.4.3
*/
public function getAssets()
{
$assets = $this->getAssetsFast();
$this->sortAssets($assets['styles']);
$this->sortAssets($assets['scripts']);
$this->sortAssets($assets['html']);
return $assets;
}
/**
* @return array
* @since 5.4.3
*/
public function getFrameworks()
{
$assets = $this->getAssetsFast();
return array_keys($assets['frameworks']);
}
/**
* @param string $location
* @return array
* @since 5.4.3
*/
public function getStyles($location = 'head')
{
$styles = $this->getAssetsInLocation('styles',
$location);
if (!$styles) {
return [];
}
$gantry = Gantry::instance();
/** @var Theme $theme */
$theme = isset($gantry['theme']) ?
$gantry['theme'] : null;
/** @var Document $document */
$document = $gantry['document'];
foreach ($styles as $key => $style) {
if (isset($style['href'])) {
$url = $style['href'];
if ($theme && preg_match('|\.scss$|',
$url)) {
// Compile SCSS files.
$url = $theme->css(basename($url,
'.scss'));
}
// Deal with streams and relative paths.
$url = $document->url($url, false, null, false);
$styles[$key]['href'] = $url;
}
}
return $styles;
}
/**
* @param string $location
* @return array
* @since 5.4.3
*/
public function getScripts($location = 'head')
{
$scripts = $this->getAssetsInLocation('scripts',
$location);
if (!$scripts) {
return [];
}
$gantry = Gantry::instance();
/** @var Document $document */
$document = $gantry['document'];
foreach ($scripts as $key => $script) {
if (isset($script['src'])) {
// Deal with streams and relative paths.
$scripts[$key]['src'] =
$document->url($script['src'], false, null, false);
}
}
return $scripts;
}
/**
* @param string $location
* @return array
* @since 5.4.3
*/
public function getHtml($location = 'bottom')
{
return $this->getAssetsInLocation('html', $location);
}
/**
* @return array
* @since 5.4.3
*/
public function toArray()
{
$array = parent::toArray();
if ($this->frameworks) {
$array['frameworks'] = $this->frameworks;
}
if ($this->styles) {
$array['styles'] = $this->styles;
}
if ($this->scripts) {
$array['scripts'] = $this->scripts;
}
if ($this->html) {
$array['html'] = $this->html;
}
return $array;
}
/**
* @param array $serialized
* @since 5.4.3
*/
public function build(array $serialized)
{
parent::build($serialized);
$this->frameworks = isset($serialized['frameworks']) ?
(array) $serialized['frameworks'] : [];
$this->styles = isset($serialized['styles']) ? (array)
$serialized['styles'] : [];
$this->scripts = isset($serialized['scripts']) ?
(array) $serialized['scripts'] : [];
$this->html = isset($serialized['html']) ? (array)
$serialized['html'] : [];
}
/**
* @param string $framework
* @return $this
* @since 5.4.3
*/
public function addFramework($framework)
{
$this->frameworks[$framework] = 1;
return $this;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*
* @example $block->addStyle('assets/js/my.js');
* @example $block->addStyle(['href' =>
'assets/js/my.js', 'media' => 'screen']);
* @since 5.4.3
*/
public function addStyle($element, $priority = 0, $location =
'head')
{
if (!is_array($element)) {
$element = ['href' => (string) $element];
}
if (empty($element['href'])) {
return false;
}
if (!isset($this->styles[$location])) {
$this->styles[$location] = [];
}
$id = !empty($element['id']) ? ['id' =>
(string) $element['id']] : [];
$href = $element['href'];
$type = !empty($element['type']) ? (string)
$element['type'] : 'text/css';
$media = !empty($element['media']) ? (string)
$element['media'] : null;
unset($element['tag'], $element['id'],
$element['rel'], $element['content'],
$element['href'], $element['type'],
$element['media']);
$this->styles[$location][md5($href) . sha1($href)] = [
':type' => 'file',
':priority' => (int) $priority,
'href' => $href,
'type' => $type,
'media' => $media,
'element' => $element
] + $id;
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
* @since 5.4.3
*/
public function addInlineStyle($element, $priority = 0, $location =
'head')
{
if (!is_array($element)) {
$element = ['content' => (string) $element];
}
if (empty($element['content'])) {
return false;
}
if (!isset($this->styles[$location])) {
$this->styles[$location] = [];
}
$content = (string) $element['content'];
$type = !empty($element['type']) ? (string)
$element['type'] : 'text/css';
$this->styles[$location][md5($content) . sha1($content)] = [
':type' => 'inline',
':priority' => (int) $priority,
'content' => $content,
'type' => $type
];
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
* @since 5.4.3
*/
public function addScript($element, $priority = 0, $location =
'head')
{
if (!is_array($element)) {
$element = ['src' => (string) $element];
}
if (empty($element['src'])) {
return false;
}
if (!isset($this->scripts[$location])) {
$this->scripts[$location] = [];
}
$src = $element['src'];
$type = !empty($element['type']) ? (string)
$element['type'] : 'text/javascript';
$defer = isset($element['defer']) ? true : false;
$async = isset($element['async']) ? true : false;
$handle = !empty($element['handle']) ? (string)
$element['handle'] : '';
$this->scripts[$location][md5($src) . sha1($src)] = [
':type' => 'file',
':priority' => (int) $priority,
'src' => $src,
'type' => $type,
'defer' => $defer,
'async' => $async,
'handle' => $handle
];
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
* @since 5.4.3
*/
public function addInlineScript($element, $priority = 0, $location =
'head')
{
if (!is_array($element)) {
$element = ['content' => (string) $element];
}
if (empty($element['content'])) {
return false;
}
if (!isset($this->scripts[$location])) {
$this->scripts[$location] = [];
}
$content = (string) $element['content'];
$type = !empty($element['type']) ? (string)
$element['type'] : 'text/javascript';
$this->scripts[$location][md5($content) . sha1($content)] = [
':type' => 'inline',
':priority' => (int) $priority,
'content' => $content,
'type' => $type
];
return true;
}
/**
* @param string $html
* @param int $priority
* @param string $location
* @return bool
* @since 5.4.3
*/
public function addHtml($html, $priority = 0, $location =
'bottom')
{
if (empty($html) || !is_string($html)) {
return false;
}
if (!isset($this->html[$location])) {
$this->html[$location] = [];
}
$this->html[$location][md5($html) . sha1($html)] = [
':priority' => (int) $priority,
'html' => $html
];
return true;
}
/**
* @param string $location
* @deprecated Temporarily needed in WP
* @since 5.4.3
*/
public function clearStyles($location = 'head')
{
foreach ($this->blocks as $block) {
if (method_exists($block, 'clearStyles')) {
$block->clearStyles($location);
}
}
unset($this->styles[$location]);
}
/**
* @param string $location
* @deprecated Temporarily needed in WP
* @since 5.4.3
*/
public function clearScripts($location = 'head')
{
foreach ($this->blocks as $block) {
if (method_exists($block, 'clearScripts')) {
$block->clearScripts($location);
}
}
unset($this->scripts[$location]);
}
/**
* @return array
* @since 5.4.3
*/
protected function getAssetsFast()
{
$assets = [
'frameworks' => $this->frameworks,
'styles' => $this->styles,
'scripts' => $this->scripts,
'html' => $this->html
];
foreach ($this->blocks as $block) {
if ($block instanceof HtmlBlock) {
$blockAssets = $block->getAssetsFast();
$assets['frameworks'] +=
$blockAssets['frameworks'];
foreach ($blockAssets['styles'] as $location
=> $styles) {
if (!isset($assets['styles'][$location])) {
$assets['styles'][$location] = $styles;
} elseif ($styles) {
$assets['styles'][$location] += $styles;
}
}
foreach ($blockAssets['scripts'] as $location
=> $scripts) {
if (!isset($assets['scripts'][$location])) {
$assets['scripts'][$location] = $scripts;
} elseif ($scripts) {
$assets['scripts'][$location] +=
$scripts;
}
}
foreach ($blockAssets['html'] as $location =>
$htmls) {
if (!isset($assets['html'][$location])) {
$assets['html'][$location] = $htmls;
} elseif ($htmls) {
$assets['html'][$location] += $htmls;
}
}
}
}
return $assets;
}
/**
* @param string $type
* @param string $location
* @return array
* @since 5.4.3
*/
protected function getAssetsInLocation($type, $location)
{
$assets = $this->getAssetsFast();
if (empty($assets[$type][$location])) {
return [];
}
$styles = $assets[$type][$location];
$this->sortAssetsInLocation($styles);
return $styles;
}
/**
* @param array $items
* @since 5.4.3
*/
protected function sortAssetsInLocation(array &$items)
{
$count = 0;
foreach ($items as &$item) {
$item[':order'] = ++$count;
}
uasort(
$items,
function ($a, $b) {
return ($a[':priority'] ==
$b[':priority']) ? $a[':order'] -
$b[':order'] : $b[':priority'] -
$a[':priority'];
}
);
}
/**
* @param array $array
* @since 5.4.3
*/
protected function sortAssets(array &$array)
{
foreach ($array as $location => &$items) {
$this->sortAssetsInLocation($items);
}
}
}PKM[�[�v*B��$Content/Block/HtmlBlockInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Block;
/**
* @since 5.4.3
*/
interface HtmlBlockInterface extends ContentBlockInterface
{
public function getAssets();
public function addFramework($framework);
public function addStyle($element, $priority = 0, $location =
'head');
public function addInlineStyle($element, $priority = 0, $location =
'head');
public function addScript($element, $priority = 0, $location =
'head');
public function addInlineScript($element, $priority = 0, $location =
'head');
public function addHtml($html, $priority = 0, $location =
'bottom');
}
PKM[�[ �Q��i�i!Content/Document/HtmlDocument.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Content\Document;
use Gantry\Component\Content\Block\ContentBlock;
use Gantry\Component\Content\Block\HtmlBlock;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Component\Url\Url;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class HtmlDocument
{
use GantryTrait;
public static $timestamp_age = 604800;
public static $urlFilterParams;
/**
* @var array|HtmlBlock[]
*/
protected static $stack;
protected static $frameworks = [];
protected static $scripts = [];
protected static $styles = [];
protected static $availableFrameworks = [
'jquery' => 'registerJquery',
'jquery.framework' => 'registerJquery',
'jquery.ui.core' =>
'registerJqueryUiSortable',
'jquery.ui.sortable' =>
'registerJqueryUiSortable',
'bootstrap.2' => 'registerBootstrap2',
'bootstrap.3' => 'registerBootstrap3',
'mootools' => 'registerMootools',
'mootools.framework' => 'registerMootools',
'mootools.core' => 'registerMootools',
'mootools.more' => 'registerMootoolsMore',
'lightcase' => 'registerLightcase',
'lightcase.init' => 'registerLightcaseInit',
];
public function __construct()
{
static::$stack = [];
static::push();
}
/**
* Create new local instance of document allowing asset caching.
*/
public static function push()
{
array_unshift(static::$stack, new HtmlBlock());
}
/**
* Return local instance of document allowing it to be cached.
*
* @return HtmlBlock
*/
public static function pop()
{
return array_shift(static::$stack);
}
/**
* @param ContentBlock $block
* @return $this
*/
public function addBlock(ContentBlock $block)
{
static::$stack[0]->addBlock($block);
return $this;
}
/**
* @param string $framework
* @return bool
*/
public static function addFramework($framework)
{
if (!isset(static::$availableFrameworks[$framework])) {
return false;
}
static::getObject();
static::$stack[0]->addFramework($framework);
return true;
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public static function addStyle($element, $priority = 0, $location =
'head')
{
static::getObject();
return static::$stack[0]->addStyle($element, $priority,
$location);
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public static function addInlineStyle($element, $priority = 0,
$location = 'head')
{
static::getObject();
return static::$stack[0]->addInlineStyle($element, $priority,
$location);
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public static function addScript($element, $priority = 0, $location =
'head')
{
static::getObject();
return static::$stack[0]->addScript($element, $priority,
$location);
}
/**
* @param string|array $element
* @param int $priority
* @param string $location
* @return bool
*/
public static function addInlineScript($element, $priority = 0,
$location = 'head')
{
static::getObject();
return static::$stack[0]->addInlineScript($element, $priority,
$location);
}
/**
* @param string $html
* @param int $priority
* @param string $location
* @return bool
*/
public static function addHtml($html, $priority = 0, $location =
'bottom')
{
static::getObject();
return static::$stack[0]->addHtml($html, $priority, $location);
}
/**
* @param array $element
* @param string $location
* @param int $priority
* @return bool
*/
public static function addHeaderTag(array $element, $location =
'head', $priority = 0)
{
$success = false;
switch ($element['tag']) {
case 'link':
if (!empty($element['rel']) &&
$element['rel'] === 'stylesheet') {
$success = static::addStyle($element, $priority,
$location);
}
break;
case 'style':
$success = static::addInlineStyle($element, $priority,
$location);
break;
case 'script':
if (!empty($element['src'])) {
$success = static::addScript($element, $priority,
$location);
} elseif (!empty($element['content'])) {
$success = static::addInlineScript($element, $priority,
$location);
}
break;
}
return $success;
}
public static function getStyles($location = 'head')
{
static::getObject();
$styles = static::$stack[0]->getStyles($location);
$output = [];
foreach ($styles as $style) {
switch ($style[':type']) {
case 'file':
$attribs = '';
if ($style['media']) {
$attribs .= ' media="' .
static::escape($style['media']) . '"';
}
$output[] = sprintf(
'<link rel="stylesheet"
href="%s" type="%s"%s />',
static::escape($style['href']),
static::escape($style['type']),
$attribs
);
break;
case 'inline':
$attribs = '';
if ($style['type'] !== 'text/css')
{
$attribs .= ' type="' .
static::escape($style['type']) . '"';
}
$output[] = sprintf(
'<style%s>%s</style>',
$attribs,
$style['content']
);
break;
}
}
return $output;
}
public static function getScripts($location = 'head')
{
static::getObject();
$scripts = static::$stack[0]->getScripts($location);
$output = [];
foreach ($scripts as $script) {
switch ($script[':type']) {
case 'file':
$attribs = '';
if ($script['async']) {
$attribs .= ' async="async"';
}
if ($script['defer']) {
$attribs .= ' defer="defer"';
}
$output[] = sprintf(
'<script type="%s"%s
src="%s"></script>',
static::escape($script['type']),
$attribs,
static::escape($script['src'])
);
break;
case 'inline':
$output[] = sprintf(
'<script
type="%s">%s</script>',
static::escape($script['type']),
$script['content']
);
break;
}
}
return $output;
}
public static function getHtml($location = 'bottom')
{
static::getObject();
$htmls = static::$stack[0]->getHtml($location);
$output = [];
foreach ($htmls as $html) {
$output[] = $html['html'];
}
return $output;
}
/**
* Escape string (emulates twig filter).
*
* @param string|object $string
* @param string $strategy
* @return string
*/
public static function escape($string, $strategy = 'html')
{
if (!is_string($string)) {
if (is_object($string) && method_exists($string,
'__toString')) {
$string = (string) $string;
} elseif (in_array($strategy, ['html',
'js', 'css', 'html_attr', 'url']))
{
return $string;
}
}
switch ($strategy) {
case 'html':
return htmlspecialchars($string, ENT_QUOTES |
ENT_SUBSTITUTE, 'UTF-8');
case 'js':
if (0 === strlen($string) ? false : (1 ===
preg_match('/^./su', $string) ? false : true)) {
throw new \RuntimeException('The string to escape
is not a valid UTF-8 string.');
}
$string = preg_replace_callback(
'#[^a-zA-Z0-9,\._]#Su',
'Gantry\\Component\\Content\\Document\\HtmlDocument::_escape_js_callback',
$string
);
return $string;
case 'css':
if (0 === strlen($string) ? false : (1 ===
preg_match('/^./su', $string) ? false : true)) {
throw new \RuntimeException('The string to escape
is not a valid UTF-8 string.');
}
$string = preg_replace_callback(
'#[^a-zA-Z0-9]#Su',
'Gantry\\Component\\Content\\Document\\HtmlDocument::_escape_css_callback',
$string
);
return $string;
case 'html_attr':
if (0 === strlen($string) ? false : (1 ===
preg_match('/^./su', $string) ? false : true)) {
throw new \RuntimeException('The string to escape
is not a valid UTF-8 string.');
}
$string = preg_replace_callback(
'#[^a-zA-Z0-9,\.\-_]#Su',
'Gantry\\Component\\Content\\Document\\HtmlDocument::_escape_html_attr_callback',
$string
);
return $string;
case 'url':
return rawurlencode($string);
default:
throw new \RuntimeException(sprintf('Invalid escaping
strategy "%s" (valid ones: html, js, css, html_attr, url).',
$strategy));
}
}
/**
* @param $framework
* @return bool
* @deprecated 5.3
*/
public static function load($framework)
{
return static::addFramework($framework);
}
/**
* Register assets.
*/
public static function registerAssets()
{
static::registerFrameworks();
}
public static function siteUrl()
{
return static::rootUri();
}
/**
* NOTE: In PHP this function can be called either from Gantry DI
container or statically.
*
* @return string
*/
public static function rootUri()
{
return '';
}
/**
* NOTE: In PHP this function can be called either from Gantry DI
container or statically.
*
* @param bool $addDomain
* @return string
*/
public static function domain($addDomain = false)
{
return '';
}
/**
* Return URL to the resource.
*
* @example {{
url('gantry-theme://images/logo.png')|default('http://www.placehold.it/150x100/f4f4f4')
}}
*
* NOTE: In PHP this function can be called either from Gantry DI
container or statically.
*
* @param string $url Resource to be located.
* @param bool $domain True to include domain name.
* @param int $timestamp_age Append timestamp to files that are less
than x seconds old. Defaults to a week.
* Use value <= 0 to disable the
feature.
* @param bool $allowNull True if non-existing files should return
null.
* @return string|null Returns url to the resource or null if
resource was not found.
*/
public static function url($url, $domain = false, $timestamp_age =
null, $allowNull = true)
{
if (!is_string($url) || $url === '') {
// Return null on invalid input.
return null;
}
if ($url[0] === '#' || $url[0] === '?') {
// Handle urls with query string or fragment only.
return str_replace(' ', '%20', $url);
}
$parts = Url::parse($url);
if (!is_array($parts)) {
// URL could not be parsed.
return $allowNull ? null : str_replace(' ',
'%20', $url);
}
// Make sure we always have scheme, host, port and path.
$scheme = isset($parts['scheme']) ?
$parts['scheme'] : '';
$host = isset($parts['host']) ? $parts['host']
: '';
$port = isset($parts['port']) ? $parts['port']
: '';
$path = isset($parts['path']) ? $parts['path']
: '';
if ($scheme && !$port) {
// If URL has a scheme, we need to check if it's one of
Gantry streams.
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
if (!$locator->schemeExists($scheme)) {
// If scheme does not exists as a stream, assume it's
external.
return str_replace(' ', '%20', $url);
}
// Attempt to find the resource (because of parse_url() we need
to put host back to path).
$newPath =
$locator->findResource("{$scheme}://{$host}{$path}", false);
if ($newPath === false) {
if ($allowNull) {
return null;
}
// Return location where the file would be if it was saved.
$path =
$locator->findResource("{$scheme}://{$host}{$path}", false,
true);
} else {
$path = $newPath;
}
} elseif ($host || $port) {
// If URL doesn't have scheme but has host or port, it is
external.
return str_replace(' ', '%20', $url);
}
// At this point URL is either relative or absolute path; let us
find if it is relative and not . or ..
if ($path && '/' !== $path[0] &&
'.' !== $path[0]) {
if ($timestamp_age === null) {
$timestamp_age = static::$timestamp_age;
}
if ($timestamp_age > 0) {
// We want to add timestamp to the URI: do it only for
existing files.
$realPath = @realpath(GANTRY5_ROOT . '/' .
$path);
if ($realPath && is_file($realPath)) {
$time = filemtime($realPath);
// Only append timestamp for files that are less than
the maximum age.
if ($time > time() - $timestamp_age) {
$parts['query'] =
(!empty($parts['query']) ?
"{$parts['query']}&" : '') .
sprintf('%x', $time);
}
}
}
// We need absolute URI instead of relative.
$path = rtrim(static::rootUri(), '/') . '/'
. $path;
}
// Set absolute URI.
$uri = $path;
// Add query string back.
if (!empty($parts['query'])) {
if (!$uri) $uri = static::rootUri();
$uri .= '?' . $parts['query'];
}
// Add fragment back.
if (!empty($parts['fragment'])) {
if (!$uri) $uri = static::rootUri();
$uri .= '#' . $parts['fragment'];
}
return static::domain($domain) . str_replace(' ',
'%20', $uri);
}
/**
* Filter stream URLs from HTML.
*
* @param string $html HTML input to be filtered.
* @param bool $domain True to include domain name.
* @param int $timestamp_age Append timestamp to files that are less
than x seconds old. Defaults to a week.
* Use value <= 0 to disable the
feature.
* @param bool $streamOnly Only touch streams.
* @return string Returns modified HTML.
*/
public static function urlFilter($html, $domain = false, $timestamp_age
= null, $streamOnly = false)
{
static::$urlFilterParams = [$domain, $timestamp_age, $streamOnly];
// Tokenize all PRE, CODE and SCRIPT tags to avoid modifying any
src|href|url in them
$tokens = [];
$html =
preg_replace_callback('#<(pre|code|script)(\s[^>]+)?>.*?</\\1>#ius',
function($matches) use (&$tokens) {
// Unfortunately uniqid() doesn't quite work in Windows,
so we need to work it around by adding some randomness.
$token = '@@'. uniqid(mt_rand(), true) .
'@@';
$match = $matches[0];
$tokens[$token] = $match;
return $token;
}, $html);
if ($streamOnly) {
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$schemes = $locator->getSchemes();
$list = [];
foreach ($schemes as $scheme) {
if (strpos($scheme, 'gantry-') === 0) {
$list[] = substr($scheme, 7);
}
}
if (empty($list)) {
return $html;
}
$match = '(gantry-(' . implode('|', $list).
')://.*?)';
} else {
$match = '(.*?)';
}
$html = preg_replace_callback('^(\s)(src|href)="' .
$match . '"^u', 'static::linkHandler', $html);
$html = preg_replace_callback('^(\s)url\(' . $match .
'\)^u', 'static::urlHandler', $html);
$html = static::replaceTokens($tokens, $html);
return $html;
}
/**
* @param array $matches
* @return string
* @internal
*/
public static function linkHandler(array $matches)
{
list($domain, $timestamp_age) = static::$urlFilterParams;
$url = trim($matches[3]);
$url = static::url($url, $domain, $timestamp_age, false);
return "{$matches[1]}{$matches[2]}=\"{$url}\"";
}
/**
* @param array $matches
* @return string
* @internal
*/
public static function urlHandler(array $matches)
{
list($domain, $timestamp_age) = static::$urlFilterParams;
$url = trim($matches[2], '"\'');
$url = static::url($url, $domain, $timestamp_age, false);
return "{$matches[1]}url({$url})";
}
/**
* This function is adapted from code coming from Twig.
*
* @param array $matches
* @return string
* @internal
*/
public static function _escape_js_callback($matches)
{
$char = $matches[0];
/*
* A few characters have short escape sequences in JSON and
JavaScript.
* Escape sequences supported only by JavaScript, not JSON, are
ommitted.
* \" is also supported but omitted, because the resulting
string is not HTML safe.
*/
static $shortMap = [
'\\' => '\\\\',
'/' => '\\/',
"\x08" => '\b',
"\x0C" => '\f',
"\x0A" => '\n',
"\x0D" => '\r',
"\x09" => '\t',
];
if (isset($shortMap[$char])) {
return $shortMap[$char];
}
// \uHHHH
$char = static::convert_encoding($char, 'UTF-16BE',
'UTF-8');
$char = strtoupper(bin2hex($char));
if (4 >= \strlen($char)) {
return sprintf('\u%04s', $char);
}
return sprintf('\u%04s\u%04s', substr($char, 0, -4),
substr($char, -4));
}
/**
* This function is adapted from code coming from Twig.
*
* @param $matches
* @return string
* @internal
*/
public static function _escape_css_callback($matches)
{
$char = $matches[0];
return sprintf('\\%X ', 1 === \strlen($char) ?
\ord($char) : static::ord($char));
}
/**
* This function is adapted from code coming from Twig and Zend
Framework.
*
* @param array $matches
* @return string
*
* @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc.
(https://www.zend.com)
* @license https://framework.zend.com/license/new-bsd New BSD
License
* @internal
*/
public static function _escape_html_attr_callback($matches)
{
$chr = $matches[0];
$ord = \ord($chr);
/*
* The following replaces characters undefined in HTML with the
* hex entity for the Unicode replacement character.
*/
if (($ord <= 0x1f && "\t" !== $chr &&
"\n" !== $chr && "\r" !== $chr) || ($ord >=
0x7f && $ord <= 0x9f)) {
return '�';
}
/*
* Check if the current character to escape has a name entity we
should
* replace it with while grabbing the hex value of the character.
*/
if (1 === \strlen($chr)) {
/*
* While HTML supports far more named entities, the lowest
common denominator
* has become HTML5's XML Serialisation which is
restricted to the those named
* entities that XML supports. Using HTML entities would result
in this error:
* XML Parsing Error: undefined entity
*/
static $entityMap = [
34 => '"', /* quotation mark */
38 => '&', /* ampersand */
60 => '<', /* less-than sign */
62 => '>', /* greater-than sign */
];
if (isset($entityMap[$ord])) {
return $entityMap[$ord];
}
return sprintf('&#x%02X;', $ord);
}
/*
* Per OWASP recommendations, we'll use hex entities for any
other
* characters where a named entity does not exist.
*/
return sprintf('&#x%04X;', static::ord($chr));
}
/**
* Replace tokens with strings.
*
* @param array $tokens
* @param $html
* @return string|NUll
*/
protected static function replaceTokens(array $tokens, $html)
{
foreach ($tokens as $token => $replacement) {
// We need to use callbacks to turn off backreferences ($1,
\\1) in the replacement string.
$callback = function() use ($replacement) { return
$replacement; };
$html = preg_replace_callback('#' .
preg_quote($token, '#') . '#u', $callback, $html);
}
return $html;
}
/**
* Register loaded frameworks.
*/
protected static function registerFrameworks()
{
foreach (static::$stack[0]->getFrameworks() as $framework) {
if (isset(static::$availableFrameworks[$framework])) {
call_user_func([get_called_class(),
static::$availableFrameworks[$framework]]);
}
}
}
protected static function registerJquery()
{
static::addScript(
[
'src' =>
'https://code.jquery.com/jquery-2.2.2.min.js',
'integrity' =>
'sha256-36cp2Co+/62rEAAYHLmRCPIych47CvdM+uTBJwSzWjI=',
'crossorigin' => 'anonymous'
],
11
);
}
protected static function registerJqueryUiSortable()
{
static::registerJquery();
static::addScript(
[
'src' =>
'https://code.jquery.com/ui/1.11.4/jquery-ui.min.js',
'integrity' =>
'sha256-xNjb53/rY+WmG+4L6tTl9m6PpqknWZvRt0rO1SRnJzw=',
'crossorigin' => 'anonymous'
],
11
);
}
protected static function registerBootstrap2()
{
static::registerJquery();
static::addScript(['src' =>
'https://maxcdn.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js'],
11);
}
protected static function registerBootstrap3()
{
static::registerJquery();
static::addScript(['src' =>
'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js'],
11);
}
protected static function registerMootools()
{
static::addScript(['src' =>
'https://cdnjs.cloudflare.com/ajax/libs/mootools/1.5.2/mootools-core-compat.min.js'],
11);
}
protected static function registerMootoolsMore()
{
static::registerMootools();
static::addScript(['src' =>
'https://cdnjs.cloudflare.com/ajax/libs/mootools-more/1.5.2/mootools-more-compat-compressed.js'],
11);
}
protected static function registerLightcase()
{
static::registerJquery();
static::addScript(['src' =>
static::url('gantry-assets://js/lightcase.js', false, null,
false)], 11, 'footer');
static::addStyle(['href' =>
static::url('gantry-assets://css/lightcase.css', false, null,
false)], 11);
}
protected static function registerLightcaseInit()
{
static::registerLightcase();
static::addInlineScript(['content' =>
"jQuery(document).ready(function($) {
jQuery('[data-rel^=lightcase]').lightcase({maxWidth:
'100%', maxHeight: '100%', video: {width:
'1280', height: '720'}}); });"], 0,
'footer');
}
protected static function getObject()
{
static $object;
if (!$object) {
// We need to initialize document for backwards compatibility
(RokSprocket/RokGallery in WP).
$object = Gantry::instance()['document'];
}
return $object;
}
/**
* @param string $string
* @param string $to
* @param string $from
* @return false|string|string[]|null
* @internal
*/
private static function convert_encoding($string, $to, $from)
{
if (\function_exists('mb_convert_encoding')) {
return mb_convert_encoding($string, $to, $from);
}
if (\function_exists('iconv')) {
return iconv($from, $to, $string);
}
throw new \RuntimeException('No suitable convert encoding
function (use UTF-8 as your encoding or install the iconv or mbstring
extension).');
}
/**
* @param string $string
* @return false|int|mixed
* @internal
*/
private static function ord($string)
{
if (\function_exists('mb_ord')) {
return mb_ord($string, 'UTF-8');
}
$code = ($string = unpack('C*', substr($string, 0, 4))) ?
$string[1] : 0;
if (0xF0 <= $code) {
return (($code - 0xF0) << 18) + (($string[2] - 0x80)
<< 12) + (($string[3] - 0x80) << 6) + $string[4] - 0x80;
}
if (0xE0 <= $code) {
return (($code - 0xE0) << 12) + (($string[2] - 0x80)
<< 6) + $string[3] - 0x80;
}
if (0xC0 <= $code) {
return (($code - 0xC0) << 6) + $string[2] - 0x80;
}
return $code;
}
}
PKN[�[,���Controller/BaseController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Controller;
use Gantry\Framework\Request;
use RocketTheme\Toolbox\DI\Container;
use RuntimeException;
abstract class BaseController implements RestfulControllerInterface
{
/**
* @var string Default HTTP method.
*/
protected $method = 'GET';
/**
* @var Request
*/
protected $request;
/**
* @var array List of HTTP verbs and their actions.
*/
protected $httpVerbs = [
'GET' => [
'/' => 'index',
'/create' => 'create',
'/*' => 'display',
'/*/edit' => 'edit'
],
'POST' => [
'/' => 'store'
],
'PUT' => [
'/*' => 'replace'
],
'PATCH' => [
'/*' => 'update'
],
'DELETE' => [
'/*' => 'destroy'
]
];
/**
* @var array Parameters from router.
*/
protected $params = [];
/**
* @var Container
*/
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
$this->request = $container['request'];
}
/**
* Execute controller.
*
* @param string $method
* @param array $path
* @param array $params
* @return mixed
* @throws \RuntimeException
*/
public function execute($method, array $path, array $params)
{
$this->method = $method;
$this->setParams($params);
list($action, $path) = $this->resolveHttpVerb($method, $path);
if (!method_exists($this, $action)) {
$action = 'undefined';
}
return call_user_func_array([$this, $action], $path);
}
/**
* Set router parameters. Replaces the old parameters.
*
* @param array $params
* @return $this
*/
public function setParams(array $params)
{
$this->params = $params;
return $this;
}
/**
* @example GET /resources
*
* @return mixed
*/
public function index()
{
return $this->undefined();
}
/**
* @example GET /resources/:id
*
* @param string $id
* @return mixed
*/
public function display($id)
{
return $this->undefined();
}
/**
* Special sub-resource to create a new resource (returns a form).
*
* @example GET /resources/create
*
* @return mixed
*/
public function create()
{
return $this->undefined();
}
/**
* Special sub-resource to edit existing resource (returns a form).
*
* @example GET /resources/:id/edit
*
* @param string $id
* @return mixed
*/
public function edit($id)
{
return $this->undefined();
}
/**
* @example POST /resources
*
* @return mixed
*/
public function store()
{
return $this->undefined();
}
/**
* @example PUT /resources/:id
*
* @param string $id
* @return mixed
*/
public function replace($id)
{
return $this->undefined();
}
/**
* @example PATCH /resources/:id
*
* @param string $id
* @return mixed
*/
public function update($id)
{
return $this->undefined();
}
/**
* @example DELETE /resources/:id
*
* @param string $id
* @return mixed
*/
public function destroy($id)
{
return $this->undefined();
}
/**
* Catch all action for all undefined actions.
*
* @return mixed
* @throws RuntimeException
*/
public function undefined()
{
if (in_array($this->method, ['HEAD',
'GET'])) {
throw new RuntimeException('Page Not Found', 404);
}
throw new RuntimeException('Invalid Action', 405);
}
/**
* Catch all action for forbidden actions.
*
* @return mixed
* @throws RuntimeException
*/
public function forbidden()
{
throw new RuntimeException('Forbidden', 403);
}
/**
* Load resource.
*
* Function throws an exception if resource does not exist.
*
* @param string|int $id
* @throws \RuntimeException
*/
protected function loadResource($id)
{
throw new RuntimeException('Resource Not Found', 404);
}
/**
* Resolve HTTP verb.
*
* @param string $method
* @param array $items
* @return array [function, parameters]
*/
protected function resolveHttpVerb($method, array $items)
{
// HEAD has identical behavior to GET.
$method = ($method == 'HEAD') ? 'GET' :
$method;
if (!isset($this->httpVerbs[$method])) {
// HTTP method is not defined.
return ['undefined', $items];
}
$path = '';
$remaining = $items;
$variables = [];
$actions = $this->httpVerbs[$method];
// Build path for the verb and fetch all the variables.
while (($current = array_shift($remaining)) !== null) {
$test = "{$path}/{$current}";
if (!isset($actions[$test])) {
// Specific path not found, check if we have a variable.
$test = "{$path}/*";
if (isset($actions[$test])) {
// Variable found, save the value and move on.
$variables[] = $current;
} elseif (isset($actions[$test . '*'])) {
// Wildcard found, pass through rest of the variables.
$path = $test . '*';
$variables = array_merge($variables, [$current],
$remaining);
break;
} else {
// No matches; we are done here.
return ['undefined', $items];
}
}
// Path was found.
$path = $test;
}
// No matching path; check if we have verb for the root.
if (!$path && isset($actions['/'])) {
$path = '/';
}
// Get the action.
$action = $path ? $actions[$path] : 'undefined';
return [$action, $variables];
}
}
PKN[�[���00Controller/HtmlController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Controller;
use Gantry\Component\Response\HtmlResponse;
use Gantry\Component\Response\Response;
abstract class HtmlController extends BaseController
{
/**
* Execute controller and returns Response object, defaulting to
HtmlResponse.
*
* @param string $method
* @param array $path
* @param array $params
* @return mixed
* @throws \RuntimeException
*/
public function execute($method, array $path, array $params)
{
$response = parent::execute($method, $path, $params);
if (!$response instanceof Response) {
$response = new HtmlResponse($response);
}
return $response;
}
}
PKN[�[0s���Controller/JsonController.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Controller;
use Gantry\Component\Response\JsonResponse;
abstract class JsonController extends BaseController
{
/**
* Execute controller and returns JsonResponse object.
*
* @param string $method
* @param array $path
* @param array $params
* @return mixed
* @throws \RuntimeException
*/
public function execute($method, array $path, array $params)
{
$response = parent::execute($method, $path, $params);
if (!$response instanceof JsonResponse) {
$response = new JsonResponse($response);
}
return $response;
}
}
PKN[�[�VVaa)Controller/RestfulControllerInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Controller;
interface RestfulControllerInterface
{
/**
* @example GET /resources
*
* @return mixed
*/
public function index();
/**
* @example GET /resources/:id
*
* @param string $id
* @return mixed
*/
public function display($id);
/**
* Special sub-resource to create a new resource (returns a form).
*
* @example GET /resources/create
*
* @return mixed
*/
public function create();
/**
* Special sub-resource to edit existing resource (returns a form).
*
* @example GET /resources/:id/edit
*
* @param string $id
* @return mixed
*/
public function edit($id);
/**
* @example POST /resources
*
* @return mixed
*/
public function store();
/**
* @example PUT /resources/:id
*
* @param string $id
* @return mixed
*/
public function replace($id);
/**
* @example PATCH /resources/:id
*
* @param string $id
* @return mixed
*/
public function update($id);
/**
* @example DELETE /resources/:id
*
* @param string $id
* @return mixed
*/
public function destroy($id);
}
PKN[�[��7��File/CompiledFile.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\File;
use RocketTheme\Toolbox\File\PhpFile;
/**
* Class CompiledFile
* @package Grav\Common\File
*
* @property string $filename
* @property string $extension
* @property string $raw
* @property array|string $content
*/
trait CompiledFile
{
protected $cachePath;
protected $caching = true;
/**
* @param string $path
* @return $this
*/
public function setCachePath($path)
{
$this->cachePath = $path;
return $this;
}
public function caching($enabled = null)
{
if (null !== $enabled) {
$this->caching = (bool) $enabled;
}
return $this->caching;
}
/**
* Get/set parsed file contents.
*
* @param mixed $var
* @return string
* @throws \BadMethodCallException
*/
public function content($var = null)
{
if (!$this->cachePath) {
throw new \BadMethodCallException("Cache path not defined
for compiled file ({$this->filename})!");
}
try {
// If nothing has been loaded, attempt to get pre-compiled
version of the file first.
if ($var === null && $this->raw === null &&
$this->content === null) {
$modified = $this->modified();
if (!$modified || !$this->caching) {
return $this->decode($this->raw());
}
$key = md5($this->filename);
$file = PhpFile::instance($this->cachePath .
"/{$key}{$this->extension}.php");
$class = get_class($this);
$cache = $file->exists() ? $file->content() : null;
// Load real file if cache isn't up to date (or is
invalid).
if (!isset($cache['@class'])
|| $cache['@class'] != $class
|| $cache['modified'] != $modified
|| $cache['filename'] != $this->filename
) {
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will
check this in a bit.
}
// Decode RAW file into compiled array.
$data = $this->decode($this->raw());
$cache = [
'@class' => $class,
'filename' => $this->filename,
'modified' => $modified,
'data' => $data
];
// If compiled file wasn't already locked by
another process, save it.
if ($file->locked() !== false) {
$file->save($cache);
$file->unlock();
// Compile cached file into bytecode cache
if
(function_exists('opcache_invalidate')) {
// Silence error in case if
`opcache.restrict_api` directive is set.
@opcache_invalidate($file->filename(),
true);
} elseif
(function_exists('apc_compile_file')) {
// PHP 5.4
@apc_compile_file($file->filename());
}
}
}
$file->free();
$this->content = $cache['data'];
}
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('Failed to read %s:
%s', basename($this->filename), $e->getMessage()), 500, $e);
}
return parent::content($var);
}
}
PKN[�[{BBFile/CompiledYamlFile.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\File;
use RocketTheme\Toolbox\File\YamlFile;
class CompiledYamlFile extends YamlFile
{
use CompiledFile;
static public $defaultCachePath;
static public $defaultCaching = true;
protected function __construct()
{
parent::__construct();
$this->caching(static::$defaultCaching);
if (static::$defaultCachePath) {
$this->setCachePath(static::$defaultCachePath);
}
}
}
PKN[�[�{�+�+Filesystem/Folder.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Filesystem;
/**
* Folder helper class.
*
* @author RocketTheme
* @license MIT
*/
abstract class Folder
{
/**
* Recursively find the last modified time under given path.
*
* @param string $path
* @return int
*/
public static function lastModifiedFolder($path)
{
$last_modified = 0;
$directory = new \RecursiveDirectoryIterator($path,
\RecursiveDirectoryIterator::SKIP_DOTS);
$iterator = new \RecursiveIteratorIterator($directory,
\RecursiveIteratorIterator::SELF_FIRST);
/** @var \RecursiveDirectoryIterator $file */
foreach ($iterator as $file) {
$dir_modified = $file->getMTime();
if ($dir_modified > $last_modified) {
$last_modified = $dir_modified;
}
}
return $last_modified;
}
/**
* Get relative path between target and base path. If path isn't
relative, return full path.
*
* @param string $path
* @param string $base
* @return string
*/
public static function getRelativePath($path, $base = GANTRY5_ROOT)
{
$base = preg_replace('![\\\/]+!', '/', $base);
$path = preg_replace('![\\\/]+!', '/', $path);
if (strpos($path, $base) === 0) {
$path = ltrim(substr($path, strlen($base)), '/');
}
return $path;
}
/**
* Get relative path between target and base path. If path isn't
relative, return full path.
*
* @param string $path
* @param string $base
* @return string
*/
public static function getRelativePathDotDot($path, $base)
{
$base = preg_replace('![\\\/]+!', '/', $base);
$path = preg_replace('![\\\/]+!', '/', $path);
if ($path === $base) {
return '';
}
$baseParts = explode('/', isset($base[0]) &&
'/' === $base[0] ? substr($base, 1) : $base);
$pathParts = explode('/', isset($path[0]) &&
'/' === $path[0] ? substr($path, 1) : $path);
array_pop($baseParts);
$lastPart = array_pop($pathParts);
foreach ($baseParts as $i => $directory) {
if (isset($pathParts[$i]) && $pathParts[$i] ===
$directory) {
unset($baseParts[$i], $pathParts[$i]);
} else {
break;
}
}
$pathParts[] = $lastPart;
$path = str_repeat('../', count($baseParts)) .
implode('/', $pathParts);
return '' === $path
|| '/' === $path[0]
|| false !== ($colonPos = strpos($path, ':'))
&& ($colonPos < ($slashPos = strpos($path, '/')) ||
false === $slashPos)
? "./$path" : $path;
}
/**
* Shift first directory out of the path.
*
* @param string $path
* @return string
*/
public static function shift(&$path)
{
$parts = explode('/', trim($path, '/'), 2);
$result = array_shift($parts);
$path = array_shift($parts);
return $result ?: null;
}
/**
* Return recursive list of all files and directories under given path.
*
* @param string $path
* @param array $params
* @return array
* @throws \RuntimeException
*/
public static function all($path, array $params = array())
{
if ($path === false) {
throw new \RuntimeException("Path to {$path} doesn't
exist.");
}
$compare = isset($params['compare']) ? 'get' .
$params['compare'] : null;
$pattern = isset($params['pattern']) ?
$params['pattern'] : null;
$filters = isset($params['filters']) ?
$params['filters'] : null;
$recursive = isset($params['recursive']) ?
$params['recursive'] : true;
$levels = isset($params['levels']) ?
$params['levels'] : -1;
$key = isset($params['key']) ? 'get' .
$params['key'] : null;
$value = isset($params['value']) ? 'get' .
$params['value'] : ($recursive ? 'getSubPathname' :
'getFilename');
$folders = isset($params['folders']) ?
$params['folders'] : true;
$files = isset($params['files']) ?
$params['files'] : true;
if ($recursive) {
$directory = new \RecursiveDirectoryIterator($path,
\RecursiveDirectoryIterator::SKIP_DOTS +
\FilesystemIterator::UNIX_PATHS + \FilesystemIterator::CURRENT_AS_SELF);
$iterator = new \RecursiveIteratorIterator($directory,
\RecursiveIteratorIterator::SELF_FIRST);
$iterator->setMaxDepth(max($levels, -1));
} else {
$iterator = new \FilesystemIterator($path);
}
$results = array();
/** @var \RecursiveDirectoryIterator $file */
foreach ($iterator as $file) {
// Ignore hidden files.
if ($file->getFilename()[0] == '.') {
continue;
}
if (!$folders && $file->isDir()) {
continue;
}
if (!$files && $file->isFile()) {
continue;
}
if ($compare && $pattern &&
!preg_match($pattern, $file->{$compare}())) {
continue;
}
$fileKey = $key ? $file->{$key}() : null;
$filePath = $file->{$value}();
if ($filters) {
if (isset($filters['key'])) {
$filter = $filters['key'];
$pre = !empty($filters['pre-key']) ?
$filters['pre-key'] : '';
if (is_callable($filter)) {
$fileKey = $pre . call_user_func($filter,
$fileKey);
} else {
$fileKey = $pre . preg_replace($filter,
'', $fileKey);
}
}
if (isset($filters['value'])) {
$filter = $filters['value'];
if (is_callable($filter)) {
$filePath = call_user_func($filter, $file);
} else {
$filePath = preg_replace($filter, '',
$filePath);
}
}
}
if ($fileKey !== null) {
$results[$fileKey] = $filePath;
} else {
$results[] = $filePath;
}
}
return $results;
}
/**
* Recursively copy directory in filesystem.
*
* @param string $source
* @param string $target
* @param string $ignore Ignore files matching pattern (regular
expression).
* @throws \RuntimeException
*/
public static function copy($source, $target, $ignore = null)
{
$source = rtrim($source, '\\/');
$target = rtrim($target, '\\/');
if (!is_dir($source)) {
throw new \RuntimeException('Cannot copy non-existing
folder.');
}
// Make sure that path to the target exists before copying.
self::create($target);
$success = true;
// Go through all sub-directories and copy everything.
$files = self::all($source);
foreach ($files as $file) {
if ($ignore && preg_match($ignore, $file)) {
continue;
}
$src = $source .'/'. $file;
$dst = $target .'/'. $file;
if (is_dir($src)) {
// Create current directory (if it doesn't exist).
if (!is_dir($dst)) {
$success &= @mkdir($dst, 0777, true);
}
} else {
// Or copy current file.
$success &= @copy($src, $dst);
}
}
if (!$success) {
$error = error_get_last();
throw new \RuntimeException($error['message']);
}
// Make sure that the change will be detected when caching.
@touch(dirname($target));
}
/**
* Move directory in filesystem.
*
* @param string $source
* @param string $target
* @throws \RuntimeException
*/
public static function move($source, $target)
{
if (!is_dir($source)) {
throw new \RuntimeException('Cannot move non-existing
folder.');
}
// Make sure that path to the target exists before moving.
self::create(dirname($target));
// Just rename the directory.
$success = @rename($source, $target);
if (!$success) {
$error = error_get_last();
throw new \RuntimeException($error['message']);
}
// Make sure that the change will be detected when caching.
@touch(dirname($source));
@touch(dirname($target));
}
/**
* Recursively delete directory from filesystem.
*
* @param string $target
* @param bool $include_target
* @throws \RuntimeException
*/
public static function delete($target, $include_target = true)
{
if (!$target) { return; }
if (!is_dir($target)) {
throw new \RuntimeException('Cannot delete non-existing
folder.');
}
$success = self::doDelete($target, $include_target);
if (!$success) {
$error = error_get_last();
throw new \RuntimeException($error['message']);
}
// Make sure that the change will be detected when caching.
if ($include_target) {
@touch(dirname($target));
} else {
@touch($target);
}
}
/**
* @param string $folder
* @throws \RuntimeException
*/
public static function create($folder)
{
if (is_dir($folder)) {
return;
}
$success = @mkdir($folder, 0777, true);
if (!$success) {
// Take yet another look, make sure that the folder
doesn't exist.
clearstatcache(true, $folder);
if (is_dir($folder)) {
return;
}
$error = error_get_last();
throw new \RuntimeException($error['message']);
}
}
/**
* @param string $folder
* @param bool $include_target
* @return bool
* @internal
*/
protected static function doDelete($folder, $include_target = true)
{
// Special case for symbolic links.
if ($include_target && is_link($folder)) {
return @unlink($folder);
}
// Go through all items in filesystem and recursively remove
everything.
$files = array_diff(scandir($folder), array('.',
'..'));
foreach ($files as $file) {
$path = "{$folder}/{$file}";
(is_dir($path)) ? self::doDelete($path) : @unlink($path);
}
return $include_target ? @rmdir($folder) : true;
}
}
PKO[�[ڀ}e
Filesystem/Streams.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Filesystem;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RocketTheme\Toolbox\StreamWrapper\ReadOnlyStream;
use RocketTheme\Toolbox\StreamWrapper\Stream;
class Streams
{
/**
* @var array
*/
protected $schemes = [];
/**
* @var array
*/
protected $registered;
/**
* @var UniformResourceLocator
*/
protected $locator;
public function __construct(UniformResourceLocator $locator = null)
{
if ($locator) {
$this->setLocator($locator);
}
}
/**
* @param UniformResourceLocator $locator
*/
public function setLocator(UniformResourceLocator $locator)
{
$this->locator = $locator;
// Set locator to both streams.
Stream::setLocator($locator);
ReadOnlyStream::setLocator($locator);
}
/**
* @return UniformResourceLocator
*/
public function getLocator()
{
return $this->locator;
}
public function add(array $schemes)
{
foreach ($schemes as $scheme => $config) {
$force = !empty($config['force']);
if (isset($config['paths'])) {
$this->locator->addPath($scheme, '',
$config['paths'], false, $force);
}
if (isset($config['prefixes'])) {
foreach ($config['prefixes'] as $prefix =>
$paths) {
$this->locator->addPath($scheme, $prefix, $paths,
false, $force);
}
}
$type = !empty($config['type']) ?
$config['type'] : 'ReadOnlyStream';
if ($type[0] != '\\') {
$type = '\\Rockettheme\\Toolbox\\StreamWrapper\\'
. $type;
}
$this->schemes[$scheme] = $type;
if (isset($this->registered)) {
$this->doRegister($scheme, $type);
}
}
}
public function register()
{
$this->registered = stream_get_wrappers();
foreach ($this->schemes as $scheme => $type) {
$this->doRegister($scheme, $type);
}
}
protected function doRegister($scheme, $type)
{
if (in_array($scheme, $this->registered)) {
stream_wrapper_unregister($scheme);
}
if (!stream_wrapper_register($scheme, $type)) {
throw new \InvalidArgumentException("Stream
'{$type}' could not be initialized.");
}
}
}
PKO[�[����WWGantry/GantryTrait.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Gantry;
use Gantry\Framework\Gantry;
trait GantryTrait
{
/**
* @var Gantry
*/
private static $gantry;
/**
* Get global Gantry instance.
*
* @return Gantry
*/
public static function gantry()
{
// We cannot set variable directly for the trait as it doesn't
work in HHVM.
if (!self::$gantry) {
self::$gantry = Gantry::instance();
}
return self::$gantry;
}
}
PKO[�[�;o�Gettext/Gettext.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Gettext;
/**
* Class Gettext
* @package Gantry\Component\Gettext
*
* Examples on translating gettext in twig:
*
* {% trans string_var %}
* http://twig.sensiolabs.org/doc/extensions/i18n.html
*
* {% trans %}Hello {{ author.name }}{% endtrans %}
* http://symfony.com/doc/current/book/translation.html
*
* {{ 'Hello %name%'|trans({'%name%': name}) }}
* {{ trans('Hello %name%', {'%name%': name}) }}
*/
class Gettext
{
public $pos = 0;
public $str;
public $len;
public $endian = 'V';
public function parse($string)
{
$this->str = $string;
$this->len = strlen($string);
$magic = self::readInt() & 0xffffffff;
if ($magic === 0x950412de) {
// Low endian.
$this->endian = 'V';
} elseif ($magic === 0xde120495) {
// Big endian.
$this->endian = 'N';
} else {
throw new \Exception('Not a Gettext file (.mo)');
}
// Skip revision number.
self::readInt();
// Total count.
$total = self::readInt();
// Offset of original table.
$originals = self::readInt();
// Offset of translation table.
$translations = self::readInt();
$this->seek($originals);
$table_originals = self::readIntArray($total * 2);
$this->seek($translations);
$table_translations = self::readIntArray($total * 2);
$items = [];
for ($i = 0; $i < $total; $i++) {
$this->seek($table_originals[$i * 2 + 2]);
$original = $this->read($table_originals[$i * 2 + 1]);
if ($original) {
$this->seek($table_translations[$i * 2 + 2]);
$items[$original] = $this->read($table_translations[$i *
2 + 1]);
}
}
return $items;
}
/**
* @return int
*/
protected function readInt()
{
$read = $this->read(4);
if ($read === false) {
return false;
}
$read = unpack($this->endian, $read);
return array_shift($read);
}
/**
* @param $count
* @return array
*/
protected function readIntArray($count)
{
return unpack($this->endian . $count, $this->read(4 *
$count));
}
/**
* @param $bytes
* @return string
*/
private function read($bytes)
{
$data = substr($this->str, $this->pos, $bytes);
$this->seek($this->pos + $bytes);
return $data;
}
/**
* @param $pos
* @return mixed
*/
private function seek($pos)
{
$this->pos = max($this->len, $pos);
return $this->pos;
}
}
PKO[�[�xх����Layout/Layout.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout;
use Gantry\Component\Config\Config;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Outlines;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccess;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
use RocketTheme\Toolbox\ArrayTraits\Iterator;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Layout
*/
class Layout implements \ArrayAccess, \Iterator, ExportInterface
{
use ArrayAccess, Iterator, Export;
const VERSION = 7;
protected static $instances = [];
protected static $indexes = [];
protected $layout = ['wrapper', 'container',
'section', 'grid', 'block',
'offcanvas'];
public $name;
public $timestamp = 0;
public $preset = [];
public $equalized = [3 => 33.3, 6 => 16.7, 7 => 14.3, 8 =>
12.5, 9 => 11.1, 11 => 9.1, 12 => 8.3];
protected $exists;
protected $items;
protected $references;
protected $parents;
protected $blocks;
protected $types;
protected $inherit;
/**
* @return array
*/
public static function presets()
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
/** @var UniformResourceIterator $iterator */
$iterator = $locator->getIterator(
'gantry-layouts://',
UniformResourceIterator::CURRENT_AS_SELF |
UniformResourceIterator::UNIX_PATHS | UniformResourceIterator::SKIP_DOTS
);
$files = [];
/** @var UniformResourceIterator $info */
foreach ($iterator as $info) {
$name = $info->getBasename('.yaml');
if (!$info->isFile() || $info->getExtension() !==
'yaml' || $name[0] === '.') {
continue;
}
$files[] = $name;
}
sort($files);
$results = ['user' => [], 'system' =>
[]];
foreach ($files as $preset) {
$scope = $preset && $preset[0] !== '_' ?
'user' : 'system';
$results[$scope][$preset] =
ucwords(trim(preg_replace(['|_|', '|/|'], ['
', ' / '], $preset)));
}
return $results;
}
/**
* @param string $name
* @return array
* @throws \RuntimeException
*/
public static function preset($name)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$filename =
$locator->findResource("gantry-layouts://{$name}.yaml");
if (!$filename) {
throw new \RuntimeException(sprintf("Preset '%s'
not found", $name), 404);
}
$layout = LayoutReader::read($filename);
$layout['preset']['name'] = $name;
$layout['preset']['timestamp'] =
filemtime($filename);
return $layout;
}
/**
* @param string $name
* @return Layout
*/
public static function instance($name)
{
if (!isset(static::$instances[$name])) {
static::$instances[$name] = static::load($name);
}
return static::$instances[$name];
}
/**
* @param string $name
* @return Layout
*/
public static function index($name)
{
if (!isset(static::$indexes[$name])) {
static::$indexes[$name] = static::loadIndex($name, true);
}
return static::$indexes[$name];
}
/**
* @param string $name
* @param array $items
* @param array $preset
*/
public function __construct($name, array $items = null, array $preset =
null)
{
$this->name = $name;
$this->items = (array) $items;
$this->exists = $items !== null;
// Add preset data from the layout.
if ($preset) {
$this->preset = $preset;
} elseif (isset($this->items['preset'])) {
$this->preset = (array) $this->items['preset'];
}
unset($this->items['preset']);
$this->preset += [
'name' => '',
'timestamp' => 0,
'image' =>
'gantry-admin://images/layouts/default.png'
];
}
/**
* @return bool
*/
public function exists()
{
return $this->exists;
}
/**
* Initialize layout.
*
* @param bool $force
* @param bool $inherit
* @return $this
*/
public function init($force = false, $inherit = true)
{
if ($force || $this->references === null) {
$this->initReferences();
if ($inherit) {
$this->initInheritance();
}
}
return $this;
}
/**
* Build separate meta-information from the layout.
*
* @return array
*/
public function buildIndex()
{
return [
'name' => $this->name,
'timestamp' => $this->timestamp,
'version' => static::VERSION,
'preset' => $this->preset,
'positions' => $this->positions(),
'sections' => $this->sections(),
'particles' => $this->particles(),
'inherit' => $this->inherit()
];
}
/**
* @return $this
*/
public function clean()
{
$this->references = null;
$this->types = null;
$this->inherit = null;
$this->cleanLayout($this->items);
return $this;
}
/**
* @param string $old
* @param string $new
* @param array $ids
* @return $this
*/
public function updateInheritance($old, $new = null, $ids = null)
{
$this->init();
$inherit = $this->inherit();
if (!empty($inherit[$old])) {
foreach ($inherit[$old] as $id => $inheritId) {
$element = $this->find($id, false);
if ($element) {
$inheritId = isset($element->inherit->particle) ?
$element->inherit->particle : $id;
if ($new && ($ids === null ||
isset($ids[$inheritId]))) {
// Add or modify inheritance.
if (!isset($element->inherit)) {
$element->inherit = new \stdClass;
}
$element->inherit->outline = $new;
} else {
// Remove inheritance.
$element->inherit = new \stdClass;
unset($this->inherit[$element->id]);
}
} else {
// Element does not exist anymore, remove its
reference.
unset($this->inherit[$id]);
}
}
}
return $this;
}
/**
* Save layout.
*
* @param bool $cascade
* @return $this
*/
public function save($cascade = true)
{
if (!$this->name) {
throw new \LogicException('Cannot save unnamed
layout');
}
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage("Saving layout for outline
{$this->name}");
$name = strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $this->name));
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// If there are atoms in the layout, copy them into outline
configuration.
$atoms = $this->atoms();
if (is_array($atoms) && $cascade) {
// Save layout into custom directory for the current theme.
$filename =
$locator->findResource("gantry-config://{$name}/page/head.yaml",
true, true);
$file = YamlFile::instance($filename);
$config = new Config($file->content());
$file->save($config->set('atoms',
json_decode(json_encode($atoms), true))->toArray());
$file->free();
}
// Remove atoms from the layout.
foreach ($this->items as $key => $section) {
if ($section->type === 'atoms') {
unset ($this->items[$key]);
}
}
// Make sure that base outline never uses inheritance.
if ($name === 'default') {
$this->inheritNothing();
}
$filename =
$locator->findResource("gantry-config://{$name}/layout.yaml",
true, true);
$file = CompiledYamlFile::instance($filename);
$file->settings(['inline' => 20]);
$file->save(LayoutReader::store($this->preset,
$this->items));
$file->free();
$this->timestamp = $file->modified();
$this->exists = true;
static::$instances[$this->name] = $this;
return $this;
}
public function export()
{
return LayoutReader::store($this->preset, $this->items);
}
/**
* Save index.
*
* @return $this
*/
public function saveIndex($index = null)
{
if (!$this->name) {
throw new \LogicException('Cannot save unnamed
layout');
}
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage("Saving layout index for outline
{$this->name}");
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$filename =
$locator->findResource("gantry-config://{$this->name}/index.yaml",
true, true);
$cache =
$locator->findResource("gantry-cache://{$this->name}/compiled/yaml",
true, true);
$file = CompiledYamlFile::instance($filename);
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will check this in a
bit.
}
$index = $index ? $index : $this->buildIndex();
// If file wasn't already locked by another process, save it.
if ($file->locked() !== false) {
$file->setCachePath($cache)->settings(['inline'
=> 20]);
$file->save($index);
$file->unlock();
}
$file->free();
static::$indexes[$this->name] = $index;
return $this;
}
/**
* @return array
*/
public function getLayoutTypes()
{
return $this->layout;
}
/**
* @param string $type
* @return bool
*/
public function isLayoutType($type)
{
return in_array($type, $this->layout, true);
}
/**
* @param $id
* @return string|null
*/
public function getParentId($id)
{
return isset($this->parents[$id]) ? $this->parents[$id] :
null;
}
/**
* @return array
*/
public function references()
{
$this->init();
return $this->references;
}
/**
* @param string $type
* @param string $subtype
* @return array
*/
public function referencesByType($type = null, $subtype = null)
{
$this->init();
if (!$type) {
return $this->types;
}
if (!$subtype) {
return isset($this->types[$type]) ? $this->types[$type] :
[];
}
return isset($this->types[$type][$subtype]) ?
$this->types[$type][$subtype] : [];
}
/**
* Return list of positions (key) with their titles (value).
*
* @return array Array of position => title
*/
public function positions()
{
$positions = $this->referencesByType('position',
'position');
$list = [];
foreach($positions as $position) {
if (!isset($position->attributes->key)) {
continue;
}
$list[$position->attributes->key] = $position->title;
}
return $list;
}
/**
* Return list of positions (key) with their titles (value).
*
* @return array Array of position => title
*/
public function sections()
{
$list = [];
foreach ($this->referencesByType('section') as $type
=> $sections) {
foreach ($sections as $id => $section) {
$list[$id] = $section->title;
}
}
foreach ($this->referencesByType('offcanvas') as $type
=> $sections) {
foreach ($sections as $id => $section) {
$list[$id] = $section->title;
}
}
return $list;
}
/**
* Return list of particles with their titles.
*
* @param bool $grouped If true, group particles by type.
* @return array Array of position => title
*/
public function particles($grouped = true)
{
$blocks = $this->referencesByType('block',
'block');
$list = [];
foreach ($blocks as $blockId => $block) {
if (!empty($block->children)) {
foreach ($block->children as $id => $particle) {
if (!empty($particle->layout) ||
in_array($particle->type, $this->layout, true)) {
continue;
}
if ($grouped) {
$list[$particle->subtype][$particle->id] =
$particle->title;
} else {
$list[$particle->id] = $particle->title;
}
}
}
}
return $list;
}
/**
* @param string $outline
* @return array
*/
public function inherit($outline = null)
{
$this->init();
$list = [];
foreach ($this->inherit as $name => $item) {
if (isset($item->inherit->outline)) {
if (isset($item->inherit->particle)) {
$list[$item->inherit->outline][$name] =
$item->inherit->particle;
} else {
$list[$item->inherit->outline][$name] = $name;
}
}
}
return $outline ? (!empty($list[$outline]) ? $list[$outline] : [])
: $list;
}
/**
* Return atoms from the layout.
*
* @return array|null
* @deprecated
*/
public function atoms()
{
$list = null;
$atoms = array_filter($this->items, function ($section) {
return $section->type === 'atoms' &&
!empty($section->children);
});
$atoms = array_shift($atoms);
if (!empty($atoms->children)) {
$list = [];
foreach ($atoms->children as $grid) {
if (!empty($grid->children)) {
foreach ($grid->children as $block) {
if (isset($block->children[0])) {
$item = $block->children[0];
$list[] = ['title' =>
$item->title, 'type' => $item->subtype,
'attributes' => $item->attributes];
}
}
}
}
}
return $list;
}
/**
* @param string $id
* @param bool $createIfNotExists
* @return object
*/
public function find($id, $createIfNotExists = true)
{
$this->init();
if (!isset($this->references[$id])) {
return $createIfNotExists ? (object)['id' => $id,
'inherit' => new \stdClass] : null;
}
return $this->references[$id];
}
/**
* @param string $id
* @return null
*/
public function block($id)
{
$this->init();
return isset($this->blocks[$id]) ? $this->blocks[$id] : null;
}
public function clearSections()
{
$this->items = $this->clearChildren($this->items);
return $this;
}
protected function clearChildren(&$items)
{
foreach ($items as $key => $item) {
if (!empty($item->children)) {
$this->children =
$this->clearChildren($item->children);
}
if (empty($item->children) &&
in_array($item->type, ['grid', 'block',
'particle', 'position', 'spacer',
'system'], true)) {
unset($items[$key]);
}
}
return array_values($items);
}
public function copySections(array $old)
{
$this->init();
/** @var Layout $old */
$old = new static('tmp', $old);
$leftover = [];
// Copy normal sections.
$data = $old->referencesByType('section');
if (isset($this->types['section'])) {
$sections = $this->types['section'];
$this->copyData($data, $sections, $leftover);
}
// Copy offcanvas.
$data = $old->referencesByType('offcanvas');
if (isset($this->types['offcanvas'])) {
$offcanvas = $this->types['offcanvas'];
$this->copyData($data, $offcanvas, $leftover);
}
// Copy atoms.
$data = $old->referencesByType('atoms');
if (isset($this->types['atoms'])) {
$atoms = $this->types['atoms'];
$this->copyData($data, $atoms, $leftover);
}
return $leftover;
}
public function inheritAll()
{
foreach ($this->references() as $item) {
if (!empty($item->inherit->outline)) {
continue;
}
if (!$this->isLayoutType($item->type)) {
$item->inherit = (object) ['outline' =>
$this->name, 'include' => ['attributes',
'block']];
} elseif ($item->type === 'section' ||
$item->type === 'offcanvas') {
$item->inherit = (object) ['outline' =>
$this->name, 'include' => ['attributes',
'block', 'children']];
}
}
$this->init(true);
return $this;
}
public function inheritNothing()
{
foreach ($this->references() as $item) {
unset($item->inherit);
}
$this->init(true);
return $this;
}
protected function copyData(array $data, array $sections, array
&$leftover)
{
foreach ($data as $type => $items) {
foreach ($items as $item) {
$found = false;
if (isset($sections[$type])) {
foreach ($sections[$type] as $section) {
if ($section->id === $item->id) {
$found = true;
$section->inherit =
$this->cloneData($item->inherit);
$section->children =
$this->cloneData($item->children);
break;
}
}
}
if (!$found && !empty($item->children)) {
$leftover[$item->id] = $item->title;
}
}
}
}
/**
* Clone data which consists mixed set of arrays and stdClass objects.
*
* @param mixed $data
* @return mixed
*/
protected function cloneData($data)
{
if (!($isObject = is_object($data)) && !is_array($data)) {
return $data;
}
$clone = [];
foreach((array) $data as $key => $value) {
if (is_object($value) || is_array($value)) {
$clone[$key] = $this->cloneData($value);
} else {
$clone[$key] = $value;
}
}
return $isObject ? (object) $clone : $clone;
}
/**
* @param array $items
*/
protected function cleanLayout(array $items)
{
foreach ($items as $item) {
if (!empty($item->inherit->include)) {
$include = $item->inherit->include;
foreach ($include as $part) {
switch ($part) {
case 'attributes':
$item->attributes = new \stdClass();
break;
case 'block':
break;
case 'children':
$item->children = [];
break;
}
}
}
if (!empty($item->children)) {
$this->cleanLayout($item->children);
}
}
}
protected function initInheritance()
{
$index = null;
if ($this->name) {
$index = static::loadIndexFile($this->name);
}
$inheriting = $this->inherit();
if (GANTRY_DEBUGGER && $inheriting) {
\Gantry\Debugger::addMessage(sprintf("Layout from outline
%s inherits %s", $this->name, implode(", ",
array_keys($inheriting))));
}
foreach ($inheriting as $outlineId => $list) {
try {
$outline = $this->instance($outlineId);
} catch (\Exception $e) {
// Outline must have been deleted.
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage("Outline {$outlineId} is missing /
deleted", 'error');
$outline = null;
}
foreach ($list as $id => $inheritId) {
$item = $this->find($id);
$inheritId = !empty($item->inherit->particle) ?
$item->inherit->particle : $id;
$inherited = $outline ? $outline->find($inheritId) :
null;
$include = !empty($item->inherit->include) ? (array)
$item->inherit->include : [];
foreach ($include as $part) {
switch ($part) {
case 'attributes':
// Deep clone attributes.
$item->attributes =
isset($inherited->attributes) ?
$this->cloneData($inherited->attributes) : new \stdClass();
break;
case 'block':
$block = $this->block($id);
if (isset($block->attributes)) {
$inheritBlock = $outline ?
$this->cloneData($outline->block($inheritId)) : null;
$blockAttributes = $inheritBlock ?
array_diff_key((array)$inheritBlock->attributes, ['fixed'
=> 1, 'size' => 1]) : [];
$block->attributes =
(object)($blockAttributes + (array)$block->attributes);
}
break;
case 'children':
if (!empty($inherited->children)) {
// Deep clone children.
$item->children =
$this->cloneData($inherited->children);
$this->initReferences($item->children, $this->getParentId($id),
null,
['outline' => $outlineId,
'include' => ['attributes', 'block']],
$index);
} else {
$item->children = [];
}
break;
}
}
if (!$outline || !isset($inherited->attributes)) {
// Remove inheritance information if outline
doesn't exist.
$item->inherit = new \stdClass;
unset($this->inherit[$item->id]);
}
}
}
}
/**
* @param array $items
* @param object $parent
* @param object $block
* @param string $inherit
* @param array $index
*/
protected function initReferences(array $items = null, $parent = null,
$block = null, $inherit = null, array $index = null)
{
if ($items === null) {
$items = $this->items;
$this->references = [];
$this->types = [];
$this->inherit = [];
}
foreach ($items as $item) {
if (is_object($item)) {
$type = $item->type;
$subtype = !empty($item->subtype) ? $item->subtype :
$type;
if ($block) {
$this->parents[$item->id] = $parent;
}
if ($block) {
$this->blocks[$item->id] = $block;
}
if ($inherit && !$this->isLayoutType($type)) {
$item->inherit = (object) $inherit;
$item->inherit->particle = $item->id;
if
(isset($index['inherit'][$item->inherit->outline])
&& ($newId = array_search($item->id,
$index['inherit'][$item->inherit->outline], true))) {
$item->id = $newId;
} else {
$item->id = $this->id($type, $subtype);
}
}
if (isset($item->id)) {
if (isset($this->references[$item->id])) {
if ($type === 'block' || $type ===
'grid') {
$item->id = $this->id($type, $subtype);
}
// elseif (null === $inherit) {
// throw new \RuntimeException('Layout
reference conflict on #' . $item->id);
// }
}
$this->references[$item->id] = $item;
$this->types[$type][$subtype][$item->id] = $item;
if (!empty($item->inherit->outline)) {
$this->inherit[$item->id] = $item;
}
} else {
$this->types[$type][$subtype][] = $item;
}
if (isset($item->children) &&
is_array($item->children)) {
$this->initReferences($item->children, $type ===
'section' ? $item : $parent, $type === 'block' ? $item
: null, $inherit, $index);
}
}
}
}
/**
* @param string $type
* @param string $subtype
* @param string $id
* @return string
*/
protected function id($type, $subtype = null, $id = null)
{
$result = [];
if ($type !== 'particle') {
$result[] = $type;
}
if ($subtype && ($subtype !== $type || $subtype ===
'position')) {
$result[] = $subtype;
}
$key = implode('-', $result);
$key_id = $key . '-'. $id;
if (!$id || isset($this->references[$key_id])) {
while ($id = rand(1000, 9999)) {
$key_id = $key . '-'. $id;
if (!isset($this->references[$key_id])) {
break;
}
}
}
return $key_id;
}
/**
* Prepare block width sizes.
*
* @return $this
*/
public function prepareWidths()
{
$this->init();
$this->calcWidths($this->items);
return $this;
}
/**
* Recalculate block widths.
*
* @param array $items
* @internal
*/
protected function calcWidths(array &$items)
{
foreach ($items as $i => $item) {
if (empty($item->children)) {
continue;
}
$this->calcWidths($item->children);
$dynamicSize = 0;
$fixedSize = 0;
$childrenCount = 0;
foreach ($item->children as $child) {
if ($child->type !== 'block') {
continue;
}
$childrenCount++;
if (!isset($child->attributes->size)) {
$child->attributes->size = 100 /
count($item->children);
}
if (empty($child->attributes->fixed)) {
$dynamicSize += $child->attributes->size;
} else {
$fixedSize += $child->attributes->size;
}
}
if (!$childrenCount) {
continue;
}
$roundSize = round($dynamicSize, 1);
$equalized = isset($this->equalized[$childrenCount]) ?
$this->equalized[$childrenCount] : 0;
// force-casting string for testing comparison due to weird PHP
behavior that returns wrong result
if ($roundSize !== 100 && (string) $roundSize !==
(string) ($equalized * $childrenCount)) {
$fraction = 0;
$multiplier = (100 - $fixedSize) / ($dynamicSize ?: 1);
foreach ($item->children as $child) {
if ($child->type !== 'block') {
continue;
}
if (!empty($child->attributes->fixed)) {
continue;
}
// Calculate size for the next item by taking account
the rounding error from the last item.
// This will allow us to approximate cumulating error
and fix it when rounding error grows
// over the rounding treshold.
$size = ($child->attributes->size * $multiplier)
+ $fraction;
$newSize = round($size);
$fraction = $size - $newSize;
$child->attributes->size = $newSize;
}
}
}
}
/**
* @param string $name
* @param string $preset
* @return static
*/
public static function load($name, $preset = null)
{
if (!$name) {
throw new \BadMethodCallException('Layout needs to have a
name');
}
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$layout = null;
$filename =
$locator("gantry-config://{$name}/layout.yaml");
// If layout file doesn't exists, figure out what preset was
used.
if (!$filename) {
// Attempt to load the index file.
$indexFile =
$locator("gantry-config://{$name}/index.yaml");
if ($indexFile || !$preset) {
$index = static::loadIndex($name, true);
$preset = $index['preset']['name'];
}
try {
$layout = static::preset($preset);
} catch (\Exception $e) {
// Layout doesn't exist, do nothing.
}
} else {
$layout = LayoutReader::read($filename);
}
return new static($name, $layout);
}
protected static function loadIndexFile($name)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Attempt to load the index file.
$indexFile =
$locator("gantry-config://{$name}/index.yaml");
if ($indexFile) {
$file = CompiledYamlFile::instance($indexFile);
$index = (array)$file->content();
$file->free();
} else {
$index = [];
}
return $index;
}
/**
* @param string $name
* @param bool $autoSave
* @return array
*/
public static function loadIndex($name, $autoSave = false)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$index = static::loadIndexFile($name);
// Find out the currently used layout file.
$layoutFile =
$locator("gantry-config://{$name}/layout.yaml");
if (!$layoutFile) {
/** @var Outlines $outlines */
$outlines = $gantry['outlines'];
$preset = isset($index['preset']['name']) ?
$index['preset']['name'] : $outlines->preset($name);
}
// Get timestamp for the layout file.
$timestamp = $layoutFile ? filemtime($layoutFile) : 0;
// If layout index file doesn't exist or is not up to date,
rebuild it.
if (empty($index['timestamp']) ||
$index['timestamp'] != $timestamp ||
!isset($index['version']) || $index['version'] !=
static::VERSION) {
$layout = isset($preset) ? new static($name,
static::preset($preset)) : static::instance($name);
$layout->timestamp = $timestamp;
if ($autoSave) {
if (!$layout->timestamp) {
$layout->save();
}
$index = $layout->buildIndex();
$layout->saveIndex($index);
} else {
$index = $layout->buildIndex();
}
}
$index += [
'name' => $name,
'timestamp' => $timestamp,
'preset' => [
'name' => '',
'image' =>
'gantry-admin://images/layouts/default.png'
],
'positions' => [],
'sections' => [],
'inherit' => []
];
return $index;
}
public function check(array $children = null)
{
if ($children === null) {
$children = $this->items;
}
foreach ($children as $item) {
if (!$item instanceof \stdClass) {
throw new \RuntimeException('Invalid layout
element');
}
if (!isset($item->type)) {
throw new \RuntimeException('Type missing');
}
if (!isset($item->subtype)) {
throw new \RuntimeException('Subtype missing');
}
if (!isset($item->attributes)) {
throw new \RuntimeException('Attributes
missing');
}
if (!is_object($item->attributes)) {
throw new \RuntimeException('Attributes not
object');
}
if (isset($item->children)) {
if (!is_array($item->children)) {
throw new \RuntimeException('Children not
array');
}
$this->check($item->children);
}
}
}
}
PKO[�[.|�G
Layout/LayoutReader.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout;
use Gantry\Component\File\CompiledYamlFile;
/**
* Read layout from yaml file.
*/
class LayoutReader
{
/**
* Get layout version.
*
* @param array $data
* @return int
*/
public static function version(array &$data)
{
if (isset($data['version'])) {
return $data['version'];
}
return isset($data['children']) &&
is_array($data['children']) ? 0 : 1;
}
/**
* Make layout from array data.
*
* @param array $data
* @return array
*/
public static function data(array $data)
{
$version = static::version($data);
$reader = static::getClass($version, $data);
$result = $reader->load();
// Make sure that all preset values are set by defining defaults.
$result['preset'] += [
'name' => '',
'image' =>
'gantry-admin://images/layouts/default.png'
];
return $result;
}
/**
* Read layout from yaml file and return parsed version of it.
*
* @param string $file
* @return array
*/
public static function read($file)
{
if (!$file) {
return [];
}
$file = CompiledYamlFile::instance($file);
$content = (array) $file->content();
$file->free();
return static::data($content);
}
/**
* Convert layout into file format.
*
* @param array $preset
* @param array $structure
* @param int $version
* @return mixed
*/
public static function store(array $preset, array $structure, $version
= 2)
{
$reader = static::getClass($version);
return $reader->store($preset, $structure);
}
/**
* @param int $version
* @param array $data
* @return object
*/
protected static function getClass($version, array $data = [])
{
$class =
"Gantry\\Component\\Layout\\Version\\Format{$version}";
if (!class_exists($class)) {
throw new \RuntimeException('Layout file cound not be
read: unsupported version {$version}.');
}
return new $class($data);
}
}
PKO[�[Q�E���Layout/Version/Format0.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout\Version;
/**
* Read layout from Layout Manager yaml file.
*/
class Format0 extends Format1
{
/**
* @return array
*/
public function load()
{
$data = &$this->data;
$preset = isset($data['preset']) &&
is_array($data['preset']) ? $data['preset'] : [];
$result = is_array($data['children']) ?
$this->object($data['children']) : [];
$invisible = [
'offcanvas' =>
$this->parse('offcanvas', [], 0),
'atoms' => $this->parse('atoms', [],
0)
];
foreach ($result as $key => &$item) {
if (isset($invisible[$item->type])) {
$invisible[$item->type] = $item;
unset($result[$key]);
}
}
$result += $invisible;
$result = array_values($result);
return ['preset' => $preset] + $result;
}
protected function object(array $items, $container = true)
{
foreach ($items as &$item) {
$item = (object) $item;
if (isset($item->attributes) &&
(is_array($item->attributes) || is_object($item->attributes))) {
$item->attributes = (object) $item->attributes;
} else {
$item->attributes = (object) [];
}
if (!empty($item->children) &&
is_array($item->children)) {
$item->children = $this->object($item->children,
false);
}
$this->normalize($item, $container);
}
return $items;
}
}
PKQ[�[��+�#�#Layout/Version/Format1.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout\Version;
/**
* Read layout from simplified yaml file.
*/
class Format1
{
protected $scopes = [0 => 'grid', 1 =>
'block'];
protected $data;
protected $keys = [];
public function __construct(array $data)
{
$this->data = $data;
}
public function load()
{
$data = &$this->data;
// Check if we have preset.
$preset = [];
if (isset($data['preset']) &&
is_array($data['preset']) &&
isset($data['layout']) &&
is_array($data['layout'])) {
$preset = $data['preset'];
$data = $data['layout'];
}
// We have user entered file; let's build the layout.
// Two last items are always offcanvas and atoms.
$offcanvas = isset($data['offcanvas']) ?
$data['offcanvas'] : [];
$atoms = isset($data['atoms']) ? $data['atoms']
: [];
unset($data['offcanvas'], $data['atoms']);
$data['offcanvas'] = $offcanvas;
if ($atoms) {
$data['atoms'] = $atoms;
}
$result = [];
foreach ($data as $field => $params) {
$child = $this->parse($field, (array) $params, 0);
unset($child->size);
$result[] = $child;
}
return ['preset' => $preset] + $result;
}
public function store(array $preset, array $structure)
{
return ['preset' => $preset, 'children'
=> $structure];
}
protected function normalize(&$item, $container = false)
{
if ($item->type === 'pagecontent') {
// Update pagecontent to match the new standards.
$item->type = 'system';
if (!$item->subtype || $item->subtype ==
'pagecontent') {
$item->subtype = 'content';
$item->title = 'Page Content';
} else {
$item->subtype ='messages';
$item->title = 'System Messages';
}
}
if ($item->type === 'section') {
// Update section to match the new standards.
$section = strtolower($item->title);
$item->id = $section;
$item->subtype = (in_array($section, ['aside',
'nav', 'article', 'header',
'footer', 'main']) ? $section : 'section');
} elseif ($item->type === 'offcanvas') {
$item->id = $item->subtype = $item->type;
unset ($item->attributes->name,
$item->attributes->boxed);
return;
} else {
// Update all ids to match the new standards.
$item->id = $this->id($item->type, $item->subtype);
}
if (!empty($item->attributes->extra)) {
foreach ($item->attributes->extra as $i => $extra) {
$v = reset($extra);
$k = key($extra);
if ($k === 'id') {
$item->id = preg_replace('/^g-/',
'', $v);
$item->attributes->id = $v;
unset ($item->attributes->extra[$i]);
}
}
if (empty($item->attributes->extra)) {
unset ($item->attributes->extra);
}
}
$item->subtype = $item->subtype ?: $item->type;
$item->layout = in_array($item->type, ['container',
'section', 'grid', 'block',
'offcanvas']);
if (isset($item->attributes->boxed)) {
// Boxed already set, just change boxed=0 to boxed=''
to use default settings.
$item->attributes->boxed = $item->attributes->boxed
?: '';
return;
}
if (!$container) {
return;
}
// Update boxed model to match the new standards.
if (isset($item->children) && count($item->children)
=== 1) {
$child = reset($item->children);
if ($item->type === 'container') {
// Remove parent container only if the only child is a
section.
if ($child->type === 'section') {
$child->attributes->boxed = 1;
$item = $child;
}
$item->attributes->boxed = '';
} elseif ($child->type === 'container') {
// Remove child container.
$item->attributes->boxed = '';
$item->children = $child->children;
}
}
}
/**
* @param int|string $field
* @param array $content
* @param int $scope
* @param bool|null $container
* @return array
*/
protected function parse($field, array $content, $scope, $container =
true)
{
if (is_numeric($field)) {
// Row or block
$type = $this->scopes[$scope];
$result = (object) ['id' => null, 'type'
=> $type, 'subtype' => $type, 'layout' =>
true, 'attributes' => (object) []];
$scope = ($scope + 1) % 2;
} elseif (substr($field, 0, 9) == 'container') {
// Container
$type = 'container';
$result = (object) ['id' => null, 'type'
=> $type, 'subtype' => $type, 'layout' =>
true, 'attributes' => (object) []];
$id = substr($field, 10) ?: null;
if ($id !== null) {
$result->attributes->id = $id;
}
} else {
// Section
$list = explode(' ', $field, 2);
$field = array_shift($list);
$size = ((float) array_shift($list)) ?: null;
$type = in_array($field, ['atoms',
'offcanvas']) ? $field : 'section';
$subtype = in_array($field, ['aside',
'nav', 'article', 'header',
'footer', 'main']) ? $field : 'section';
$result = (object) [
'id' => null,
'type' => $type,
'subtype' => $subtype,
'layout' => true,
'title' => ucfirst($field),
'attributes' => (object) ['id' =>
'g-' . $field]
];
if ($size) {
$result->size = $size;
}
}
if (!empty($content)) {
$result->children = [];
foreach ($content as $child => $params) {
if (is_array($params)) {
$child = $this->parse($child, $params, $scope,
false);
} else {
$child = $this->resolve($params, $scope);
}
if (!empty($child->size)) {
$result->attributes->size = $child->size;
}
unset($child->size);
$result->children[] = $child;
}
}
$this->normalize($result, $container);
return $result;
}
/**
* @param string $field
* @param int $scope
* @return array
*/
protected function resolve($field, $scope)
{
$list = explode(' ', $field, 2);
$list2 = explode('-', array_shift($list), 2);
$size = ((float) array_shift($list)) ?: null;
$type = array_shift($list2);
$subtype = array_shift($list2) ?: false;
$title = ucfirst($subtype ?: $type);
$attributes = new \stdClass;
$attributes->enabled = 1;
if ($subtype && $type === 'position') {
$attributes->key = $subtype;
$subtype = false;
}
$result = (object) ['id' => $this->id($type,
$subtype), 'title' => $title, 'type' => $type,
'subtype' => $subtype, 'attributes' =>
$attributes];
$this->normalize($result);
if ($scope > 1) {
if ($size) {
$result->attributes->size = $size;
}
return $result;
}
if ($scope <= 1) {
$result = (object) ['id' =>
$this->id('block'), 'type' => 'block',
'subtype' => 'block', 'layout' => true,
'children' => [$result], 'attributes' => new
\stdClass];
if ($size) {
$result->attributes->size = $size;
}
}
if ($scope == 0) {
$result = (object) ['id' =>
$this->id('grid'), 'type' => 'grid',
'subtype' => 'grid', 'layout' => true,
'children' => [$result], 'attributes' => new
\stdClass];
}
return $result;
}
protected function id($type, $subtype = null)
{
if ($type === 'atoms') {
return $type;
}
$result = [];
if ($type !== 'particle' && $type !==
'atom') {
$result[] = $type;
}
if ($subtype && $subtype !== $type) {
$result[] = $subtype;
}
$key = implode('-', $result);
while ($id = rand(1000, 9999)) {
if (!isset($this->keys[$key][$id])) {
break;
}
}
$this->keys[$key][$id] = true;
return $key . '-'. $id;
}
}
PKQ[�[��]��E�ELayout/Version/Format2.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Layout\Version;
/**
* Read layout from simplified yaml file.
*/
class Format2
{
protected $scopes = [0 => 'grid', 1 =>
'block'];
protected $sections = ['wrapper', 'container',
'section', 'grid', 'block',
'offcanvas'];
protected $structures = ['div', 'section',
'aside', 'nav', 'article',
'header', 'footer', 'main'];
protected $data;
protected $structure;
protected $content;
protected $keys;
/**
* @param array $data
*/
public function __construct(array $data = [])
{
$this->data = $data;
}
/**
* @return array
*/
public function load()
{
$data = &$this->data;
// Parse layout.
$result = [];
foreach ($data['layout'] as $field => &$params) {
if (!is_array($params)) {
$params = [];
}
$child = $this->parse($field, $params);
unset($child->size);
$result[] = $child;
}
return ['preset' => $data['preset']] +
$result;
}
/**
* @param array $preset
* @param array $structure
* @return array
*/
public function store(array $preset, array $structure)
{
$this->structure = [];
$this->content = [];
$structure = ['children' =>
json_decode(json_encode($structure), true)];
$structure = $this->build($structure);
$result = [
'version' => 2,
'preset' => $preset,
'layout' => $structure
];
if ($this->structure) {
$result['structure'] = $this->structure;
}
if ($this->content) {
$result['content'] = $this->content;
}
return $result;
}
/**
* @param int|string $field
* @param array $content
* @param int $scope
* @param object $parent
* @return array
*/
protected function parse($field, array &$content, $scope = 0,
$parent = null)
{
if (is_numeric($field)) {
// Row or block
$result = (object)['id' =>
$this->id($this->scopes[$scope]), 'type' =>
$this->scopes[$scope], 'subtype' =>
$this->scopes[$scope], 'layout' => true,
'attributes' => (object)[]];
$scope = ($scope + 1) % 2;
} else {
list ($type, $subtype, $id, $size, $section_id, $boxed) =
$this->parseSectionString($field);
if ($type == 'grid') {
$scope = 1;
}
if ($type == 'block') {
$scope = 0;
}
// Build object.
$result =
isset($this->data['structure'][$section_id]) ? (array)
$this->data['structure'][$section_id] : [];
$result += [
'id' => $section_id,
'layout' => true,
'type' => $type,
'subtype' => $subtype,
'title' => $this->getTitle($type, $subtype,
$id),
'attributes' => []
];
if (isset($boxed) &&
!isset($result['attributes']['boxed'])) {
$result['attributes']['boxed'] =
$boxed;
}
if ($parent && $parent->type === 'block'
&& !empty($result['block'])) {
$parent->attributes = (object)
($result['block'] + (array) $parent->attributes);
}
unset ($result['block']);
$result = (object) $result;
$result->attributes = (object) $result->attributes;
if (isset($result->inherit)) {
$result->inherit = (object) $result->inherit;
}
if ($size) {
$result->size = $size;
}
if (($type === 'grid' || $type === 'block')
&& !isset($result->attributes->id)) {
$result->attributes->id = $section_id;
}
}
if (!empty($content)) {
$result->children = [];
foreach ($content as $child => &$params) {
if (!$params && !is_array($params)) {
$params = [];
}
if (is_array($params)) {
$child = $this->parse($child, $params, $scope,
$result);
} else {
$child = $this->resolve($params, $scope, $result);
}
if (!empty($child->size)) {
$result->attributes->size = $child->size;
}
unset($child->size);
$result->children[] = $child;
}
}
return $result;
}
/**
* @param string $field
* @param int $scope
* @param object $parent
* @return array
*/
protected function resolve($field, $scope, $parent)
{
list ($type, $subtype, $id, $size, $content_id) =
$this->parseContentString($field);
$title = $this->getTitle($type, $subtype, $id);
$result = isset($this->data['content'][$content_id]) ?
(array) $this->data['content'][$content_id] : [];
$result += ['id' => $this->id($type, $subtype,
$id), 'title' => $title, 'type' => $type,
'subtype' => $subtype, 'attributes' => []];
$result['attributes'] = (object)
($result['attributes'] + ['enabled' => 1]);
if (isset($result['inherit'])) {
$result['inherit'] = (object)
$result['inherit'];
}
if (isset($result['block'])) {
$block = $result['block'];
unset ($result['block']);
}
$result = (object) $result;
if ($type === 'position' &&
!isset($result->attributes->key) && !in_array($subtype,
['module', 'widget'])) {
$result->attributes->key = $id;
}
if ($scope > 1) {
if ($parent->type === 'block' &&
!empty($block)) {
$parent->attributes = (object) ($block + (array)
$parent->attributes);
}
if ($size) {
$result->attributes->size = $size;
}
}
if ($scope <= 1) {
$result = (object) ['id' =>
$this->id('block'), 'type' => 'block',
'subtype' => 'block', 'layout' => true,
'children' => [$result], 'attributes' => new
\stdClass];
if (!empty($block)) {
$result->attributes = (object) $block;
}
if ($size) {
$result->attributes->size = $size;
}
}
if ($scope == 0) {
$result = (object) ['id' =>
$this->id('grid'), 'type' => 'grid',
'subtype' => 'grid', 'layout' => true,
'children' => [$result], 'attributes' => new
\stdClass];
}
return $result;
}
/**
* @param array $content
* @return array|null
*/
protected function build(array &$content)
{
$result = [];
$ctype = isset($content['type']) ?
$content['type'] : null;
if (in_array($ctype, ['grid', 'block'])) {
if (empty($content['attributes']['id']) ||
$content['attributes']['id'] ===
$content['id']) {
unset ($content['attributes']['id']);
}
}
if ($ctype === 'block') {
if (empty($content['attributes']['extra']))
{
unset
($content['attributes']['extra']);
}
if (empty($content['attributes']['fixed']))
{
unset
($content['attributes']['fixed']);
}
}
if ($ctype === 'section') {
if (empty($content['attributes']['extra']))
{
unset
($content['attributes']['extra']);
}
}
if (!isset($content['children'])) {
$content['children'] = [];
}
unset ($content['layout']);
// Clean up all items for saving.
foreach ($content['children'] as &$child) {
$size = null;
$id = $child['id'];
$type = $child['type'];
$subtype = $child['subtype'];
$isSection = in_array($type, $this->sections);
if (empty($child['inherit']['outline']) ||
empty($child['inherit']['include'])) {
unset ($child['inherit']);
} else {
foreach ($child['inherit']['include']
as $include) {
switch ($include) {
case 'attributes':
unset($child['attributes']);
break;
case 'block':
if ($ctype === 'block') {
// Keep block size and fixed status.
$attributes =
!empty($content['attributes']) ? $content['attributes']
: [];
$content['attributes'] =
array_intersect_key($attributes, ['fixed' => 1,
'size' => 1]);
}
break;
case 'children':
$child['children'] = [];
break;
}
}
}
if (!$isSection) {
// Special handling for positions.
if ($type === 'position') {
// TODO: we may want to simplify position id, but we
need to take into account multiple instances of the same position key.
/*
if (!$subtype || $subtype === 'position') {
$id = 'position-' .
(isset($child['attributes']['key']) ?
$child['attributes']['key'] : rand(1000,9999));
unset
($child['attributes']['key']);
}
*/
unset
($child['attributes']['title']);
}
$value = $id;
if
(!empty($child['attributes']['enabled'])) {
unset
($child['attributes']['enabled']);
}
} else {
// Recursively handle structure.
$value = $this->build($child);
}
// Clean up defaults.
if (empty($child['title']) ||
$child['title'] === 'Untitled' ||
$child['title'] === $this->getTitle($type, $subtype, $id)) {
unset ($child['title']);
}
if (!$subtype || $subtype === $type) {
unset ($child['subtype']);
}
// Remove id and children as we store data in flat structure
with id being the key.
unset ($child['id'], $child['children']);
if ($type === 'offcanvas' &&
isset($child['attributes']['name'])) {
unset ($child['attributes']['name']);
}
if ($ctype === 'block') {
// Embed size into array key/value.
if
(isset($content['attributes']['size']) &&
$content['attributes']['size'] != 100) {
$size =
$content['attributes']['size'];
}
unset ($content['attributes']['size']);
// Embed parent block.
if (!empty($content['attributes'])) {
$child['block'] =
$content['attributes'];
unset ($content['attributes']);
}
}
if (isset($child['attributes']['size'])) {
if ($child['attributes']['size'] != 100
&& is_string($value)) {
$size =
$child['attributes']['size'];
}
unset ($child['attributes']['size']);
}
// Remove attributes if there aren't any.
if (empty($child['attributes'])) {
unset ($child['attributes']);
}
// Special handling for grid and block elements.
if (in_array($type, ['grid', 'block'])
&& count($child) === 1 && isset($child['type']))
{
$id = null;
}
// Check if type and subtype can be generated from the id.
if ($subtype &&
(preg_match("/^{$type}-{$subtype}(-|$)/", $id))
|| (in_array($type, ['section',
'particle']) &&
preg_match("/^{$subtype}(-|$)/", $id))) {
unset ($child['type'],
$child['subtype']);
} elseif (preg_match("/^{$type}(-|$)/", $id)) {
unset ($child['type']);
}
// Add item configuration if not empty.
if ($id && !empty($child)) {
if (!is_string($value)) {
$this->structure[$id] = $child;
} else {
$this->content[$id] = $child;
}
}
// Add item to the layout.
if (!is_string($value)) {
// Add structural item.
if ($id) {
// Sections and other complex items.
$id =
isset($child['attributes']['boxed']) ?
"/{$id}/" : $id;
$result[trim("{$id} {$size}")] = $value;
} elseif (!empty($value)) {
// Simple grid / block item.
$result[] = $value;
}
} else {
// Add content item.
$result[] = trim("{$value} {$size}");
}
}
// TODO: maybe collapse grid as well?
if ($ctype && in_array($ctype, ['block'])
&& count($result) <= 1 && key($result) === 0) {
unset ($this->structure[$content['id']]);
return reset($result) ?: null;
}
return $result;
}
/**
* @param string $string
* @return array
*/
protected function parseSectionString($string)
{
// Extract: "[section-id] [size]".
$list = explode(' ', $string, 2);
$section_id = array_shift($list);
$size = ((float) array_shift($list)) ?: null;
// Extract slashes from "/[section-id]/".
$boxedLeft = $section_id[0] === '/';
$boxedRight = $section_id[strlen($section_id)-1] === '/';
$boxed = ($boxedLeft && $boxedRight ? '' :
($boxedLeft ? '1' : ($boxedRight ? '0' : null)));
$section_id = trim($section_id, '/');
// Extract section id if it exists: "[section]-[id]".
$list = explode('-', $section_id, 2);
// Get section and its type.
$section = reset($list);
$type = (in_array($section, $this->sections)) ? $section :
'section';
$subtype = ($type !== 'section' || in_array($section,
$this->structures)) ? $section : 'section';
// Extract id.
if ($type == 'section' && in_array($section,
$this->structures)) {
$id = array_pop($list);
} else {
$id = $section_id;
}
return [$type, $subtype, $id, $size, $section_id, $boxed];
}
/**
* @param string $string
* @return array
*/
protected function parseContentString($string)
{
// Extract: "[type-subtype] [size]".
$list = explode(' ', $string, 2);
$content_id = array_shift($list);
$size = ((float) array_shift($list)) ?: null;
// Extract sub-type if it exists:
"[type]-[subtype]-[id]".
$list = explode('-', $content_id);
// Get type, subtype and id.
$type = reset($list);
$test = end($list);
$id = ((string)(int) $test === (string) $test) ? array_pop($list) :
null;
if (in_array($type, ['system', 'position',
'particle', 'spacer'])) {
array_shift($list);
} else {
$type = 'particle';
}
$subtype = implode('-', $list);
if ($type === 'position' && !in_array($subtype,
['module', 'widget'])) {
$id = ($subtype ?: $type) . ($id !== null ? "-{$id}"
: '');
$subtype = 'position';
}
return [$type, $subtype ?: $type, $id, $size, $content_id];
}
/**
* @param string $type
* @param string $subtype
* @param string $id
* @return string
*/
protected function getTitle($type, $subtype, $id)
{
if (in_array($type, $this->sections)) {
if ($type === 'offcanvas') {
return 'Offcanvas';
}
if ($type === 'grid' || $type === 'block')
{
return null;
}
return ucfirst((string)(int) $id === (string) $id ? ($subtype
?: $type) . "-{$id}" : $id);
}
if ($type === 'position' && !in_array($subtype,
['module', 'widget'])) {
return
ucfirst(preg_replace('/^position-(.*?[a-z])/ui', '\1',
$id));
}
if ($type === 'system') {
if ($subtype === 'messages') {
return 'System Messages';
}
if ($subtype === 'content') {
return 'Page Content';
}
}
return ucfirst($subtype ?: $type);
}
/**
* @param string $type
* @param string $subtype
* @param string $id
* @return string
*/
protected function id($type, $subtype = null, $id = null)
{
$result = [];
if ($type !== 'particle') {
$result[] = $type;
}
if ($subtype && $subtype !== $type) {
$result[] = $subtype;
}
$key = implode('-', $result);
if (!$id || isset($this->keys[$key][$id])) {
while ($id = rand(1000, 9999)) {
if (!isset($this->keys[$key][$id])) {
break;
}
}
}
$this->keys[$key][$id] = true;
return $key . '-'. $id;
}
}
PKQ[�[j픞--Menu/AbstractMenu.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Menu;
use Gantry\Component\Config\Config;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Gantry\GantryTrait;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters;
use RocketTheme\Toolbox\ArrayTraits\Countable;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\Iterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
abstract class AbstractMenu implements \ArrayAccess, \Iterator, \Countable
{
use GantryTrait, ArrayAccessWithGetters, Iterator, Export, Countable;
protected $default;
protected $base;
protected $active;
protected $params;
protected $override = false;
protected $config;
/**
* @var array|Item[]
*/
protected $items;
/**
* @var Config|null
*/
protected $pathMap;
protected $defaults = [
'menu' => '',
'base' => '/',
'startLevel' => 1,
'maxLevels' => 0,
'showAllChildren' => true,
'highlightAlias' => true,
'highlightParentAlias' => true
];
abstract public function __construct();
/**
* Return list of menus.
*
* @return array
*/
abstract public function getMenus();
/**
* Return default menu.
*
* @return string
*/
public function getDefaultMenuName()
{
return null;
}
/**
* Returns true if the platform implements a Default menu.
*
* @return boolean
*/
public function hasDefaultMenu()
{
return false;
}
/**
* Return active menu.
*
* @return string
*/
public function getActiveMenuName()
{
return null;
}
/**
* Returns true if the platform implements an Active menu.
*
* @return boolean
*/
public function hasActiveMenu()
{
return false;
}
/**
* @param array $params
* @param Config $menu
* @return AbstractMenu
*/
public function instance(array $params = [], Config $menu = null)
{
$params = $params + $this->defaults;
$menus = $this->getMenus();
if (!$menus) {
throw new \RuntimeException('Site does not have
menus', 404);
}
if (empty($params['menu'])) {
$params['menu'] = $this->getDefaultMenuName();
if (!$params['menu'] &&
!empty($params['admin'])) {
// In admin just select the first menu if there isn't
default menu to be selected.
$params['menu'] = reset($menus);
};
} elseif ($params['menu'] == '-active-') {
$params['menu'] = $this->getActiveMenuName();
}
if (!$params['menu']) {
throw new \RuntimeException('No menu selected', 404);
}
if (!in_array($params['menu'], $menus)) {
throw new \RuntimeException('Menu not found', 404);
}
$instance = clone $this;
$instance->params = $params;
if ($menu) {
$instance->override = true;
$instance->config = $menu;
} else {
$instance->config = null;
}
$config = $instance->config();
$items = isset($config['items']) ?
$config['items'] : [];
// Create menu structure.
$instance->init($params);
// Get menu items from the system (if not specified otherwise).
if ($config->get('settings.type') !==
'custom') {
$instance->getList($params, $items);
}
// Add custom menu items.
$instance->addCustom($params, $items);
// Sort menu items.
$instance->sortAll();
return $instance;
}
/**
* Get menu configuration.
*
* @return Config
*/
public function config()
{
if (!$this->config) {
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$menu = $this->params['menu'];
$file =
CompiledYamlFile::instance($locator("gantry-config://menu/{$menu}.yaml"));
$this->config = new Config($file->content());
$this->config->def('settings.title',
ucfirst($menu));
$file->free();
}
return $this->config;
}
public function name()
{
return $this->params['menu'];
}
public function root()
{
return $this->offsetGet('');
}
public function ordering()
{
$list = [];
foreach ($this->items as $name => $item) {
$groups = $item->groups();
if (count($groups) == 1 && empty($groups[0])) {
continue;
}
$list[$name] = [];
foreach ($groups as $col => $children) {
$list[$name][$col] = [];
foreach ($children as $child) {
$list[$name][$col][] = $child->path;
}
}
}
return $list;
}
public function items($withdefaults = true)
{
$list = [];
foreach ($this->items as $key => $item) {
if ($key !== '') {
$list[$item->path] = $item->toArray($withdefaults);
}
}
return $list;
}
public function settings()
{
return (array) $this->config()->get('settings');
}
/**
* @return object
*/
public function getBase()
{
return $this->offsetGet($this->base);
}
/**
* @return object
*/
public function getDefault()
{
return $this->offsetGet($this->default);
}
/**
* @return object
*/
public function getActive()
{
return $this->offsetGet($this->active);
}
/**
* @return string|null
*/
public function getCacheId()
{
return $this->active ?: '-inactive-';
}
public function isActive($item)
{
$active = $this->getActive();
if ($active && $item && ($active->path ===
$item->path || strpos($active->path, $item->path . '/')
=== 0)) {
return true;
}
return false;
}
public function isCurrent($item)
{
$active = $this->getActive();
return $item && $active && $item->path ===
$active->path;
}
public function init(&$params)
{
$this->items = ['' => new Item($this, '',
['layout' => 'horizontal'])];
}
public function add(Item $item)
{
$this->items[$item->path] = $item;
// If parent exists, assign menu item to its parent; otherwise
ignore menu item.
if (isset($this->items[$item->parent_id])) {
$this->items[$item->parent_id]->addChild($item);
} elseif (!$this->items['']->count()) {
$this->items[$item->parent_id] =
$this->items[''];
$this->items[$item->parent_id]->addChild($item);
}
return $this;
}
/**
* Get menu items from the platform.
*
* @param int $levels
* @return array
*/
abstract protected function getItemsFromPlatform($levels);
/**
* Get base menu item.
*
* If itemid is not specified or does not exist, return active menu
item.
* If there is no active menu item, fall back to home page for the
current language.
* If there is no home page, return null.
*
* @param string $path
*
* @return string
*/
abstract protected function calcBase($path);
/**
* Get a list of the menu items.
*
* @param array $params
* @param array $items
*/
abstract public function getList(array $params, array $items);
/**
* Add custom menu items.
*
* @param array $params
* @param array $items
*/
public function addCustom(array $params, array $items)
{
$start = $params['startLevel'];
$max = $params['maxLevels'];
$end = $max ? $start + $max - 1 : 0;
$config = $this->config();
$type = $config->get('settings.type');
// Add custom menu elements.
foreach ($items as $route => $item) {
if ($type !== 'custom' &&
(!isset($item['type']) || $item['type'] !==
'particle')) {
continue;
}
$tree = explode('/', $route);
$parentTree = $tree;
array_pop($parentTree);
// Enabled state should equal particle setting.
$item['enabled'] =
!isset($item['options']['particle']['enabled'])
||
!empty($item['options']['particle']['enabled']);
$item['level'] = $level = count($tree);
$item['parent_id'] = implode('/',
$parentTree);
if (($start && $start > $level)
|| ($end && $level > $end)
// TODO: Improve. In the mean time Item::add() handles this
part.
// || ($start > 1 && !in_array($tree[$start -
2], $tree))
) {
continue;
}
$item = new Item($this, $route, $item);
$this->add($item);
}
}
/**
* @param array $ordering
* @param string $path
* @param array $map
*/
public function sortAll(array $ordering = null, $path = '',
$map = null)
{
if ($ordering === null) {
$config = $this->config();
$ordering = $config['ordering'] ?
$config['ordering'] : [];
}
if (!isset($this->items[$path]) ||
!$this->items[$path]->hasChildren()) {
return;
}
if ($map === null) {
$map = $this->pathMap ? $this->pathMap->toArray() :
[];
}
$order = [];
$newMap = [];
$item = $this->items[$path];
if ($this->isAssoc($ordering)) {
foreach ($ordering as $key => $value) {
if ($map) {
$newMap = isset($map[$key]['children']) ?
$map[$key]['children'] : [];
$key = isset($map[$key]['path']) ?
basename($map[$key]['path']) : $key;
$order[$key] = $value;
}
if (is_array($value)) {
$this->sortAll($value, $path ? $path . '/'
. $key : $key, $newMap);
}
}
$item->sortChildren($order ?: $ordering);
} else {
foreach ($ordering as $i => $group) {
foreach ($group as $key => $value) {
if ($map) {
$newMap = isset($map[$key]['children']) ?
$map[$key]['children'] : [];
$key = isset($map[$key]['path']) ?
basename($map[$key]['path']) : $key;
$order[$i][$key] = $value;
}
if (is_array($value)) {
$this->sortAll($value, $path ? $path .
'/' . $key : $key, $newMap);
}
}
}
$item->groupChildren($order ?: $ordering);
}
}
protected function isAssoc(array $array)
{
return (array_values($array) !== $array);
}
}
PKQ[�[��1D�&�&
Menu/Item.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Menu;
use RocketTheme\Toolbox\ArrayTraits\ArrayAccessWithGetters;
use RocketTheme\Toolbox\ArrayTraits\Export;
/**
* @property string $id
* @property string $type
* @property string $path
* @property string $alias
* @property string $title
* @property string $link
* @property string $parent_id
* @property string $layout
* @property int $browserNav
* @property bool $menu_text
* @property bool $visible
* @property int $group
* @property int $level
*/
class Item implements \ArrayAccess, \Iterator, \Serializable, \Countable
{
use ArrayAccessWithGetters, Export;
const VERSION = 1;
protected $items;
protected $menu;
protected $groups = [];
protected $children = [];
protected $url;
protected static $defaults = [
'id' => 0,
'type' => 'link',
'path' => null,
'alias' => null,
'title' => null,
'link' => null,
'parent_id' => null,
'layout' => 'list',
'target' => '_self',
'dropdown' => '',
'icon' => '',
'image' => '',
'subtitle' => '',
'hash' => '',
'class' => '',
'icon_only' => false,
'enabled' => true,
'visible' => true,
'group' => 0,
'columns' => [],
'level' => 0,
'link_title' => '',
'anchor_class' => ''
];
public function __construct(AbstractMenu $menu, $name, array $item =
[])
{
$this->menu = $menu;
$tree = explode('/', $name);
$alias = array_pop($tree);
$parent = implode('/', $tree);
// As we always calculate parent (it can change), prevent old one
from being inserted.
unset($item['parent_id']);
$this->items = $item + [
'id' => preg_replace('|[^a-z0-9]|i',
'-', $name) ?: 'root',
'path' => $name,
'alias' => $alias,
'title' => ucfirst($alias),
'link' => $name,
'parent_id' => $parent != '.' ? $parent
: '',
] + static::$defaults;
}
public function getDropdown()
{
if (!$this->items['dropdown']) {
return count($this->groups()) > 1 ? 'fullwidth'
: 'standard';
}
return $this->items['dropdown'];
}
public function serialize()
{
// FIXME: need to create collection class to gather the sibling
data.
return serialize([
'version' => static::VERSION,
'items' => $this->items,
'groups' => $this->groups,
'children' => $this->children,
'url' => $this->url
]);
}
public function unserialize($serialized)
{
// FIXME: need to create collection class to gather the sibling
data.
$data = unserialize($serialized);
if (!isset($data['version']) &&
$data['version'] === static::VERSION) {
throw new \UnexpectedValueException('Serialized data is
not valid');
}
$this->items = $data['items'];
$this->groups = $data['groups'];
$this->children = $data['children'];
$this->url = $data['url'];
}
/**
* @param string|null|bool $url
* @return string
*/
public function url($url = false)
{
if ($url !== false) {
$this->url = $url;
}
return $this->url;
}
/**
* @return AbstractMenu
* @deprecated Need to break relationship to the menu and use a
collection instead.
*/
protected function menu()
{
return $this->menu;
}
/**
* @return Item
*/
public function parent()
{
return $this->menu()[$this->items['parent_id']];
}
public function columnWidth($column)
{
if (isset($this->items['columns'][$column])) {
return $this->items['columns'][$column];
}
return 100 / count($this->groups());
}
public function groups()
{
if ($this->groups) {
$list = [];
foreach ($this->groups as $i => $group) {
$list[$i] = [];
foreach ($group as $path) {
$list[$i][] = $this->menu()[$path];
}
}
return $list;
}
return [$this->children()];
}
public function children()
{
$list = [];
foreach ($this as $child) {
$list[] = $child;
}
return $list;
}
public function hasChildren()
{
return !empty($this->children);
}
public function getGroup($i)
{
$groups = $this->groups();
$i = (int) $i;
return isset($groups[$i]) ? $groups[$i] : [];
}
public function update(array $data)
{
$this->items = array_replace($this->items, $data);
return $this;
}
public function addChild(Item $child)
{
$child->level = $this->level + 1;
$child->parent_id = $this->path;
$this->children[$child->alias] = $child->path;
return $this;
}
public function removeChild(Item $child)
{
unset($this->children[$child->alias]);
return $this;
}
public function sortChildren($ordering)
{
// Array with keys that point to the items.
$children =& $this->children;
if ($children) {
if (is_array($ordering)) {
// Remove extra items from ordering and reorder.
$children = array_replace(array_intersect_key($ordering,
$children), $children);
} else {
switch ((string) $ordering) {
case 'abc':
// Alphabetical ordering.
ksort($children, SORT_NATURAL);
break;
case 'cba':
// Reversed alphabetical ordering.
krsort($children, SORT_NATURAL);
break;
}
}
}
return $this;
}
public function reverse()
{
array_reverse($this->children, true);
array_reverse($this->groups, true);
return $this;
}
public function groupChildren(array $groups)
{
// Array with keys that point to the items.
$children =& $this->children;
if ($children) {
$menu = $this->menu();
$ordered = [];
// Create empty groups.
$this->groups = array_fill(0, max(1,
count($this->items['columns'])), []);
foreach ($groups as $i => $ordering) {
if (!is_array($ordering)) {
continue;
}
// Get the items for this group with proper ordering.
$group = array_replace(
array_intersect_key($ordering, $children),
array_intersect_key($children, $ordering)
);
// Assign each menu items to the group.
$group = array_map(
function($value) use ($i, $menu) {
$item = $menu[$value];
$item->group = $i;
return $value;
},
$group
);
// Update remaining children.
$children = array_diff_key($children, $ordering);
// Build child ordering.
$ordered += $group;
// Add items to the current group.
$this->groups[$i] = $group;
}
if ($children) {
// Add leftover children to the ordered list and to the
first group.
$ordered += $children;
$this->groups[0] += $children;
}
// Reorder children by their groups.
$children = $ordered;
}
return $this;
}
// Implements \Iterator
/**
* Returns the current child.
*
* @return Item
*/
public function current()
{
return $this->menu()[current($this->children)];
}
/**
* Returns the key of the current child.
*
* @return mixed Returns scalar on success, or NULL on failure.
*/
public function key()
{
return key($this->children);
}
/**
* Moves the current position to the next child.
*
* @return void
*/
public function next()
{
next($this->children);
}
/**
* Rewinds back to the first child.
*
* @return void
*/
public function rewind()
{
reset($this->children);
}
/**
* Count number of children.
*
* @return int
*/
public function count()
{
return count($this->children);
}
/**
* This method is called after Iterator::rewind() and Iterator::next()
to check if the current position is valid.
*
* @return bool Returns TRUE on success or FALSE on failure.
*/
public function valid()
{
return key($this->children) !== null;
}
/**
* Convert object into an array.
*
* @return array
*/
public function toArray($withDefaults = true)
{
$items = $this->items;
if (!$withDefaults) {
foreach (static::$defaults as $key => $value) {
if ($items[$key] === $value) {
unset($items[$key]);
}
}
}
return $items;
}
}
PKQ[�[�{{GLGLOutline/OutlineCollection.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Outline;
use FilesystemIterator;
use Gantry\Component\Collection\Collection;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Layout\Layout;
use Gantry\Framework\Atoms;
use RocketTheme\Toolbox\DI\Container;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class OutlineCollection extends Collection
{
/**
* @var Container
*/
protected $container;
/**
* @var string
*/
protected $path;
/**
* @param Container $container
* @param array $items
*/
public function __construct(Container $container, $items = [])
{
$this->container = $container;
$this->items = $items;
}
/**
* @param string $id
* @return string|null
*/
public function name($id)
{
return isset($this->items[$id]) ? $this->items[$id] : null;
}
/**
* @param string $id
* @return string
*/
public function title($id)
{
return isset($this->items[$id]) ? $this->items[$id] : $id;
}
public function all()
{
return $this;
}
public function system()
{
foreach ($this->items as $key => $item) {
if (substr($key, 0, 1) !== '_') {
unset($this->items[$key]);
}
}
return $this;
}
public function user()
{
foreach ($this->items as $key => $item) {
if (substr($key, 0, 1) === '_' || $key ==
'default') {
unset($this->items[$key]);
}
}
return $this;
}
public function filter(array $include = null)
{
if ($include !== null) {
foreach ($this->items as $key => $item) {
if (!in_array($key, $include)) {
unset($this->items[$key]);
}
}
}
return $this;
}
/**
* Returns list of all positions defined in all outlines.
*
* @return array
*/
public function positions()
{
$list = [];
foreach ($this->items as $name => $title) {
try {
$index = Layout::index($name);
$list += $index['positions'];
} catch (\Exception $e) {
// Layout cannot be read. We will just skip it instead of
throwing an exception.
}
}
return $list;
}
/**
* @param string $section
* @param bool $includeInherited
* @return array
*/
public function getOutlinesWithSection($section, $includeInherited =
true)
{
$list = [];
foreach ($this->items as $name => $title) {
try {
$index = Layout::index($name);
} catch (\Exception $e) {
// Layout cannot be read. We will just skip it instead of
throwing an exception.
continue;
}
if (isset($index['sections'][$section])) {
if (!$includeInherited) {
foreach ($index['inherit'] as $outline =>
$items) {
if (is_array($items) && in_array($section,
$items)) {
continue 2;
}
}
}
$list[$name] = $title;
}
}
return $list;
}
/**
* @param string $particle
* @param bool $includeInherited
* @return array
*/
public function getOutlinesWithParticle($particle, $includeInherited =
true)
{
$list = [];
foreach ($this->items as $name => $title) {
try {
$index = Layout::index($name);
} catch (\Exception $e) {
// Layout cannot be read. We will just skip it instead of
throwing an exception.
continue;
}
if (isset($index['particles'][$particle])) {
$ids = $index['particles'][$particle];
if (!$includeInherited &&
!empty($index['inherit'])) {
foreach ($index['inherit'] as $items) {
foreach ((array) $items as $id => $inheritId) {
unset($ids[$id]);
}
}
}
if ($ids) {
$list[$name] = $title;
}
}
}
return $list;
}
/**
* @param string $type
* @param bool $includeInherited
* @return array
*/
public function getOutlinesWithAtom($type, $includeInherited = true)
{
$list = [];
foreach ($this->items as $name => $title) {
$file =
CompiledYamlFile::instance("gantry-theme://config/{$name}/page/head.yaml");
$index = $file->content();
$file->free();
if (isset($index['atoms'])) {
foreach ($index['atoms'] as $atom) {
if (!empty($atom['id']) &&
$atom['type'] === $type && ($includeInherited ||
empty($atom['inherit']))) {
$list[$name] = $title;
}
}
}
}
return $list;
}
/**
* @param string $particle
* @param bool $includeInherited
* @return array
*/
public function getAllParticleInstances($particle, $includeInherited =
true)
{
$list = [];
foreach ($this->items as $name => $title) {
$list += $this->getParticleInstances($name, $particle,
$includeInherited);
}
return $list;
}
/**
* @param string $outline
* @param string $particle
* @param bool $includeInherited
* @return array
*/
public function getParticleInstances($outline, $particle,
$includeInherited = true)
{
$list = [];
$index = Layout::index($outline);
if (isset($index['particles'][$particle])) {
$list = $index['particles'][$particle];
if (!$includeInherited &&
!empty($index['inherit'])) {
foreach ($index['inherit'] as $items) {
foreach ((array) $items as $id => $inheritId) {
unset($list[$id]);
}
}
}
}
$layout = Layout::instance($outline);
foreach ($list as $id => $title) {
$item = clone $layout->find($id);
$block = $layout->block($id);
$item->block = isset($block->attributes) ?
$block->attributes : new \stdClass();
$list[$id] = $item;
}
return $list;
}
/**
* @param string $outline
* @param string $type
* @param bool $includeInherited
* @return array
*/
public function getAtomInstances($outline, $type, $includeInherited =
true)
{
$list = [];
$file =
CompiledYamlFile::instance("gantry-theme://config/{$outline}/page/head.yaml");
$head = $file->content();
$file->free();
if (isset($head['atoms'])) {
foreach ($head['atoms'] as $atom) {
if (!empty($atom['id']) &&
$atom['type'] === $type && ($includeInherited ||
empty($atom['inherit']['outline']))) {
$list[$atom['id']] = (object) $atom;
}
}
}
return $list;
}
/**
* Return list of outlines which are inheriting the specified atom.
*
* @param string $outline
* @param string $id
* @return array
*/
public function getInheritingOutlinesWithAtom($outline, $id = null)
{
$list = [];
foreach ($this->items as $name => $title) {
$file =
CompiledYamlFile::instance("gantry-theme://config/{$name}/page/head.yaml");
$head = $file->content();
$file->free();
if (isset($head['atoms'])) {
foreach ($head['atoms'] as $atom) {
if
(!empty($atom['inherit']['outline']) &&
$atom['inherit']['outline'] == $outline &&
(!$id || $atom['inherit']['atom'] == $id)) {
$list[$name] = $title;
}
}
}
}
return $list;
}
/**
* Return list of outlines which are inheriting the specified outline.
*
* You can additionally pass section or particle id to filter the
results for only that type.
*
* @param string $outline
* @param string|array $id
* @return array
*/
public function getInheritingOutlines($outline, $id = null)
{
$list = [];
foreach ($this->items as $name => $title) {
try {
$index = Layout::index($name);
} catch (\Exception $e) {
// Layout cannot be read. We will just skip it instead of
throwing an exception.
continue;
}
if (!empty($index['inherit'][$outline]) &&
(!$id || array_intersect((array) $id,
$index['inherit'][$outline]))) {
$list[$name] = $title;
}
}
return $list;
}
/**
* Return list of outlines inherited by the specified outline.
*
* You can additionally pass section or particle id to filter the
results for only that type.
*
* @param string $outline
* @param string $id
* @return array
*/
public function getInheritedOutlines($outline, $id = null)
{
try {
$index = Layout::index($outline);
} catch (\Exception $e) {
// Layout cannot be read. We will just return nothing instead
of throwing an exception.
return [];
}
$list = [];
foreach ($index['inherit'] as $name => $inherited) {
if (!$id || array_intersect_key((array) $id, $inherited[$id]))
{
$list[$name] = isset($this->items[$name]) ?
$this->items[$name] : $name;
}
}
return $list;
}
/**
* @param int|string $id
* @return int|string
*/
public function preset($id)
{
return $id;
}
/**
* @param int|string $id
* @return Layout
*/
public function layout($id)
{
return Layout::load($id);
}
/**
* @param int|string $id
* @return array
*/
public function layoutPreset($id)
{
$layout = Layout::load($id);
$preset = $layout->preset;
unset($layout);
return $preset;
}
/**
* @param string $path
* @return $this
* @throws \RuntimeException
*/
public function load($path = 'gantry-config://')
{
$this->path = $path;
$iterator = $this->getFilesystemIterator($path);
$files = [];
/** @var FilesystemIterator $info */
foreach ($iterator as $name => $info) {
if (!$info->isDir() || $name[0] == '.' ||
!is_file($info->getPathname() . '/index.yaml')) {
continue;
}
$files[$name] = ucwords(trim(preg_replace(['|_|',
'|/|'], [' ', ' / '], $name)));
}
unset($files['default']);
unset($files['menu']);
asort($files);
$this->items = $this->addDefaults($files);
return $this;
}
/**
* @param string|null $id
* @param string $title
* @param string|array $preset
* @return string
* @throws \RuntimeException
*/
public function create($id, $title = null, $preset = null)
{
$title = $title ?: 'Untitled';
$name = ltrim(strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $id ?: $title)), '_');
if (!$name) {
throw new \RuntimeException("Outline needs a name",
400);
}
if ($name === 'default') {
throw new \RuntimeException("Outline cannot use reserved
name '{$name}'", 400);
}
$name = $this->findFreeName($name);
if (!$id) {
$title = ucwords(trim(preg_replace(['|_|',
'|/|'], [' ', ' / '], $name)));
}
if (!is_array($preset)) {
// Load preset.
$preset = Layout::preset($preset ?: 'default');
}
// Create layout and index for the new layout.
$layout = new Layout($name, $preset);
$layout->save()->saveIndex();
$this->items[$name] = $title;
return $name;
}
/**
* @param string $id
* @param string $title
* @param bool $inherit
* @return string
* @throws \RuntimeException
*/
public function duplicate($id, $title = null, $inherit = false)
{
if (!$this->canDuplicate($id)) {
throw new \RuntimeException("Outline '$id'
cannot be duplicated", 400);
}
$layout = Layout::load($id);
if ($inherit) {
$layout->inheritAll()->clean();
}
$new = $this->create(null, $title, $layout->toArray() +
['preset' => $layout->preset]);
if ($id === 'default') {
// For Base Outline we're done.
return $new;
}
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$path =
$locator->findResource("{$this->path}/{$id}");
if (!$path) {
// Nothing to copy.
return $new;
}
$newPath =
$locator->findResource("{$this->path}/{$new}", true, true);
try {
// Copy everything over except index, layout and assignments.
Folder::copy($path, $newPath,
'/^(index|layout|assignments)\..*$/');
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('Duplicating Outline
failed: ', $e->getMessage()), 500, $e);
}
return $new;
}
/**
* @param string $id
* @param string $title
* @return string
* @throws \RuntimeException
*/
public function rename($id, $title)
{
if (!$this->canDelete($id)) {
throw new \RuntimeException("Outline '$id'
cannot be renamed", 400);
}
$gantry = $this->container;
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$path =
$locator->findResource("{$this->path}/{$id}", true, true);
if (!$path || !is_dir($path)) {
throw new \RuntimeException('Outline not found',
404);
}
$folder = strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $title));
if ($folder === 'default' || $folder[0] ===
'_') {
throw new \RuntimeException("Outline cannot use reserved
name '{$folder}'", 400);
}
$newPath =
$locator->findResource("{$this->path}/{$folder}", true,
true);
if (is_dir($newPath)) {
throw new \RuntimeException("Outline '$id'
already exists.", 400);
}
try {
foreach ($this->getInheritingOutlines($id) as $outline =>
$title) {
$this->layout($outline)->updateInheritance($id,
$folder)->save()->saveIndex();
}
foreach ($this->getInheritingOutlinesWithAtom($id) as
$outline => $title) {
Atoms::instance($outline)->updateInheritance($id,
$folder)->save();
}
Folder::move($path, $newPath);
} catch (\Exception $e) {
throw new \RuntimeException(sprintf('Renaming Outline
failed: %s', $e->getMessage()), 500, $e);
}
$this->items[$id] = $title;
return $folder;
}
/**
* @param string $id
* @throws \RuntimeException
*/
public function delete($id)
{
if (!$this->canDelete($id)) {
throw new \RuntimeException("Outline '$id'
cannot be deleted", 400);
}
$gantry = $this->container;
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$path =
$locator->findResource("{$this->path}/{$id}", true, true);
if (!is_dir($path)) {
throw new \RuntimeException('Outline not found',
404);
}
foreach ($this->getInheritingOutlines($id) as $outline =>
$title) {
$this->layout($outline)->updateInheritance($id)->save()->saveIndex();
}
foreach ($this->getInheritingOutlinesWithAtom($id) as $outline
=> $title) {
Atoms::instance($outline)->updateInheritance($id)->save();
}
if (file_exists($path)) {
Folder::delete($path);
}
unset($this->items[$id]);
}
/**
* @param string $id
* @return boolean
*/
public function canDuplicate($id)
{
if (!isset($this->items[$id])) {
return false;
}
return true;
}
/**
* @param string $id
* @return boolean
*/
public function canDelete($id)
{
if (!$id || $id[0] === '_' || $id ===
'default') {
return false;
}
return true;
}
/**
* @param string $id
* @return boolean
*/
public function isDefault($id)
{
return $id === 'default';
}
/**
* @param array $outlines
* @return array
*/
protected function addDefaults(array $outlines)
{
return [
'default' => 'Base Outline',
'_body_only' => 'Body Only',
'_error' => 'Error',
'_offline' => 'Offline'
] + $outlines;
}
/**
* Find unused name with number appended to it when duplicating an
outline.
*
* @param string $id
* @return string
*/
protected function findFreeName($id)
{
if (!isset($this->items[$id])) {
return $id;
}
$name = $id;
$count = 0;
if (preg_match('|^(?:_)?(.*?)(?:_(\d+))?$|ui', $id,
$matches)) {
$matches += ['', '', ''];
list (, $name, $count) = $matches;
}
$count = max(1, $count);
do {
$count++;
} while (isset($this->items["{$name}_{$count}"]));
return "{$name}_{$count}";
}
protected function getFilesystemIterator($path)
{
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
$custom = $locator->findResource($path, true, true);
if (is_dir($custom)) {
/** @var FilesystemIterator $iterator */
$iterator = new FilesystemIterator(
$custom,
FilesystemIterator::CURRENT_AS_SELF |
FilesystemIterator::KEY_AS_FILENAME |
FilesystemIterator::UNIX_PATHS |
FilesystemIterator::SKIP_DOTS
);
} else {
/** @var UniformResourceIterator $iterator */
$iterator = $locator->getIterator(
$path,
UniformResourceIterator::CURRENT_AS_SELF |
UniformResourceIterator::KEY_AS_FILENAME |
UniformResourceIterator::UNIX_PATHS |
UniformResourceIterator::SKIP_DOTS
);
}
return $iterator;
}
}
PKR[�[�T�ڍ�Position/Module.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Position;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Module implements \ArrayAccess
{
use NestedArrayAccessWithGetters, Export;
public $name;
public $position;
public $assigned;
protected $items;
/**
* Module constructor.
*
* @param string $name
* @param string $position
* @param array $data
*/
public function __construct($name, $position = null, array $data =
null)
{
$this->name = $name;
$this->position = $position;
if ($data) {
$this->init($data);
} else {
$this->load();
}
}
public function update(array $data)
{
$this->init($data);
return $this;
}
/**
* Save module.
*
* @param string $position
* @param string $name
* @return $this
*/
public function save($name = null, $position = null)
{
$this->name = $name ?: $this->name;
$this->position = $position ?: $this->position;
$items = $this->toArray();
unset($items['position'], $items['id']);
$file = $this->file(true);
$file->save($items);
return $this;
}
/**
* Delete module.
*
* @return $this
*/
public function delete()
{
$file = $this->file(true);
if ($file->exists()) {
$file->delete();
}
return $this;
}
/**
* Return true if module exists.
*
* @return bool
*/
public function exists()
{
return $this->name ? $this->file()->exists() : false;
}
public function toArray()
{
return ['position' => $this->position,
'id' => $this->name] + $this->items;
}
protected function load()
{
$file = $this->file();
$this->init($file->content());
$file->free();
}
protected function init($data)
{
unset($data['id'], $data['position']);
$this->items = $data;
if (isset($this->items['assignments'])) {
$assignments = $this->items['assignments'];
if (is_array($assignments)) {
$this->assigned = 'some';
} elseif ($assignments !== 'all') {
$this->assigned = 'none';
} else {
$this->assigned = 'all';
}
} else {
$this->assigned = 'all';
}
}
protected function file($save = false)
{
$position = $this->position ?: '_unassigned_';
$this->name = $this->name ?: ($save ?
$this->findFreeName() : null);
$name = $this->name ?: '_untitled_';
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
return
CompiledYamlFile::instance($locator->findResource("gantry-positions://{$position}/{$name}.yaml",
true, $save));
}
/**
* Find unused name with number appended.
*/
protected function findFreeName()
{
$position = $this->position ?: '_unassigned_';
$name = $this->get('type');
$name = $name == 'particle' ?
$this->get('options.type') : $name;
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
if
(!file_exists($locator->findResource("gantry-positions://{$position}/{$name}.yaml",
true, true))) {
return $name;
}
$count = 1;
do {
$count++;
} while
(file_exists($locator->findResource("gantry-positions://{$position}/{$name}_{$count}.yaml",
true, true)));
return "{$name}_{$count}";
}
}
PKR[�[�l*�)#)#Position/Position.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Position;
use Gantry\Component\Collection\Collection;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use Symfony\Component\Yaml\Yaml;
class Position extends Collection
{
public $name;
public $title;
protected $modules = [];
/**
* Position constructor.
*
* @param string $name
* @param array $items
*/
public function __construct($name, array $items = null)
{
$this->name = $name;
$this->load($items);
}
/**
* Save position.
*
* @return $this
*/
public function save()
{
$file = $this->file(true);
$file->save($this->toArray());
return $this;
}
/**
* Clone position together with its modules. Returns new position.
*
* @param string $name
* @return Position
*/
public function duplicate($name)
{
$new = clone $this;
$new->name = $name;
$new->save();
foreach ($this as $module) {
$clone = clone $module;
$clone->position = $name;
$clone->save();
}
return $new;
}
/**
* Raname module key
*
* @param string $name
* @return static
*/
public function rename($name)
{
$new = $this->duplicate($name);
$this->delete();
return $new;
}
/**
* Delete position.
*
* @return $this
*/
public function delete()
{
$file = $this->file(true);
if ($file->exists()) {
$file->delete();
}
$folder = $this->folder(true);
if (is_dir($folder)) {
Folder::delete($folder);
}
return $this;
}
/**
* Update modules in the position.
*
* @param array $items
* @return $this
*/
public function update(array $items)
{
$list = [];
foreach ($items as $item) {
$name = ($item instanceof Module) ? $item->name : $item;
$list[] = $name;
if (!in_array($name, $this->items)) {
$this->add($item);
}
}
$remove = array_diff($this->items, $list);
foreach ($remove as $item) {
$module = $this->get($item);
if ($module->position === $this->name) {
$module->delete();
}
}
$this->items = $list;
return $this;
}
/**
* @param Module|string $item
* @param string $name Temporary name for the module.
* @return $this
*/
public function add($item, $name = null)
{
if ($item instanceof Module) {
$this->modules[$name ?: $item->name] = $item;
$item = $name ?: $item->name;
}
$this->items[] = $item;
return $this;
}
public function remove($item)
{
if ($item instanceof Module) {
$item = $item->name;
}
unset($this->modules[$item]);
$this->items = array_diff($this->items, $item);
return $this;
}
/**
* @param $name
* @return Module
*/
public function get($name)
{
if (!isset($this->modules[$name])) {
$this->modules[$name] = $this->loadModule($name);
}
return $this->modules[$name];
}
/**
* Returns the value at specified offset.
*
* @param string $offset The offset to retrieve.
* @return Module
*/
public function offsetGet($offset)
{
if (!isset($this->items[$offset])) {
return null;
}
$name = $this->items[$offset];
if (!isset($this->modules[$name])) {
$this->modules[$name] = $this->loadModule($name);
}
return $this->modules[$name];
}
/**
* Assigns a value to the specified offset.
*
* @param mixed $offset The offset to assign the value to.
* @param mixed $value The value to set.
*/
public function offsetSet($offset, $value)
{
if (!$value instanceof Position) {
throw new \InvalidArgumentException('Value has to be
instance of Position');
}
if (is_null($offset)) {
$this->items[] = $value->name;
$this->modules[$value->name] = $value;
} else {
$this->items[$offset] = $value->name;
$this->modules[$value->name] = $value;
}
}
/**
* Unsets an offset.
*
* @param mixed $offset The offset to unset.
*/
public function offsetUnset($offset)
{
parent::offsetUnset($offset);
if (!isset($this->items[$offset])) {
return;
}
$name = $this->items[$offset];
if (isset($this->modules[$name])) {
unset($this->modules[$name]);
}
}
/**
* @return \ArrayIterator
*/
public function getIterator()
{
$items = [];
foreach ($this->items as $key => $name) {
$items[] = $this->offsetGet($key);
}
return new \ArrayIterator($items);
}
/**
* @return array
*/
public function toArray($includeModules = false)
{
$array = [
'name' => $this->name,
'title' => $this->title,
];
if (!$includeModules) {
$array['ordering'] = $this->items;
} else {
$list = [];
foreach ($this->getIterator() as $key => $module) {
$list[$key] = $module->toArray();
}
$array['modules'] = $list;
}
return $array;
}
/**
* @param int $inline
* @param int $indent
* @param bool $includeModules
* @return string
*/
public function toYaml($inline = 3, $indent = 2, $includeModules =
false)
{
return Yaml::dump($this->toArray($includeModules), $inline,
$indent, true, false);
}
/**
* @param bool $includeModules
* @return string
*/
public function toJson($includeModules = false)
{
return json_encode($this->toArray($includeModules));
}
/**
* @return array
*/
public function listModules()
{
$list = [];
foreach ($this->items as $name) {
$list[] = "{$this->name}/{$name}";
}
return $list;
}
/**
* @param bool $save
* @return string
*/
public function folder($save = false)
{
return $this->locator()->findResource($this->path(), true,
$save);
}
/**
* @param $data
*/
protected function load($data)
{
if ($data === null) {
$file = $this->file();
$data = $file->content();
$file->free();
}
$this->title = isset($data['title']) ?
$data['title'] : $this->name;
if (isset($data['modules'])) {
foreach ($data['modules'] as $array) {
$this->add(new Module($array['id'],
$this->name, $array), $array['id'] ?: rand());
}
return;
}
// Sort modules by ordering, if items are not listed in ordering,
use alphabetical order.
$ordering = isset($data['ordering']) ?
array_flip($data['ordering']) : [];
$path = $this->locator()->findResource($this->path());
$files = $path ? Folder::all(
$path,
[
'compare' => 'Filename',
'pattern' => '|\.yaml$|',
'folders' => false,
'recursive' => false,
'key' => 'Filename',
'filters' => ['key' =>
'|\.yaml$|']
]
) : [];
ksort($files);
$this->items = array_keys($ordering + $files);
}
/**
* @param string $name
* @return $this
*/
protected function loadModule($name)
{
return new Module($name, $this->name);
}
/**
* @param bool $save
* @return CompiledYamlFile
*/
protected function file($save = false)
{
return
CompiledYamlFile::instance($this->locator()->findResource($this->path()
. '.yaml', true, $save));
}
/**
* @return UniformResourceLocator
*/
protected function locator()
{
return Gantry::instance()['locator'];
}
/**
* @return string
*/
protected function path()
{
return "gantry-positions://{$this->name}";
}
}
PKR[�[���..Position/Positions.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Position;
use Gantry\Component\Collection\Collection;
use Gantry\Component\File\CompiledYamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceIterator;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
use RocketTheme\Toolbox\DI\Container;
class Positions extends Collection
{
/**
* @var array|Position[]
*/
protected $items;
/**
* @var string
*/
protected $path;
/**
* @var Container
*/
protected $container;
public function __construct(Container $container)
{
$this->container = $container;
}
/**
* @param string $path
*
* @return $this
* @throws \RuntimeException
*/
public function load($path = 'gantry-positions://')
{
$this->path = $path;
$positions = [];
/** @var UniformResourceLocator $locator */
$locator = $this->container['locator'];
if ($locator->findResource($path)) {
/** @var UniformResourceIterator $iterator */
$iterator = $locator->getIterator($path);
/** @var UniformResourceIterator $info */
foreach ($iterator as $info) {
if (!$info->isFile() || $info->getExtension() !==
'yaml') {
continue;
}
$name = $info->getBasename('.yaml');
$position =
CompiledYamlFile::instance($info->getPathname())->content();
// Only use filesystem position if it it is properly set
up.
if ($position) {
$positions[$name] = new Position($name, $position);
}
}
}
// Add empty positions from the layouts.
foreach ($this->container['outlines']->positions()
as $name => $title) {
if (!isset($positions[$name])) {
$positions[$name] = new Position($name, ['title'
=> $title]);
}
}
ksort($positions);
$this->items = $positions;
return $this;
}
/**
* Updates all positions with their modules from an array and saves
them.
*
* @param array $data
* @return $this
*/
public function import(array $data)
{
foreach ($data as $pos) {
$list = [];
$position = $pos['name'];
foreach ($pos['modules'] as $item) {
$name = !empty($item['id']) ?
$item['id'] : '';
if ($name && !empty($item['position'])) {
$module =
$this[$item['position']]->get($name);
if ($position !== $item['position']) {
$module->delete();
}
} else {
$module = new Module($name, $position);
}
$module->update($item)->save($name, $position);
$list[] = $module;
}
$this[$pos['name']]->update($list)->save();
}
return $this;
}
/**
* @param Position $item
* @return $this
*/
public function add($item)
{
if ($item instanceof Position) {
$this->items[$item->name] = $item;
}
return $this;
}
/**
* @param string $title
* @param string $id
*
* @return string
* @throws \RuntimeException
*/
public function create($title = 'Untitled', $id = null)
{
$name = strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $id ?: $title));
if (!$name) {
throw new \RuntimeException("Position needs a name",
400);
}
$name = $this->findFreeName($name);
$position = new Position($name, ['title' => $title]);
$position->save();
return $name;
}
/**
* @param string $id
* @param string $new
*
* @return string
* @throws \RuntimeException
*/
public function duplicate($id, $new = null)
{
if (!isset($this->items[$id])) {
throw new \RuntimeException(sprintf("Duplicating Position
failed: '%s' not found.", $id), 400);
}
$new = $this->findFreeName($new ?
strtolower(preg_replace('|[^a-z\d_-]|ui', '_', $new)) :
$id);
$position = $this->items[$id];
$new = $position->duplicate($new);
return $new->name;
}
/**
* @param string $id
* @param string $new
*
* @return string
* @throws \RuntimeException
*/
public function rename($id, $new)
{
if (!isset($this->items[$id])) {
throw new \RuntimeException(sprintf("Renaming Position
failed: '%s' not found.", $id), 400);
}
$newId = strtolower(preg_replace('|[^a-z\d_-]|ui',
'_', $new));
if (isset($this->items[$newId])) {
throw new \RuntimeException(sprintf("Renaming Position
failed: '%s' already exists.", $newId), 400);
}
$position = $this->items[$id];
$position->rename($new);
return $position->name;
}
/**
* @param string $id
*
* @throws \RuntimeException
*/
public function delete($id)
{
if (!isset($this->items[$id])) {
throw new \RuntimeException(sprintf("Deleting Position
failed: '%s' not found.", $id), 400);
}
$position = $this->items[$id];
$position->delete();
}
/**
* Find unused name with number appended to it when duplicating an
position.
*
* @param string $id
*
* @return string
*/
protected function findFreeName($id)
{
if (!isset($this->items[$id])) {
return $id;
}
$name = $id;
$count = 0;
if (preg_match('|^(?:_)?(.*?)(?:_(\d+))?$|ui', $id,
$matches)) {
$matches += ['', '', ''];
list (, $name, $count) = $matches;
}
$count = max(1, $count);
do {
$count++;
} while (isset($this->items["{$name}_{$count}"]));
return "{$name}_{$count}";
}
}
PKR[�[���O��Remote/Response.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Remote;
class Response
{
/**
* The callback for the progress
*
* @var callable Either a function or callback in array notation
*/
public static $callback = null;
/**
* Which method to use for HTTP calls, can be 'curl',
'fopen' or 'auto'. Auto is default and fopen is the
preferred method
*
* @var string
*/
private static $method = 'auto';
/**
* Default parameters for `curl` and `fopen`
*
* @var array
*/
private static $defaults = [
'curl' => [
CURLOPT_REFERER => 'Gantry5 Response',
CURLOPT_USERAGENT => 'Gantry5 Response',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HEADER => false,
/**
* Example of callback parameters from within your own class
*/
//CURLOPT_NOPROGRESS => false,
//CURLOPT_PROGRESSFUNCTION => [$this, 'progress']
],
'fopen' => [
'method' => 'GET',
'user_agent' => 'Gantry5 Response',
'max_redirects' => 5,
'follow_location' => 1,
'timeout' => 15,
/**
* Example of callback parameters from within your own class
*/
//'notification' => [$this, 'progress']
]
];
/**
* Sets the preferred method to use for making HTTP calls.
*
* @param string $method Default is `auto`
*
* @return Response
*/
public static function setMethod($method = 'auto')
{
if (!in_array($method, ['auto', 'curl',
'fopen'])) {
$method = 'auto';
}
self::$method = $method;
return new self();
}
/**
* Makes a request to the URL by using the preferred method
*
* @param string $uri URL to call
* @param array $options An array of parameters for both `curl` and
`fopen`
* @param callable $callback
*
* @return string The response of the request
*/
public static function get($uri = '', $options = [],
$callback = null)
{
if (!self::isCurlAvailable() && !self::isFopenAvailable())
{
throw new \RuntimeException('Could not start an HTTP
request. `allow_url_open` is disabled and `cURL` is not available');
}
$options = array_replace_recursive(self::$defaults, $options);
$method = 'get' . ucfirst(strtolower(self::$method));
self::$callback = $callback;
return static::$method($uri, $options, $callback);
}
/**
* Checks if cURL is available
*
* @return boolean
*/
public static function isCurlAvailable()
{
return function_exists('curl_version');
}
/**
* Checks if the remote fopen request is enabled in PHP
*
* @return boolean
*/
public static function isFopenAvailable()
{
return preg_match('/1|yes|on|true/i',
ini_get('allow_url_fopen'));
}
/**
* Progress normalized for cURL and fopen
*
* @return array Normalized array with useful data.
* Format: ['code' => int|false,
'filesize' => bytes, 'transferred' => bytes,
'percent' => int]
*/
public static function progress()
{
static $filesize = null;
$args = func_get_args();
$isCurlResource = is_resource($args[0]) &&
get_resource_type($args[0]) == 'curl';
$notification_code = !$isCurlResource ? $args[0] : false;
$bytes_transferred = $isCurlResource ? $args[2] : $args[4];
if ($isCurlResource) {
$filesize = $args[1];
} elseif ($notification_code == STREAM_NOTIFY_FILE_SIZE_IS) {
$filesize = $args[5];
}
if ($bytes_transferred > 0) {
if ($notification_code == STREAM_NOTIFY_PROGRESS |
STREAM_NOTIFY_COMPLETED || $isCurlResource) {
$progress = [
'code' => $notification_code,
'filesize' => $filesize,
'transferred' => $bytes_transferred,
'percent' => $filesize <= 0 ?
'-' : round(($bytes_transferred * 100) / $filesize, 1)
];
if (self::$callback !== null) {
call_user_func_array(self::$callback, [$progress]);
}
}
}
}
/**
* Automatically picks the preferred method
*
* @return string The response of the request
*/
private static function getAuto()
{
if (self::isFopenAvailable()) {
return self::getFopen(func_get_args());
}
if (self::isCurlAvailable()) {
return self::getCurl(func_get_args());
}
return '';
}
/**
* Starts a HTTP request via fopen
*
* @return string The response of the request
*/
private static function getFopen()
{
if (count($args = func_get_args()) == 1) {
$args = $args[0];
}
$uri = $args[0];
$options = $args[1];
$callback = $args[2];
if ($callback) {
$options['fopen']['notification'] =
['self', 'progress'];
}
$stream = stream_context_create(['http' =>
$options['fopen']], $options['fopen']);
$content = @file_get_contents($uri, false, $stream);
if ($content === false) {
throw new \RuntimeException("Error while trying to
download '$uri'");
}
return $content;
}
/**
* Starts a HTTP request via cURL
*
* @return string The response of the request
*/
private static function getCurl()
{
$args = func_get_args();
$args = count($args) > 1 ? $args : array_shift($args);
$uri = $args[0];
$options = $args[1];
$callback = $args[2];
$ch = curl_init($uri);
curl_setopt_array($ch, $options['curl']);
if ($callback) {
curl_setopt_array(
$ch,
[
CURLOPT_NOPROGRESS => false,
CURLOPT_PROGRESSFUNCTION => ['self',
'progress']
]
);
}
$response = curl_exec($ch);
if ($errno = curl_errno($ch)) {
$error_message = curl_strerror($errno);
throw new \RuntimeException("cURL error ({$errno}):\n
{$error_message}");
}
curl_close($ch);
return $response;
}
}
PKR[�[��N@Request/Input.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Request;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\ExportInterface;
use RocketTheme\Toolbox\ArrayTraits\Iterator;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
class Input implements \ArrayAccess, \Iterator, ExportInterface
{
use NestedArrayAccessWithGetters, Iterator, Export;
/**
* @var array
*/
protected $items;
/**
* Constructor to initialize array.
*
* @param array $items Initial items inside the iterator.
*/
public function __construct(array &$items = [])
{
$this->items = &$items;
}
/**
* Returns input array. If there are any JSON encoded fields (key:
_json), those will be decoded as well.
*
* @param string $path Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @return array
*/
public function getArray($path = null, $default = null, $separator =
'.')
{
$data = $path ? $this->get($path, $default, $separator) :
$this->items;
return (array) $this->getChildren($data);
}
/**
* Returns JSON decoded input array.
*
* @param string $path Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @return array
*/
public function getJsonArray($path = null, $default = null, $separator
= '.')
{
return (array) $this->getJson($path, $default, $separator,
true);
}
/**
* Returns JSON decoded input. Accosiative arrays become objects.
*
* @param string|null $path Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @param bool $assoc True to return associative arrays
instead of objects.
* @return mixed
*/
public function getJson($path = null, $default = null, $separator =
'.', $assoc = false)
{
$data = $this->get($path, null, $separator);
if (!isset($data)) {
return $default;
}
if (!is_string($data)) {
throw new \RuntimeException(sprintf('%s::%s(%s) expects
input to be JSON encoded string', __CLASS__, __FUNCTION__, $path));
}
$data = json_decode($data, $assoc);
if (!isset($data)) {
throw new \RuntimeException(sprintf('%s::%s(): %s',
__CLASS__, __FUNCTION__, json_last_error_msg()));
}
return $data;
}
/**
* @param $current
* @return array|mixed
* @internal
*/
protected function getChildren(&$current)
{
if (!is_array($current)) {
return $current;
}
$array = [];
foreach ($current as $key => &$value) {
if ($key === '_json') {
$array += json_decode($value, true);
} else {
$array[$key] = $this->getChildren($value);
}
}
return $array;
}
}
PKS[�[(5���Request/Request.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Request;
class Request
{
/**
* @var string
*/
protected $method;
/**
* @var Input
*/
public $get;
/**
* @var Input
*/
public $post;
/**
* @var Input
*/
public $cookie;
/**
* @var Input
*/
public $server;
/**
* @var Input
*/
public $request;
public function __construct()
{
$this->init();
}
public function getMethod()
{
if (!$this->method) {
$method = $this->server['REQUEST_METHOD'] ?:
'GET';
if ('POST' === $method) {
$method =
$this->server['X-HTTP-METHOD-OVERRIDE'] ?: $method;
$method = $this->post['METHOD'] ?: $method;
}
$this->method = strtoupper($method);
}
return $this->method;
}
protected function init()
{
$this->get = new Input($_GET);
$this->post = new Input($_POST);
$this->cookie = new Input($_COOKIE);
$this->server = new Input($_SERVER);
$this->request = new Input($_REQUEST);
}
}
PKT[�[]�>J��Response/HtmlResponse.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Response;
class HtmlResponse extends Response
{
}
PKT[�[(�ggResponse/JsonResponse.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Response;
class JsonResponse extends Response
{
public $mimeType = 'application/json';
protected $success = true;
protected $message;
protected $exceptions = [];
protected $messages = [];
protected $content = [];
/**
* @param string $content
* @param bool $success
* @return $this
*/
public function setContent($content, $success = true)
{
$this->success = (bool) $success;
if (is_array($content)) {
foreach ($content as $key => $value) {
$this->parseValue($key, $value);
}
} else {
$this->parseValue(null, $content);
}
return $this;
}
/**
* @return string
*/
public function __toString()
{
// Empty output buffer to make sure that the response is clean and
valid.
while (($output = ob_get_clean()) !== false) {
// In debug mode send also output buffers (debug dumps, PHP
notices and warnings).
if ($output && (GANTRY5_DEBUG || headers_sent())) {
$this->messages['php'][] = $output;
}
}
$json = [
'code' => $this->code,
'success' => $this->success
];
if ($this->messages) {
$json['messages'] = $this->messages;
}
if ($this->exceptions) {
$json['exceptions'] = $this->exceptions;
}
if (GANTRY5_DEBUG) {
$json['memory'] = ['peak' =>
memory_get_peak_usage(), 'current' => memory_get_usage()];
}
$json += $this->content;
return (string) json_encode($json);
}
protected function parseValue($key, $value)
{
if ($value instanceof \Exception) {
// Prepare the error response if we are dealing with an error.
$this->success = false;
$this->exceptions = $this->parseException($value);
} elseif ($value instanceof HtmlResponse) {
// Add HTML response (numeric keys are always integers).
$key = !$key || is_int($key) ? 'html' : $key;
$this->content[$key] = trim((string) $value);
} elseif (is_null($key)) {
// If the returned value was not an array, put the contents
into data variable.
$this->content['data'] = $value;
} elseif (is_int($key)) {
// If the key was an integer, also put the contents into data
variable.
$this->content['data'][$key] = $value;
} else {
$this->content[$key] = $value;
}
}
protected function parseException(\Exception $e)
{
$this->code = $e->getCode();
// Build data from exceptions.
$exceptions = [];
do {
$exception = [
'code' => $e->getCode(),
'message' => $e->getMessage()
];
if (GANTRY5_DEBUG) {
$exception += [
'type' => get_class($e),
'file' => $e->getFile(),
'line' => $e->getLine()
];
}
$exceptions[] = $exception;
$e = $e->getPrevious();
}
while (GANTRY5_DEBUG && $e);
return $exceptions;
}
}
PKT[�[�~�77Response/RedirectResponse.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Response;
class RedirectResponse extends Response
{
public function __construct($content = '', $status = 303)
{
parent::__construct('', $status);
$this->setHeader('Location', $content);
}
public function getContent()
{
return (string) $this->getHeaders()['Location'];
}
public function setContent($content)
{
$this->setHeader('Location', $content);
}
}
PKT[�[ʚ@%��Response/Response.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Response;
class Response
{
public $charset = 'utf-8';
public $mimeType = 'text/html';
protected $code = 200;
protected $message = 'OK';
protected $lifetime = 0;
protected $etag;
/**
* @var array Response headers.
*/
protected $headers = [];
/**
* @var string Response body.
*/
protected $content;
protected $responseCodes = [
200 => 'OK',
400 => 'Bad Request',
401 => 'Unauthorized',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
410 => 'Gone',
500 => 'Internal Server Error',
501 => 'Not Implemented',
503 => 'Service Temporarily Unavailable'
];
public function __construct($content = '', $status = 200)
{
if ($content) {
$this->setContent($content);
}
if ($status != 200) {
$this->setStatusCode($status);
}
}
/**
* @param int $seconds
* @return $this
*/
public function setLifetime($seconds)
{
$this->lifetime = $seconds;
return $this;
}
/**
* @param mixed $key
* @return $this
*/
public function setKey($key)
{
$this->etag = md5(json_encode($key));
return $this;
}
/**
* @return int
*/
public function getStatusCode()
{
return $this->code;
}
/**
* @param int $code
* @param string $message
* @return $this
*/
public function setStatusCode($code, $message = null)
{
if ($message) {
$this->code = $code;
$this->message = $message;
} else {
$this->code = isset($this->responseCodes[$code]) ? (int)
$code : 500;
$this->message = $this->responseCodes[$this->code];
}
return $this;
}
/**
* @return string
*/
public function getStatus()
{
$code = $this->getStatusCode();
return $code . ' ' .
(isset($this->responseCodes[$code]) ? $this->responseCodes[$code] :
'Unknown error');
}
/**
* @return array
*/
public function getHeaders()
{
return $this->headers;
}
/**
* @param array $headers
* @param bool $replace
* @return $this
*/
public function setHeaders(array $headers, $replace = false)
{
foreach ($headers as $key => $values) {
$act = $replace;
foreach ((array) $values as $value) {
$this->setHeader($key, $value, $act);
$act = false;
}
}
return $this;
}
/**
* @return $this
*/
public function clearHeaders()
{
$this->headers = [];
return $this;
}
/**
* @param $name
* @param $value
* @param bool $replace
* @return $this
*/
public function setHeader($name, $value, $replace = false)
{
if ($replace) {
$this->headers[$name] = [$value];
} else {
$this->headers[$name][] = $value;
}
return $this;
}
/**
* @return string
*/
public function getContent()
{
return (string) $this->content;
}
/**
* @param string $content
* @return Response
* @throws \UnexpectedValueException
*/
public function setContent($content) {
if ($content !== null && !is_string($content) &&
!is_numeric($content) && !is_callable([$content,
'__toString'])) {
throw new \UnexpectedValueException(
sprintf('Content must be a string or object
implementing __toString()')
);
}
$this->content = $content;
return $this;
}
/**
* @return string
*/
public function __toString()
{
return (string) $this->content;
}
}
PKU[�[V�99Router/Router.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Router;
use Gantry\Admin\EventListener;
use Gantry\Admin\Theme;
use Gantry\Component\Controller\BaseController;
use Gantry\Component\Response\HtmlResponse;
use Gantry\Component\Response\Response;
use Gantry\Component\Response\JsonResponse;
use Gantry\Framework\Services\ErrorServiceProvider;
use RocketTheme\Toolbox\DI\Container;
use RocketTheme\Toolbox\Event\EventDispatcher;
use Whoops\Exception\ErrorException;
abstract class Router implements RouterInterface
{
/**
* @var Container
*/
protected $container;
protected $format;
protected $resource;
protected $method;
protected $path;
protected $params;
public function __construct(Container $container)
{
$this->container = $container;
}
public function dispatch()
{
$this->boot();
$this->load();
// Render the page or execute the task.
try {
$response = static::execute($this->resource,
$this->method, $this->path, $this->params, $this->format);
} catch (ErrorException $e) {
throw $e;
} catch (\Exception $e) {
// Handle errors.
if ($this->container->debug()) {
throw $e;
}
$response = $this->getErrorResponse($e, $this->format ==
'json');
}
return $this->send($response);
}
public function execute($resource, $method = 'GET', $path,
$params = [], $format = 'html')
{
$class = '\\Gantry\\Admin\\Controller\\' .
ucfirst($format) . '\\' . strtr(ucwords(strtr($resource,
'/', ' ')), ' ', '\\');
// Protect against CSRF Attacks.
if (!in_array($method, ['GET', 'HEAD'], true)
&& !$this->checkSecurityToken()) {
throw new \RuntimeException('Invalid security token;
please reload the page and try again.', 403);
}
if (!class_exists($class)) {
if ($format === 'json') {
// Special case: All HTML requests can be returned also as
JSON.
$response = $this->execute($resource, $method, $path,
$params, 'html');
return $response instanceof JsonResponse ? $response : new
JsonResponse($response);
}
throw new \RuntimeException('Page Not Found', 404);
}
/** @var BaseController $controller */
$controller = new $class($this->container);
// Execute action.
$response = $controller->execute($method, $path, $params);
if (!$response instanceof Response) {
$response = new HtmlResponse($response);
}
return $response;
}
/**
* @return $this
*/
abstract protected function boot();
abstract protected function checkSecurityToken();
/**
* @return $this
*/
public function load()
{
static $loaded = false;
if ($loaded) {
return $this;
}
$loaded = true;
if (isset($this->container['theme.path']) &&
file_exists($this->container['theme.path'] .
'/includes/gantry.php')) {
include $this->container['theme.path'] .
'/includes/gantry.php';
}
if (isset($this->container['theme'])) {
// Initialize current theme if it is set.
$this->container['theme'];
} else {
// Otherwise initialize streams and error handler manually.
$this->container['streams']->register();
$this->container->register(new ErrorServiceProvider);
}
$this->container['admin.theme'] = function () {
return new Theme(GANTRYADMIN_PATH);
};
// Add event listener.
if (class_exists('Gantry\\Admin\\EventListener')) {
$listener = new EventListener;
/** @var EventDispatcher $events */
$events = $this->container['events'];
$events->addSubscriber($listener);
}
// Boot the service.
$this->container['admin.theme'];
return $this;
}
protected function getErrorResponse(\Exception $e, $json = false)
{
$response = new HtmlResponse;
$response->setStatusCode($e->getCode());
$params = [
'ajax' => $json,
'title' => $response->getStatus(),
'error' => $e,
];
$response->setContent($this->container['admin.theme']->render('@gantry-admin/error.html.twig',
$params));
if ($json) {
return new JsonResponse([$e, $response]);
}
return $response;
}
protected function send(Response $response) {
// Output HTTP header.
header("HTTP/1.1 {$response->getStatus()}", true,
$response->getStatusCode());
header("Content-Type: {$response->mimeType};
charset={$response->charset}");
foreach ($response->getHeaders() as $key => $values) {
foreach ($values as $value) {
header("{$key}: {$value}");
}
}
echo $response;
return true;
}
}
PKU[�[X}�q&q&Stylesheet/CssCompiler.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Stylesheet;
use Gantry\Component\Config\Config;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Framework\Gantry;
use Leafo\ScssPhp\Colors;
use RocketTheme\Toolbox\File\PhpFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
abstract class CssCompiler implements CssCompilerInterface
{
use GantryTrait;
protected $type;
protected $name;
protected $debug = false;
protected $warnings = [];
/**
* @var array
*/
protected $fonts;
/**
* @var array
*/
protected $variables;
/**
* @var string
*/
protected $target = 'gantry-theme://css-compiled';
/**
* @var string
*/
protected $configuration = 'default';
/**
* @var array
*/
protected $paths;
/**
* @var array
*/
protected $files;
/**
* @var mixed
*/
protected $compiler;
/**
* @var bool
*/
protected $production;
public function __construct()
{
$gantry = static::gantry();
/** @var Config $global */
$global = $gantry['global'];
// In production mode we do not need to do any other checks.
$this->production = (bool)
$global->get('production');
}
public function getWarnings()
{
return $this->warnings;
}
/**
* @return string
*/
public function getTarget()
{
return $this->target;
}
/**
* @param string $target
* @return $this
*/
public function setTarget($target = null)
{
if ($target !== null) {
$this->target = (string) $target;
}
return $this;
}
/**
* @param string $configuration
* @return $this
*/
public function setConfiguration($configuration = null)
{
if ($configuration !== null) {
$this->configuration = $configuration;
}
return $this;
}
/**
* @param array $fonts
* @return $this
*/
public function setFonts(array $fonts = null)
{
if ($fonts !== null) {
// Normalize font data.
$list = [];
foreach ($fonts as $family => $data) {
$family = strtolower($family);
if (is_array($data)) {
// font: [400: url1, 500: url2, 700: url3]
$list[$family] = $data;
} else {
// font: url
$list[$family] = [400 => (string) $data];
}
}
$this->compiler->setFonts($list);
}
return $this;
}
/**
* @param array $paths
* @return $this
*/
public function setPaths(array $paths = null)
{
if ($paths !== null) {
$this->paths = $paths;
}
return $this;
}
/**
* @param array $files
* @return $this
*/
public function setFiles(array $files = null)
{
if ($files !== null) {
$this->files = $files;
}
return $this;
}
/**
* @param string $name
* @return string
*/
public function getCssUrl($name)
{
$out = $name . ($this->configuration !== 'default' ?
'_'. $this->configuration : '');
return "{$this->target}/{$out}.css";
}
/**
* @return $this
*/
public function compileAll()
{
foreach ($this->files as $file) {
$this->compileFile($file);
}
return $this;
}
public function needsCompile($in, $variables)
{
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$out = $this->getCssUrl($in);
$path = $locator->findResource($out);
// Check if CSS file exists at all.
if (!$path) {
$this->setVariables($variables());
return true;
}
if ($this->production) {
// Open the file to see if it contains development comment in
the beginning of the file.
$handle = fopen($path, 'rb');
$contents = fread($handle, 36);
fclose($handle);
if ($contents === '/* GANTRY5 DEVELOPMENT MODE
ENABLED.') {
$this->setVariables($variables());
return true;
}
// Compare checksum comment in the file.
if ($contents !== $this->checksum()) {
$this->setVariables($variables());
return true;
}
// In production mode we do not need to do any other checks.
return false;
}
$uri = basename($out);
$metaFile =
PhpFile::instance($locator->findResource("gantry-cache://theme/scss/{$uri}.php",
true, true));
// Check if meta file exists.
if (!$metaFile->exists()) {
$this->setVariables($variables());
return true;
}
$content = $metaFile->content();
$metaFile->free();
// Check if filename in meta file matches.
if (empty($content['file']) || $content['file']
!== $out) {
$this->setVariables($variables());
return true;
}
// Check if meta timestamp matches to CSS file.
if (filemtime($path) !== $content['timestamp']) {
$this->setVariables($variables());
return true;
}
$this->setVariables($variables());
// Check if variables have been changed.
$oldVariables = isset($content['variables']) ?
$content['variables'] : [];
if ($oldVariables != $this->getVariables()) {
return true;
}
// Preload all CSS files to locator cache.
foreach ($this->paths as $path) {
$locator->fillCache($path);
}
// Check if any of the imported files have been changed.
$imports = isset($content['imports']) ?
$content['imports'] : [];
if (!$imports) {
return $this->findImport($in) !== null;
}
foreach ($imports as $resource => $timestamp) {
$import = $locator->isStream($resource) ?
$locator->findResource($resource) : realpath($resource);
if (!$import || filemtime($import) !== $timestamp) {
return true;
}
}
return false;
}
public function setVariables(array $variables)
{
$this->variables = array_filter($variables);
foreach($this->variables as &$value) {
// Check variable against colors and units.
/* Test regex against these:
* Should only match the ones marked as +
* - family=Aguafina+Script
* - #zzzzzz
* - #fff
* + #ffaaff
* + 33em
* + 0.5px
* - 50 rem
* - rgba(323,323,2323)
* + rgba(125,200,100,0.3)
* - rgb(120,12,12)
*/
if
(preg_match('/(^(#([a-fA-F0-9]{6})|(rgba\(\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*(0|[1-9]\d?|1\d\d?|2[0-4]\d|25[0-5])\s*,\s*((0.[0-9]+)|[01])\s*\)))|(\d+(\.\d+){0,1}(rem|em|ex|ch|vw|vh|vmin|vmax|%|px|cm|mm|in|pt|pc))$)/i',
$value)) {
continue;
}
// Check variable against predefined color names (we use Leafo
SCSS Color class to do that).
if (isset(Colors::$cssColors[strtolower($value)])) {
continue;
}
// All the unknown values need to be quoted.
$value = "'{$value}'";
}
return $this;
}
public function getVariables()
{
return $this->variables;
}
public function reset()
{
$this->compiler->reset();
return $this;
}
/**
* @param string $url
* @return null|string
*/
abstract public function findImport($url);
protected function checksum($len = 36)
{
static $checksum;
if (!$checksum) {
$checksum = md5(GANTRY5_VERSION . ' ' .
Gantry::instance()['theme']->version);
}
return '/*' . substr($checksum, 0, $len - 4) .
'*/';
}
protected function createMeta($out, $md5)
{
$gantry = Gantry::instance();
if ($this->production) {
return;
}
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$uri = basename($out);
$metaFile =
PhpFile::instance($locator->findResource("gantry-cache://theme/scss/{$uri}.php",
true, true));
$data = [
'file' => $out,
'timestamp' =>
filemtime($locator->findResource($out)),
'md5' => $md5,
'variables' => $this->getVariables(),
'imports' =>
$this->compiler->getParsedFiles()
];
// Attempt to lock the file for writing.
try {
$metaFile->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will check this in a
bit.
}
// If meta file wasn't already locked by another process, save
it.
if ($metaFile->locked() !== false) {
$metaFile->save($data);
$metaFile->unlock();
}
$metaFile->free();
}
}
PKU[�[�03��#Stylesheet/CssCompilerInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Stylesheet;
interface CssCompilerInterface
{
/**
* @return array
*/
public function getWarnings();
/**
* @return string
*/
public function getTarget();
/**
* @param string $target
* @return $this
*/
public function setTarget($target = null);
/**
* @param string $configuration
* @return $this
*/
public function setConfiguration($configuration = null);
/**
* @param array $paths
* @return $this
*/
public function setPaths(array $paths = null);
/**
* @param array $files
* @return $this
*/
public function setFiles(array $files = null);
/**
* @param array $fonts
* @return $this
*/
public function setFonts(array $fonts);
/**
* @param string $name
* @return string
*/
public function getCssUrl($name);
public function getVariables();
public function setVariables(array $variables);
public function registerFunction($name, callable $callback);
public function unregisterFunction($name);
public function needsCompile($in, $variables);
public function compileFile($in);
/**
* @return $this
*/
public function reset();
/**
* @return $this
*/
public function compileAll();
public function resetCache();
}
PKU[�[�d瑄,�,Stylesheet/Scss/Compiler.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Stylesheet\Scss;
use Gantry\Component\Filesystem\Folder;
use Gantry\Framework\Document;
use Gantry\Framework\Gantry;
use Leafo\ScssPhp\Compiler as BaseCompiler;
use Leafo\ScssPhp\Formatter\OutputBlock;
use Leafo\ScssPhp\Parser;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Compiler extends BaseCompiler
{
protected $basePath;
protected $fonts;
protected $usedFonts;
protected $streamNames;
protected $parsedFiles = [];
public function __construct()
{
parent::__construct();
$this->registerFunction('get-font-url', [$this,
'userGetFontUrl']);
$this->registerFunction('get-font-family', [$this,
'userGetFontFamily']);
$this->registerFunction('get-local-fonts', [$this,
'userGetLocalFonts']);
$this->registerFunction('get-local-font-weights',
[$this, 'userGetLocalFontWeights']);
$this->registerFunction('get-local-font-url', [$this,
'userGetLocalFontUrl']);
}
/**
* @param $basePath
*/
public function setBasePath($basePath)
{
/** @var Document $document */
$document = Gantry::instance()['document'];
$this->basePath = rtrim($document->rootUri(), '/')
. '/' . Folder::getRelativePath($basePath);
}
/**
* @param array $fonts
*/
public function setFonts(array $fonts)
{
$this->fonts = $fonts;
}
/**
* @param $args
* @return mixed
*/
public function compileArgs($args)
{
foreach ($args as &$arg) {
$arg = $this->compileValue($arg);
}
return $args;
}
/**
* Get variable
*
* @api
*
* @param string $name
* @param boolean $shouldThrow
* @param BaseCompiler\Environment $env
* @param bool $unreduced
*
* @return mixed
*/
public function get($name, $shouldThrow = true,
BaseCompiler\Environment $env = null, $unreduced = false)
{
try {
return parent::get($name, $shouldThrow, $env, $unreduced);
} catch (\Exception $e) {
echo $e->getMessage() . "\n";
return ['string', '', ['']];
}
}
/**
* @param array $args
* @return string
* @throws \Leafo\ScssPhp\Exception\CompilerException
*/
public function libUrl(array $args)
{
// Function has a single parameter.
$parsed = reset($args);
if (!$parsed) {
$this->throwError('url() is missing parameter');
}
// Compile parsed value to string.
$url = trim($this->compileValue($parsed),
'\'"');
// Handle ../ inside CSS files (points to current theme).
if (strpos($url, '../') === 0 && strpos($url,
'../', 3) === false) {
$url = 'gantry-theme://' . substr($url, 3);
}
// Generate URL, failed streams will be transformed to 404 URLs.
$url = Gantry::instance()['document']->url($url, null,
null, false);
// Changes absolute URIs to relative to make the path to work even
if the site gets moved.
if ($url && $url[0] === '/' &&
$this->basePath) {
$url = Folder::getRelativePathDotDot($url, $this->basePath);
}
// Make sure that all the URLs inside CSS are https compatible by
replacing http:// protocol with //.
if (strpos($url, 'http://') === 0) {
$url = str_replace('http://', '//', $url);
}
// Return valid CSS.
return "url('{$url}')";
}
/**
* get-font-url($my-font-variable);
*
* @param array $args
* @return string
*/
public function userGetFontUrl($args)
{
$value = trim($this->compileValue(reset($args)),
'\'"');
// It's a google font
if (0 === strpos($value, 'family=')) {
$fonts = $this->decodeFonts($value);
$font = reset($fonts);
// Only return url once per font.
if ($font && !isset($this->usedFonts[$font])) {
$this->usedFonts[$font] = true;
return
"url('//fonts.googleapis.com/css?{$value}')";
}
}
return false;
}
/**
* font-family: get-font-family($my-font-variable);
*
* @param array $args
* @return string
*/
public function userGetFontFamily($args)
{
$value = trim($this->compileValue(reset($args)),
'\'"');
return $this->encodeFonts($this->decodeFonts($value));
}
/**
* get-local-fonts($my-font-variable, $my-font-variable2, ...);
*
* @param array $args
* @return array
*/
public function userGetLocalFonts($args)
{
$args = $this->compileArgs($args);
$fonts = [];
foreach ($args as $value) {
// It's a local font, we need to load any of the mapped
fonts from the theme
$fonts = array_merge($fonts, $this->decodeFonts($value,
true));
}
$fonts = $this->getLocalFonts($fonts);
// Create a basic list of strings so that SCSS parser can parse the
list.
$list = [];
foreach ($fonts as $font => $data) {
$list[] = ['string', '"', [$font]];
}
return ['list', ',', $list];
}
/**
* get-local-font-weights(roboto);
*
* @param array $args
* @return array
*/
public function userGetLocalFontWeights($args)
{
$name = trim($this->compileValue(reset($args)),
'\'"');
$weights = isset($this->fonts[$name]) ?
array_keys($this->fonts[$name]) : [];
// Create a list of numbers so that SCSS parser can parse the list.
$list = [];
foreach ($weights as $weight) {
$list[] = ['string', '', [(int) $weight]];
}
return ['list', ',', $list];
}
/**
* get-local-font-url(roboto, 400);
*
* @param array $args
* @return string
*/
public function userGetLocalFontUrl($args)
{
$args = $this->compileArgs($args);
$name = isset($args[0]) ? trim($args[0], '\'"')
: '';
$weight = isset($args[1]) ? $args[1] : 400;
// Only return url once per font.
$weightName = $name . '-' . $weight;
if (isset($this->fonts[$name][$weight]) &&
!isset($this->usedFonts[$weightName])) {
$this->usedFonts[$weightName] = true;
return $this->fonts[$name][$weight];
}
return false;
}
/**
* Get local font data.
*
* @param array $fonts
* @return array
*/
protected function getLocalFonts(array $fonts)
{
$list = [];
foreach ($fonts as $family) {
$family = strtolower($family);
if (isset($this->fonts[$family])) {
$list[$family] = $this->fonts[$family];
}
}
return $list;
}
/**
* Convert array of fonts into a CSS parameter string.
*
* @param array $fonts
* @return string
*/
protected function encodeFonts(array $fonts)
{
array_walk($fonts, function(&$val) {
// Check if font family is one of the 4 default ones, otherwise
add quotes.
if (!\in_array($val, ['cursive', 'serif',
'sans-serif', 'monospace'], true)) {
$val = '"' . $val . '"';
}
});
return implode(', ', $fonts);
}
/**
* Convert string into array of fonts.
*
* @param string $string
* @param bool $localOnly
* @return array
*/
protected function decodeFonts($string, $localOnly = false)
{
if (0 === strpos($string, 'family=')) {
if ($localOnly) {
// Do not return external fonts.
return [];
}
// Matches google font family name
preg_match('/^family=([^&:]+).*$/ui', $string,
$matches);
return [urldecode($matches[1])];
}
// Filter list of fonts and quote them.
$list = (array) explode(',', $string);
array_walk($list, function(&$val) {
$val = trim($val, "'\" \t\n\r\0\x0B");
});
array_filter($list);
return $list;
}
public function reset()
{
$this->usedFonts = [];
return $this;
}
/**
* Instantiate parser
*
* @param string $path
*
* @return \Leafo\ScssPhp\Parser
*/
protected function parserFactory($path)
{
$parser = new Parser($path, count($this->sourceNames),
$this->encoding);
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
$this->sourceNames[] = $locator->isStream($path) ?
$locator->findResource($path, false) : $path;
$this->streamNames[] = $path;
$this->addParsedFile($path);
return $parser;
}
/**
* Adds to list of parsed files
*
* @api
*
* @param string $path
*/
public function addParsedFile($path)
{
if ($path && file_exists($path)) {
$this->parsedFiles[$path] = filemtime($path);
}
}
/**
* Returns list of parsed files
*
* @api
*
* @return array
*/
public function getParsedFiles()
{
return $this->parsedFiles;
}
/**
* Clean parset files.
*
* @api
*/
public function cleanParsedFiles()
{
$this->parsedFiles = [];
}
/**
* Handle import loop
*
* @param string $name
*
* @throws \Exception
*/
protected function handleImportLoop($name)
{
for ($env = $this->env; $env; $env = $env->parent) {
$file = $this->streamNames[$env->block->sourceIndex];
if (realpath($file) === $name) {
$this->throwError('An @import loop has been found:
%s imports %s', $file, basename($file));
break;
}
}
}
/**
* Override function to improve the logic.
*
* @param string $path
* @param OutputBlock $out
*
* @throws \Exception
*/
protected function importFile($path, OutputBlock $out)
{
$this->addParsedFile($path);
/** @var UniformResourceLocator $locator */
$locator = Gantry::instance()['locator'];
// see if tree is cached
$realPath = $locator($path);
if (isset($this->importCache[$realPath])) {
$this->handleImportLoop($realPath);
$tree = $this->importCache[$realPath];
} else {
$code = file_get_contents($realPath);
$parser = $this->parserFactory($path);
$tree = $parser->parse($code);
$this->importCache[$realPath] = $tree;
}
$dirname = dirname($path);
array_unshift($this->importPaths, $dirname);
$this->compileChildrenNoReturn($tree->children, $out);
array_shift($this->importPaths);
}
}
PKU[�[�}��Stylesheet/ScssCompiler.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Stylesheet;
use Gantry\Component\Stylesheet\Scss\Compiler;
use Gantry\Framework\Document;
use Gantry\Framework\Gantry;
use Leafo\ScssPhp\Exception\CompilerException;
use RocketTheme\Toolbox\File\File;
use RocketTheme\Toolbox\File\JsonFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class ScssCompiler extends CssCompiler
{
/**
* @var string
*/
public $type = 'scss';
/**
* @var string
*/
public $name = 'SCSS';
/**
* @var Compiler
*/
protected $compiler;
/**
* Constructor.
*/
public function __construct()
{
parent::__construct();
$this->compiler = new Compiler();
if ($this->production) {
$this->compiler->setFormatter('Leafo\ScssPhp\Formatter\Crunched');
} else {
$this->compiler->setFormatter('Leafo\ScssPhp\Formatter\Expanded');
// Work around bugs in SCSS compiler.
// TODO: Pass our own SourceMapGenerator instance instead.
$this->compiler->setSourceMap(Compiler::SOURCE_MAP_INLINE);
$this->compiler->setSourceMapOptions([
'sourceMapBasepath' => '/',
'sourceRoot' => '/',
]);
$this->compiler->setLineNumberStyle(Compiler::LINE_COMMENTS);
}
}
public function compile($in)
{
return $this->compiler->compile($in);
}
public function resetCache()
{
}
/**
* @param string $in Filename without path or extension.
* @return bool True if the output file was saved.
* @throws \RuntimeException
*/
public function compileFile($in)
{
// Buy some extra time as compilation may take a lot of time in
shared environments.
@set_time_limit(30);
@set_time_limit(60);
@set_time_limit(90);
@set_time_limit(120);
ob_start();
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$out = $this->getCssUrl($in);
$path = $locator->findResource($out, true, true);
$file = File::instance($path);
// Attempt to lock the file for writing.
try {
$file->lock(false);
} catch (\Exception $e) {
// Another process has locked the file; we will check this in a
bit.
}
if ($file->locked() === false) {
// File was already locked by another process, lets avoid
compiling the same file twice.
return false;
}
// Set the lookup paths.
$this->compiler->setBasePath($path);
$this->compiler->setImportPaths([[$this,
'findImport']]);
// Run the compiler.
$this->compiler->setVariables($this->getVariables());
$scss = '@import "' . $in . '.scss"';
try {
$css = $this->compiler->compile($scss);
} catch (CompilerException $e) {
throw new \RuntimeException("CSS Compilation on file
'{$in}.scss' failed on error: {$e->getMessage()}", 500,
$e);
}
if (strpos($css, $scss) === 0) {
$css = '/* ' . $scss . ' */';
}
// Extract map from css and save it as separate file.
if ($pos = strrpos($css, '/*# sourceMappingURL=')) {
$map = json_decode(urldecode(substr($css, $pos + 43, -3)),
true);
/** @var Document $document */
$document = $gantry['document'];
foreach ($map['sources'] as &$source) {
$source = $document->url($source, null, -1);
}
unset($source);
$mapFile = JsonFile::instance($path . '.map');
$mapFile->save($map);
$mapFile->free();
$css = substr($css, 0, $pos) . '/*#
sourceMappingURL=' . basename($out) . '.map */';
}
$warnings = trim(ob_get_clean());
if ($warnings) {
$this->warnings[$in] = explode("\n", $warnings);
}
if (!$this->production) {
$warning = <<<WARN
/* GANTRY5 DEVELOPMENT MODE ENABLED.
WARNING: This file is automatically generated by Gantry5. Any
modifications to this file will be lost!
For more information on modifying CSS, please read:
http://docs.gantry.org/gantry5/configure/styles
http://docs.gantry.org/gantry5/tutorials/adding-a-custom-style-sheet
*/
WARN;
$css = $warning . "\n\n" . $css;
} else {
$css = "{$this->checksum()}\n{$css}";
}
$file->save($css);
$file->unlock();
$file->free();
$this->createMeta($out, md5($css));
$this->compiler->cleanParsedFiles();
return true;
}
/**
* @param string $name Name of function to register to the
compiler.
* @param callable $callback Function to run when called by the
compiler.
* @return $this
*/
public function registerFunction($name, callable $callback)
{
$this->compiler->registerFunction($name, $callback);
return $this;
}
/**
* @param string $name Name of function to unregister.
* @return $this
*/
public function unregisterFunction($name)
{
$this->compiler->unregisterFunction($name);
return $this;
}
/**
* @param string $url
* @return null|string
* @internal
*/
public function findImport($url)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Ignore vanilla css and external requests.
if (preg_match('/\.css$|^https?:\/\//', $url)) {
return null;
}
// Try both normal and the _partial filename.
$files = array($url, preg_replace('/[^\/]+$/',
'_\0', $url));
foreach ($this->paths as $base) {
foreach ($files as $file) {
if (!preg_match('|\.scss$|', $file)) {
$file .= '.scss';
}
if ($locator->findResource($base . '/' .
$file)) {
return $base . '/' . $file;
}
}
}
return null;
}
}
PKU[�[�i}}System/Messages.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license GNU/GPLv2 and later
*
* http://www.gnu.org/licenses/gpl-2.0.html
*/
namespace Gantry\Component\System;
class Messages
{
protected $messages = [];
public function add($message, $type = 'warning')
{
$this->messages[] = ['type' => $type,
'message' => $message];
return $this;
}
public function get()
{
return $this->messages;
}
public function clean()
{
$this->messages = [];
return $this;
}
}
PKV[�[�Y�22Theme/AbstractTheme.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\Config\Config;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Component\Twig\TwigCacheFilesystem;
use Gantry\Component\Twig\TwigExtension;
use Gantry\Framework\Platform;
use Gantry\Framework\Services\ErrorServiceProvider;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Class AbstractTheme
* @package Gantry\Component
*
* @property string $path
* @property string $layout
*/
abstract class AbstractTheme
{
use GantryTrait;
/**
* @var string
*/
public $name;
/**
* @var string
*/
public $path;
/**
* @var \Twig_Environment
*/
protected $renderer;
/**
* Construct theme object.
*
* @param string $path
* @param string $name
*/
public function __construct($path, $name = null)
{
if (!is_dir($path)) {
throw new \LogicException('Theme not found!');
}
$this->name = $name ? $name : basename($path);
$this->path = $path;
$this->init();
}
/**
* Get context for render().
*
* @param array $context
* @return array
*/
public function getContext(array $context)
{
$context['theme'] = $this;
return $context;
}
/**
* Define twig environment.
*
* @param \Twig_Environment $twig
* @param \Twig_LoaderInterface $loader
* @return \Twig_Environment
*/
public function extendTwig(\Twig_Environment $twig,
\Twig_LoaderInterface $loader = null)
{
if
($twig->hasExtension('Gantry\Component\Twig\TwigExtension')) {
return $twig;
}
if (!$loader) {
$loader = $twig->getLoader();
}
$this->setTwigLoaderPaths($loader);
$twig->addExtension(new TwigExtension);
if (method_exists($this, 'toGrid')) {
$filter = new \Twig_SimpleFilter('toGrid', [$this,
'toGrid']);
$twig->addFilter($filter);
}
return $twig;
}
/**
* Return renderer.
*
* @return \Twig_Environment
*/
public function renderer()
{
if (!$this->renderer) {
$gantry = static::gantry();
/** @var Config $global */
$global = $gantry['global'];
$cachePath = $global->get('compile_twig', 1) ?
$this->getCachePath('twig') : null;
$cache = $cachePath ? new TwigCacheFilesystem($cachePath,
\Twig_Cache_Filesystem::FORCE_BYTECODE_INVALIDATION) : null;
$debug = $gantry->debug();
$production = (bool) $global->get('production',
1);
$loader = new \Twig_Loader_Filesystem();
$params = [
'cache' => $cache,
'debug' => $debug,
'auto_reload' => !$production,
'autoescape' => 'html'
];
$twig = new \Twig_Environment($loader, $params);
$this->setTwigLoaderPaths($loader);
if ($debug) {
$twig->addExtension(new \Twig_Extension_Debug());
}
$this->renderer = $this->extendTwig($twig, $loader);
}
return $this->renderer;
}
/**
* Render a template file by using given context.
*
* @param string $file
* @param array $context
* @return string
*/
public function render($file, array $context = [])
{
// Include Gantry specific things to the context.
$context = $this->getContext($context);
return $this->renderer()->render($file, $context);
}
/**
* Compile and render twig string.
*
* @param string $string
* @param array $context
* @return string
*/
public function compile($string, array $context = [])
{
$renderer = $this->renderer();
$template = $renderer->createTemplate($string);
// Include Gantry specific things to the context.
$context = $this->getContext($context);
return $template->render($context);
}
/**
* Initialize theme.
*/
protected function init()
{
$gantry = static::gantry();
$gantry['streams']->register();
// Only add error service if development or debug mode has been
enabled or user is admin.
if (!$gantry['global']->get('production', 0)
|| $gantry->debug() || $gantry->admin()) {
$gantry->register(new ErrorServiceProvider);
}
// Initialize theme cache stream.
$cachePath = $this->getCachePath();
Folder::create($cachePath);
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$locator->addPath('gantry-cache', 'theme',
[$cachePath], true, true);
CompiledYamlFile::$defaultCachePath =
$locator->findResource('gantry-cache://theme/compiled/yaml',
true, true);
CompiledYamlFile::$defaultCaching =
$gantry['global']->get('compile_yaml', 1);
}
/**
* Set twig lookup paths to the loader.
*
* @param \Twig_LoaderInterface $loader
* @return \Twig_Loader_Filesystem|null
* @internal
*/
protected function setTwigLoaderPaths(\Twig_LoaderInterface $loader)
{
if ($loader instanceof \Twig_Loader_Chain) {
$new = new \Twig_Loader_Filesystem();
$loader->addLoader($new);
$loader = $new;
} elseif (!($loader instanceof \Twig_Loader_Filesystem)) {
return null;
}
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$loader->setPaths($locator->findResources('gantry-engine://templates'),
'nucleus');
$loader->setPaths($locator->findResources('gantry-particles://'),
'particles');
return $loader;
}
/**
* Get path to Twig cache.
*
* @param string $path
* @return string
*/
protected function getCachePath($path = '')
{
$gantry = static::gantry();
/** @var Platform $patform */
$patform = $gantry['platform'];
// Initialize theme cache stream.
return $patform->getCachePath() . '/' . $this->name
. ($path ? '/' . $path : '');
}
/**
* @deprecated 5.0.2
*/
public function debug()
{
return static::gantry()->debug();
}
/**
* @deprecated 5.1.5
*/
public function add_to_context(array $context)
{
return $this->getContext($context);
}
/**
* @deprecated 5.1.5
*/
public function add_to_twig(\Twig_Environment $twig,
\Twig_LoaderInterface $loader = null)
{
return $this->extendTwig($twig, $loader);
}
}
PKV[�[�����Theme/ThemeDetails.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Streams;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ArrayTraits\Export;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccessWithGetters;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Class ThemeDetails
* @package Gantry\Component\Theme
*/
class ThemeDetails implements \ArrayAccess
{
use NestedArrayAccessWithGetters, Export;
protected $items;
protected $parent;
/**
* Create new theme details.
*
* @param string $theme
*/
public function __construct($theme)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$filename =
$locator->findResource("gantry-themes://{$theme}/gantry/theme.yaml");
if (!$filename) {
throw new \RuntimeException(sprintf('Theme %s not
found', $theme), 404);
}
$cache =
$locator->findResource("gantry-cache://{$theme}/compiled/yaml",
true, true);
$file = CompiledYamlFile::instance($filename);
$this->items = $file->setCachePath($cache)->content();
$file->free();
$this->offsetSet('name', $theme);
$parent = (string)
$this->get('configuration.theme.parent', $theme);
$parent = $parent != $theme ? $parent : null;
$this->offsetSet('parent', $parent);
}
/**
* @return string
*/
public function addStreams()
{
$gantry = Gantry::instance();
// Initialize theme stream.
$streamName =
$this->addStream($this->offsetGet('name'),
$this->getPaths());
// Initialize parent theme streams.
$loaded = [$this->offsetGet('name')];
$details = $this;
while ($details = $details->parent()) {
if (in_array($details->name, $loaded)) {
break;
}
$this->addStream($details->name,
$details->getPaths(false));
$loaded[] = $details->name;
}
/** @var Streams $streams */
$streams = $gantry['streams'];
$streams->register();
return $streamName;
}
/**
* Get parent theme details if theme has a parent.
*
* @return ThemeDetails|null
* @throws \RuntimeException
*/
public function parent()
{
$parent = $this->offsetGet('parent');
if (!$this->parent && $parent) {
try {
$this->parent = new ThemeDetails($parent);
} catch (\RuntimeException $e) {
throw new \RuntimeException(sprintf('Parent theme %s
not found', $parent), 404);
}
}
return $this->parent;
}
/**
* Get all possible paths to the theme.
*
* @return array
*/
public function getPaths($overrides = true)
{
$paths = array_merge(
$overrides ? (array)
$this->get('configuration.theme.overrides',
'gantry-theme://custom') : [],
['gantry-theme://'],
(array) $this->get('configuration.theme.base',
'gantry-theme://common')
);
$parent = $this->offsetGet('parent');
if ($parent) {
// Stream needs to be valid URL.
$streamName = 'gantry-themes-' .
preg_replace('|[^a-z\d+.-]|ui', '-', $parent);
$paths[] = "{$streamName}://";
}
return $this->parsePaths($paths);
}
/**
* Convert theme path into stream URI.
*
* @param string $path
* @return string
*/
public function getUrl($path)
{
$uri = (string) $this->offsetGet($path);
if (strpos($uri, 'gantry-theme://') === 0) {
list (, $uri) = explode('://', $uri, 2);
}
if (!strpos($uri, '://')) {
$name = $this->offsetGet('name');
// Stream needs to be valid URL.
$streamName = 'gantry-themes-' .
preg_replace('|[^a-z\d+.-]|ui', '-', $name);
$uri = "{$streamName}://{$uri}";
}
return $uri;
}
/**
* Turn list of theme paths to be universal, so they can be used
outside of the theme.
*
* @param array $items
* @return array
*/
public function parsePaths(array $items)
{
foreach ($items as &$item) {
$item = $this->parsePath($item);
}
return $items;
}
/**
* Convert theme paths to be universal, so they can be used outside of
the theme.
*
* @param string $path
* @return string
*/
public function parsePath($path)
{
if (strpos($path, 'gantry-theme://') === 0) {
list (, $path) = explode('://', $path, 2);
}
if (!strpos($path, '://')) {
$name = $this->offsetGet('name');
$path = "gantry-themes://{$name}/{$path}";
}
return $path;
}
/**
* @return string|null
* @deprecated 5.1.5
*/
public function getParent()
{
return $this->offsetGet('parent');
}
/**
* @param string $name
* @param array $paths
* @return string|null
*/
protected function addStream($name, $paths)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
/** @var Streams $streams */
$streams = $gantry['streams'];
// Add theme stream.
$streamName = 'gantry-themes-' .
preg_replace('|[^a-z\d+.-]|ui', '-', $name);
if (!$locator->schemeExists($streamName)) {
$streams->add([$streamName => ['paths' =>
$paths]]);
}
return $streamName;
}
}
PKX[�[1���%�%Theme/ThemeInstaller.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Layout\Layout;
use Gantry\Framework\Gantry;
use Gantry\Framework\Platform;
use Gantry\Framework\Services\ErrorServiceProvider;
use RocketTheme\Toolbox\File\YamlFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
abstract class ThemeInstaller
{
/**
* Set to true if in Gantry.
*
* @var bool
*/
public $initialized = false;
public $actions = [];
protected $name;
protected $outlines;
protected $script;
public function __construct($extension = null)
{
if ($extension) {
$this->name = $extension;
}
}
abstract public function getPath();
/**
* Get list of available outlines.
*
* @param array $filter
* @return array
*/
public function getOutlines(array $filter = null)
{
if (!isset($this->outlines)) {
$this->outlines = [];
$path = $this->getPath();
// If no outlines are given, try loading outlines.yaml file.
$file = YamlFile::instance($path .
'/install/outlines.yaml');
if ($file->exists()) {
// Load the list from the yaml file.
$this->outlines = (array) $file->content();
$file->free();
} elseif (is_dir($path . '/install/outlines')) {
// Build the list from the install folder.
// recurse = false, full=true
$folders = Folder::all($path .
'/install/outlines', ['folders' => true,
'recursive' => false]);
foreach ($folders as $folder) {
$this->outlines[basename($folder)] = [];
}
}
// Always include system outlines.
$this->outlines += ['default' => [],
'_body_only' => [], '_error' => [],
'_offline' => []];
}
return is_array($filter) ? array_intersect_key($this->outlines,
array_flip($filter)) : $this->outlines;
}
public function getOutline($name)
{
$list = $this->getOutlines([$name]);
return reset($list);
}
public function installDefaults()
{
$installerScript = $this->getInstallerScript();
if ($installerScript && method_exists($installerScript,
'installDefaults')) {
$installerScript->installDefaults($this);
} else {
$this->createDefaults();
}
}
public function installSampleData()
{
$installerScript = $this->getInstallerScript();
if ($installerScript && method_exists($installerScript,
'installSampleData')) {
$installerScript->installSampleData($this);
} else {
$this->createSampleData();
}
}
public function createDefaults()
{
$this->createOutlines();
}
public function createSampleData()
{
}
public function render($template, $context = [])
{
try {
$loader = new \Twig_Loader_Filesystem();
$loader->setPaths([$this->getPath() .
'/install/templates']);
$params = [
'cache' => null,
'debug' => false,
'autoescape' => 'html'
];
$twig = new \Twig_Environment($loader, $params);
$name = $this->name;
$context += [
'name' => $this->translate($name),
'actions' => $this->actions
];
return $twig->render($template, $context);
} catch (\Exception $e) {
return '';
}
}
/**
* Set available outlines.
*
* @param array $outlines If parameter isn't provided, outlines
list get reloaded from the disk.
* @return $this
*/
public function setOutlines(array $outlines = null)
{
$this->outlines = $outlines;
return $this;
}
/**
* @param array $filter
*/
public function createOutlines(array $filter = null)
{
$outlines = $this->getOutlines($filter);
foreach ($outlines as $folder => $params) {
$this->createOutline($folder, $params);
}
}
/**
* @param string $folder
* @param array $params
* @return string|bool
*/
public function createOutline($folder, array $params = [])
{
if (!$folder) {
throw new \RuntimeException('Cannot create outline without
folder name');
}
$this->initialize();
$created = false;
$params += [
'preset' => null,
'title' => null
];
$title = $params['title'] ?: ucwords(trim(strtr($folder,
['_' => ' '])));
$preset = $params['preset'] ?: 'default';
// Copy configuration for the new layout.
if (($this->copyCustom($folder, $folder) || $created)) {
// Update layout and save it.
$layout = Layout::load($folder, $preset);
$layout->save()->saveIndex();
if ($created) {
$this->actions[] = ['action' =>
'outline_created', 'text' =>
$this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_CREATED',
$title)];
} else {
$this->actions[] = ['action' =>
'outline_updated', 'text' =>
$this->translate('GANTRY5_INSTALLER_ACTION_OUTLINE_UPDATED',
$title)];
}
}
return $folder;
}
public function initialize()
{
if ($this->initialized) {
return;
}
$name = $this->name;
$path = $this->getPath();
// Remove compiled CSS files if they exist.
$cssPath = $path . '/custom/css-compiled';
if (is_dir($cssPath)) {
Folder::delete($cssPath);
} elseif (is_file($cssPath)) {
@unlink($cssPath);
}
// Remove wrongly named file if it exists.
$md5path = $path . '/MD5SUM';
if (is_file($md5path)) {
@unlink($md5path);
}
// Restart Gantry and initialize it.
$gantry = Gantry::restart();
$gantry['theme.name'] = $name;
$gantry['streams']->register();
// Only add error service if debug mode has been enabled.
if ($gantry->debug()) {
$gantry->register(new ErrorServiceProvider);
}
/** @var Platform $patform */
$patform = $gantry['platform'];
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
// Initialize theme stream.
$details = new ThemeDetails($name);
$locator->addPath('gantry-theme', '',
$details->getPaths(), false, true);
// Initialize theme cache stream and clear theme cache.
$cachePath = $patform->getCachePath() . '/' . $name;
if (is_dir($cachePath)) {
Folder::delete($cachePath);
}
Folder::create($cachePath);
$locator->addPath('gantry-cache', 'theme',
[$cachePath], true, true);
CompiledYamlFile::$defaultCachePath =
$locator->findResource('gantry-cache://theme/compiled/yaml',
true, true);
CompiledYamlFile::$defaultCaching =
$gantry['global']->get('compile_yaml', 1);
$this->initialized = true;
}
public function finalize()
{
// Copy standard outlines if they haven't been copied already.
$this->copyCustom('default', 'default');
$this->copyCustom('_body_only',
'_body_only');
$this->copyCustom('_error', '_error');
$this->copyCustom('_offline', '_offline');
$this->initialize();
}
/**
* @param string $layout
* @param string $id
* @return bool True if files were copied over.
*/
protected function copyCustom($layout, $id)
{
$path = $this->getPath();
// Only copy files if the target id doesn't exist.
$dst = $path . '/custom/config/' . $id;
if (!$layout || !$id || is_dir($dst)) {
return false;
}
// New location for G5.3.2+
$src = $path . '/install/outlines/' . $layout;
if (!is_dir($src)) {
// Old and deprecated location.
$src = $path . '/install/layouts/' . $layout;
}
try {
is_dir($src) ? Folder::copy($src, $dst) : Folder::create($dst);
} catch (\Exception $e) {
throw new \RuntimeException("Creating configuration for
outline '{$layout}' failed: {$e->getMessage()}", 500,
$e);
}
return true;
}
protected function translate($text)
{
$translator = Gantry::instance()['translator'];
$args = func_get_args();
return call_user_func_array([$translator, 'translate'],
$args);
}
protected function getInstallerScript()
{
if (!$this->script) {
$className = ucfirst($this->name) .
'InstallerScript';
if (!class_exists($className)) {
$path = "{$this->getPath()}/install.php";
if (is_file($path)) {
require_once $path;
}
}
if (class_exists($className)) {
$this->script = new $className;
}
}
return $this->script;
}
}
PKX[�[��IA��Theme/ThemeInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\Config\Config;
use Gantry\Component\Layout\Layout;
use Gantry\Component\Stylesheet\CssCompilerInterface;
/**
* Class ThemeTrait
* @package Gantry\Framework\Base
*
* @property string $path
* @property string $layout
*/
interface ThemeInterface
{
// AbstractTheme class
/**
* Get context for render().
*
* @param array $context
* @return array
*/
public function getContext(array $context);
/**
* Define twig environment.
*
* @param \Twig_Environment $twig
* @param \Twig_LoaderInterface $loader
* @return \Twig_Environment
*/
public function extendTwig(\Twig_Environment $twig,
\Twig_LoaderInterface $loader = null);
/**
* Returns renderer.
*
* @return \Twig_Environment
*/
public function renderer();
/**
* Render a template file.
*
* @param string $file
* @param array $context
* @return string
*/
public function render($file, array $context = array());
// ThemeTrait class
/**
* Update all CSS files in the theme.
*
* @param array $outlines
* @return array List of CSS warnings.
*/
public function updateCss(array $outlines = null);
/**
* Set current layout.
*
* @param string $name
* @param bool $force
* @return $this
*/
public function setLayout($name = null, $force = false);
/**
* Get current preset.
*
* @param bool $forced If true, return only forced preset or null.
* @return string|null $preset
*/
public function preset($forced = false);
/**
* Set preset to be used.
*
* @param string $name
* @return $this
*/
public function setPreset($name = null);
/**
* Return CSS compiler used in the theme.
*
* @return CssCompilerInterface
* @throws \RuntimeException
*/
public function compiler();
/**
* Returns URL to CSS file.
*
* If file does not exist, it will be created by using CSS compiler.
*
* @param string $name
* @return string
*/
public function css($name);
/**
* Return all CSS variables.
*
* @return array
*/
public function getCssVariables();
/**
* Returns style presets for the theme.
*
* @return Config
*/
public function presets();
/**
* Return name of the used layout preset.
*
* @return string
* @throws \RuntimeException
*/
public function type();
/**
* Load current layout and its configuration.
*
* @param string $name
* @return Layout
* @throws \LogicException
*/
public function loadLayout($name = null);
/**
* Check whether layout has content bock.
*
* @return bool
*/
public function hasContent();
/**
* Returns all non-empty segments from the layout.
*
* @return array
*/
public function segments();
/**
* Returns details of the theme.
*
* @return ThemeDetails
*/
public function details();
/**
* Returns configuration of the theme.
*
* @return array
*/
public function configuration();
/**
* Function to convert block sizes into CSS classes.
*
* @param $text
* @return string
*/
public function toGrid($text);
}
PKX[�[b����Z�ZTheme/ThemeTrait.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Theme;
use Gantry\Component\Config\Config;
use Gantry\Component\Content\Block\ContentBlock;
use Gantry\Component\Content\Block\HtmlBlock;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Component\Filesystem\Folder;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Component\Layout\Layout;
use Gantry\Component\Stylesheet\CssCompilerInterface;
use Gantry\Framework\Document;
use Gantry\Framework\Menu;
use Gantry\Framework\Services\ConfigServiceProvider;
use RocketTheme\Toolbox\File\PhpFile;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
/**
* Class ThemeTrait
* @package Gantry\Component
*
* @property string $path
* @property string $layout
*/
trait ThemeTrait
{
use GantryTrait;
protected $layoutObject;
protected $atoms;
protected $segments;
protected $preset;
protected $cssCache;
/**
* @var CssCompilerInterface
*/
protected $compiler;
protected $equalized = [3 => 33.3, 6 => 16.7, 7 => 14.3, 8
=> 12.5, 9 => 11.1, 11 => 9.1, 12 => 8.3];
/**
* @var ThemeDetails
*/
protected $details;
/**
* Register Theme stream.
*
* @param string $savePath
*/
public function registerStream($savePath = null)
{
$streamName = $this->details()->addStreams();
/** @var UniformResourceLocator $locator */
$locator = self::gantry()['locator'];
$locator->addPath('gantry-theme', '',
array_merge((array) $savePath, [[$streamName, '']]));
}
/**
* Update all CSS files in the theme.
*
* @param array $outlines
* @return array List of CSS warnings.
*/
public function updateCss(array $outlines = null)
{
$gantry = static::gantry();
$compiler = $this->compiler();
if (is_null($outlines)) {
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$path = $locator->findResource($compiler->getTarget(),
true, true);
// Make sure that all the CSS files get deleted.
if (is_dir($path)) {
Folder::delete($path, false);
}
$outlines = $gantry['outlines'];
}
// Make sure that PHP has the latest data of the files.
clearstatcache();
$warnings = [];
foreach ($outlines as $outline => $title) {
$config = ConfigServiceProvider::load($gantry, $outline);
$compiler->reset()->setConfiguration($outline)->setVariables($config->flatten('styles',
'-'));
$results = $compiler->compileAll()->getWarnings();
if ($results) {
$warnings[$outline] = $results;
}
}
return $warnings;
}
/**
* Set layout to be used.
*
* @param string $name
* @param bool $force
* @return $this
*/
public function setLayout($name = null, $force = false)
{
$gantry = static::gantry();
// Force new layout to be set.
if ($force) {
unset($gantry['configuration']);
}
// Set default name only if configuration has not been set before.
if ($name === null &&
!isset($gantry['configuration'])) {
$name = 'default';
}
$outline = isset($gantry['configuration']) ?
$gantry['configuration'] : null;
// Set configuration if given.
if ($name && $name != $outline) {
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage("Using Gantry outline {$name}");
$gantry['configuration'] = $name;
unset($gantry['config']);
$gantry['config'] =
ConfigServiceProvider::load($gantry, $name);
}
return $this;
}
/**
* Get current preset.
*
* @param bool $forced If true, return only forced preset or null.
* @return string|null $preset
*/
public function preset($forced = false)
{
$presets = $this->presets()->toArray();
$preset = $this->preset;
if (!$preset && !$forced) {
$preset =
static::gantry()['config']->get('styles.preset',
'-undefined-');
}
if ($preset && !isset($presets[$preset])) {
$preset = null;
}
return $preset;
}
/**
* Set preset to be used.
*
* @param string $name
* @return $this
*/
public function setPreset($name = null)
{
// Set preset if given.
if ($name) {
$this->preset = $name;
}
return $this;
}
/**
* Return CSS compiler used in the theme.
*
* @return CssCompilerInterface
* @throws \RuntimeException
*/
public function compiler()
{
if (!$this->compiler) {
$compilerClass = (string)
$this->details()->get('configuration.css.compiler',
'\Gantry\Component\Stylesheet\ScssCompiler');
if (!class_exists($compilerClass)) {
throw new \RuntimeException('CSS compiler used by the
theme not found');
}
$details = $this->details();
/** @var CssCompilerInterface $compiler */
$this->compiler = new $compilerClass();
$this->compiler
->setTarget($details->get('configuration.css.target'))
->setPaths($details->get('configuration.css.paths'))
->setFiles($details->get('configuration.css.files'))
->setFonts($details->get('configuration.fonts'));
}
$preset = $this->preset(true);
if ($preset) {
$this->compiler->setConfiguration($preset);
} else {
$gantry = static::gantry();
$this->compiler->setConfiguration(isset($gantry['configuration'])
? $gantry['configuration'] : 'default');
}
return $this->compiler->reset();
}
/**
* Returns URL to CSS file.
*
* If file does not exist, it will be created by using CSS compiler.
*
* @param string $name
* @return string
*/
public function css($name)
{
if (!isset($this->cssCache[$name])) {
$compiler = $this->compiler();
if ($compiler->needsCompile($name, [$this,
'getCssVariables'])) {
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer("css-{$name}", "Compiling CSS:
{$name}") && \Gantry\Debugger::addMessage("Compiling CSS:
{$name}");
$compiler->compileFile($name);
GANTRY_DEBUGGER &&
\Gantry\Debugger::stopTimer("css-{$name}");
}
$this->cssCache[$name] = $compiler->getCssUrl($name);
}
return $this->cssCache[$name];
}
public function getCssVariables()
{
if ($this->preset) {
$variables = $this->presets()->flatten($this->preset .
'.styles', '-');
} else {
$gantry = self::gantry();
$variables =
$gantry['config']->flatten('styles', '-');
}
return $variables;
}
/**
* Returns style presets for the theme.
*
* @return Config
*/
public function presets()
{
static $presets;
if (!$presets) {
$gantry = static::gantry();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$filename =
$locator->findResource("gantry-theme://gantry/presets.yaml");
$file = CompiledYamlFile::instance($filename);
$presets = new Config($file->content());
$file->free();
}
return $presets;
}
/**
* Return name of the used layout preset.
*
* @return string
* @throws \RuntimeException
*/
public function type()
{
if (!$this->layoutObject) {
throw new \RuntimeException('Function called too
early');
}
$name = isset($this->layoutObject->preset['name'])
? $this->layoutObject->preset['name'] :
'unknown';
return $name;
}
/**
* Load current layout and its configuration.
*
* @param string $name
* @return Layout
* @throws \LogicException
*/
public function loadLayout($name = null)
{
if (!$name) {
try {
$name = static::gantry()['configuration'];
} catch (\Exception $e) {
throw new \LogicException('Gantry: Outline has not
been defined yet', 500);
}
}
if (!isset($this->layoutObject) ||
$this->layoutObject->name != $name) {
$layout = Layout::instance($name);
if (!$layout->exists()) {
$layout = Layout::instance('default');
}
// TODO: Optimize
$this->layoutObject = $layout->init();
}
return $this->layoutObject;
}
/**
* Check whether layout has content bock.
*
* @return bool
*/
public function hasContent()
{
$layout = $this->loadLayout();
$content = $layout->referencesByType('system',
'content');
return !empty($content);
}
/**
* Load atoms and assets from the page settings.
*
* @since 5.4.9
*/
public function loadAtoms()
{
if (!isset($this->atoms)) {
$this->atoms = true;
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer('atoms', "Preparing
atoms");
$gantry = static::gantry();
/** @var Config $config */
$config = $gantry['config'];
/** @var \Gantry\Framework\Document $document */
$document = $gantry['document'];
$atoms = (array) $config->get('page.head.atoms');
foreach ($atoms as $data) {
$atom = [
'type' => 'atom',
'subtype' => $data['type'],
] + $data;
try {
$block = $this->getContent($atom);
$document->addBlock($block);
} catch (\Exception $e) {
if ($gantry->debug()) {
throw new \RuntimeException("Rendering Atom
'{$atom['subtype']}' failed on error:
{$e->getMessage()}", 500, $e);
}
}
}
$assets = (array) $config->get('page.assets');
if ($assets) {
$atom = [
'id' => 'page-assets',
'title' => 'Page Assets',
'type' => 'atom',
'subtype' => 'assets',
'attributes' => $assets +
['enabled' => 1]
];
try {
$block = $this->getContent($atom);
$document->addBlock($block);
} catch (\Exception $e) {
if ($gantry->debug()) {
throw new \RuntimeException("Rendering CSS/JS
Assets failed on error: {$e->getMessage()}", 500, $e);
}
}
}
GANTRY_DEBUGGER &&
\Gantry\Debugger::stopTimer('atoms');
}
}
/**
* Returns all non-empty segments from the layout.
*
* @return array
*/
public function segments()
{
if (!isset($this->segments)) {
$this->segments = $this->loadLayout()->toArray();
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer('segments', "Preparing
layout");
$this->prepareLayout($this->segments);
GANTRY_DEBUGGER &&
\Gantry\Debugger::stopTimer('segments');
}
return $this->segments;
}
/**
* Prepare layout for rendering. Initializes all CSS/JS in particles.
*/
public function prepare()
{
$this->segments();
}
/**
* Returns details of the theme.
*
* @return ThemeDetails
*/
public function details()
{
if (!$this->details) {
$this->details = new ThemeDetails($this->name);
}
return $this->details;
}
/**
* Returns configuration of the theme.
*
* @return array
*/
public function configuration()
{
return (array) $this->details()['configuration'];
}
/**
* Function to convert block sizes into CSS classes.
*
* @param $text
* @return string
*/
public function toGrid($text)
{
if (!$text) {
return '';
}
$number = round($text, 1);
$number = max(5, $number);
$number = (string) ($number == 100 ? 100 : min(95, $number));
static $sizes = array(
'33.3' => 'size-33-3',
'16.7' => 'size-16-7',
'14.3' => 'size-14-3',
'12.5' => 'size-12-5',
'11.1' => 'size-11-1',
'9.1' => 'size-9-1',
'8.3' => 'size-8-3'
);
return isset($sizes[$number]) ? ' ' . $sizes[$number] :
'size-' . (int) $number;
}
/**
* Magic setter method
*
* @param mixed $offset Asset name value
* @param mixed $value Asset value
*/
public function __set($offset, $value)
{
if ($offset == 'title') {
$offset = 'name';
}
$this->details()->offsetSet('details.' . $offset,
$value);
}
/**
* Magic getter method
*
* @param mixed $offset Asset name value
* @return mixed Asset value
*/
public function __get($offset)
{
if ($offset == 'title') {
$offset = 'name';
}
$value = $this->details()->offsetGet('details.' .
$offset);
if ($offset == 'version' && is_int($value)) {
$value .= '.0';
}
return $value;
}
/**
* Magic method to determine if the attribute is set
*
* @param mixed $offset Asset name value
* @return boolean True if the value is set
*/
public function __isset($offset)
{
if ($offset == 'title') {
$offset = 'name';
}
return $this->details()->offsetExists('details.' .
$offset);
}
/**
* Magic method to unset the attribute
*
* @param mixed $offset The name value to unset
*/
public function __unset($offset)
{
if ($offset == 'title') {
$offset = 'name';
}
$this->details()->offsetUnset('details.' .
$offset);
}
/**
* Prepare layout by loading all the positions and particles.
*
* Action is needed before displaying the layout as it recalculates
block widths based on the visible content.
*
* @param array $items
* @param bool $temporary
* @param bool $sticky
* @internal
*/
protected function prepareLayout(array &$items, $temporary = false,
$sticky = false)
{
foreach ($items as $i => &$item) {
// Non-numeric items are meta-data which should be ignored.
if (((string)(int) $i !== (string) $i) || !is_object($item)) {
continue;
}
if (!empty($item->children)) {
$fixed = true;
foreach ($item->children as $child) {
$fixed &= !empty($child->attributes->fixed);
}
$this->prepareLayout($item->children, $fixed,
$temporary);
}
// TODO: remove hard coded types.
switch ($item->type) {
case 'system':
break;
case 'atom':
case 'particle':
case 'position':
case 'spacer':
GANTRY_DEBUGGER &&
\Gantry\Debugger::startTimer($item->id, "Rendering
{$item->id}");
$item->content = $this->renderContent($item,
['prepare_layout' => true]);
// Note that content can also be null (postpone
rendering).
if ($item->content === '') {
unset($items[$i]);
}
GANTRY_DEBUGGER &&
\Gantry\Debugger::stopTimer($item->id);
break;
default:
if ($sticky) {
$item->attributes->sticky = 1;
break;
}
if (empty($item->children)) {
unset($items[$i]);
break;
}
$dynamicSize = 0;
$fixedSize = 0;
$childrenCount = count($item->children);
foreach ($item->children as $child) {
if (!isset($child->attributes->size)) {
$child->attributes->size = 100 /
count($item->children);
}
if (empty($child->attributes->fixed)) {
$dynamicSize += $child->attributes->size;
} else {
$fixedSize += $child->attributes->size;
}
}
$roundSize = round($dynamicSize, 1);
$equalized = isset($this->equalized[$childrenCount])
? $this->equalized[$childrenCount] : 0;
// force-casting string for testing comparison due to
weird PHP behavior that returns wrong result
if ($roundSize != 100 && (string) $roundSize !=
(string) ($equalized * $childrenCount)) {
$fraction = 0;
$multiplier = (100 - $fixedSize) / ($dynamicSize ?:
1);
foreach ($item->children as $child) {
if (!empty($child->attributes->fixed)) {
continue;
}
// Calculate size for the next item by taking
account the rounding error from the last item.
// This will allow us to approximate cumulating
error and fix it when rounding error grows
// over the rounding treshold.
$size = ($child->attributes->size *
$multiplier) + $fraction;
$newSize = round($size);
$fraction = $size - $newSize;
$child->attributes->size = $newSize;
}
}
}
}
}
/**
* Renders individual content block, like particle or position.
*
* Function is used to pre-render content.
*
* @param object|array $item
* @param array $options
* @return string|null
*/
public function renderContent($item, $options = [])
{
$gantry = static::gantry();
$content = $this->getContent($item, $options);
/** @var Document $document */
$document = $gantry['document'];
$document->addBlock($content);
$html = $content->toString();
return !strstr($html, '@@DEFERRED@@') ? $html : null;
}
/**
* Renders individual content block, like particle or position.
*
* Function is used to pre-render content.
*
* @param object|array $item
* @param array $options
* @return ContentBlock
* @since 5.4.3
*/
public function getContent($item, $options = [])
{
if (is_array($item)) {
$item = (object) $item;
}
$gantry = static::gantry();
/** @var Config $global */
$global = $gantry['global'];
$production = (bool) $global->get('production');
$subtype = $item->subtype;
$enabled =
$gantry['config']->get("particles.{$subtype}.enabled",
1);
if (!$enabled) {
return new HtmlBlock;
}
$attributes = isset($item->attributes) ? $item->attributes :
[];
$particle =
$gantry['config']->getJoined("particles.{$subtype}",
$attributes);
$cached = false;
$cacheKey = [];
// Enable particle caching only in production mode.
if ($production && isset($particle['caching'])) {
$caching = $particle['caching'] + ['type'
=> 'dynamic'];
switch ($caching['type']) {
case 'static':
$cached = true;
break;
case 'config_matches':
if
(isset($particle['caching']['values'])) {
$values = (array)
$particle['caching']['values'];
$compare = array_intersect_key($particle, $values);
$cached = ($values === $compare);
}
break;
case 'menu':
/** @var Menu $menu */
$menu = $gantry['menu'];
$cacheId = $menu->getCacheId();
// FIXME: menu caching needs to handle dynamic modules
inside menu: turning it off for now.
if (false && $cacheId !== null) {
$cached = true;
$cacheKey['menu_cache_key'] = $cacheId;
}
break;
}
}
if ($cached) {
$cacheKey['language'] =
$gantry['page']->language;
$cacheKey['attributes'] = $particle;
$cacheKey += (array) $item;
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$key = md5(json_encode($cacheKey));
$filename =
$locator->findResource("gantry-cache://theme/html/{$key}.php",
true, true);
$file = PhpFile::instance($filename);
if ($file->exists()) {
try {
return ContentBlock::fromArray((array)
$file->content());
} catch (\Exception $e) {
// Invalid cache, continue to rendering.
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage(sprintf('Failed to load %s %s
cache', $item->type, $item->id), 'debug');
}
}
}
// Create new document context for assets.
$context = $this->getContext(['segment' => $item,
'enabled' => 1, 'particle' => $particle] +
$options);
/** @var Document $document */
$document = $gantry['document'];
$document->push();
$html =
trim($this->render("@nucleus/content/{$item->type}.html.twig",
$context));
$content = $document->pop()->setContent($html);
if (isset($file)) {
// Save HTML and assets into the cache.
GANTRY_DEBUGGER &&
\Gantry\Debugger::addMessage(sprintf('Caching %s %s',
$item->type, $item->id), 'debug');
$file->save($content->toArray());
}
return $content;
}
}
PKX[�[$�E��
�
Translator/Translator.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Translator;
use Gantry\Component\File\CompiledYamlFile;
use Gantry\Framework\Gantry;
use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
class Translator implements TranslatorInterface
{
protected $default = 'en';
protected $active = 'en';
protected $sections = [];
protected $translations = [];
protected $untranslated = [];
public function translate($string)
{
if (preg_match('|^GANTRY5(_[A-Z0-9]+){2,}$|', $string)) {
list(, $section, $code) = explode('_', $string, 3);
$string = ($this->find($this->active, $section, $string)
?: $this->find($this->default, $section, $string)) ?: $string;
}
if (func_num_args() === 1) {
return $string;
}
$args = func_get_args();
$args[0] = $string;
return call_user_func_array('sprintf', $args);
}
/**
* Set new active language if given and return previous active
language.
*
* @param string $language Language code. If not given, current
language is kept.
* @return string Previously active language.
*/
public function active($language = null)
{
$previous = $this->active;
if ($language) {
$this->active = $language;
}
return $previous;
}
public function untranslated()
{
return $this->untranslated;
}
protected function find($language, $section, $string)
{
if (!isset($this->sections[$language][$section])) {
$translations = $this->load($language, $section);
if (isset($this->translations[$language])) {
$this->translations[$language] += $translations;
} else {
$this->translations[$language] = $translations;
}
$this->sections[$language][$section] =
!empty($translations);
}
if (!isset($this->translations[$language][$string])) {
$this->untranslated[$language][$section][$string] = null;
return null;
}
return $this->translations[$language][$string];
}
protected function load($language, $section)
{
$gantry = Gantry::instance();
/** @var UniformResourceLocator $locator */
$locator = $gantry['locator'];
$section = strtolower($section);
if ($section === 'engine') {
// TODO: add support for other engines than nucleus.
$section = 'nucleus';
}
$filename = 'gantry-admin://translations/' . $language .
'/' . $section . '.yaml';
$file = CompiledYamlFile::instance($filename);
if (!$file->exists() && ($pos = strpos($language,
'-')) > 0) {
$filename = 'gantry-admin://translations/' .
substr($language, 0, $pos) . '/' . $section . '.yaml';
$file = CompiledYamlFile::instance($filename);
}
$cachePath =
$locator->findResource('gantry-cache://translations', true,
true);
$translations = (array)
$file->setCachePath($cachePath)->content();
$file->free();
return $translations;
}
}
PKX[�[�f��GG"Translator/TranslatorInterface.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Translator;
interface TranslatorInterface
{
/**
* @param string $string
* @return string
*/
public function translate($string);
/**
* Set new active language if given and return previous active
language.
*
* @param string $language Language code. If not given, current
language is kept.
* @return string Previously active language.
*/
public function active($language = null);
}
PKX[�[�Ϸ�Twig/Node/TwigNodeAssets.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeAssets extends \Twig_Node implements
\Twig_NodeCaptureInterface
{
protected $tagName = 'assets';
public function __construct(\Twig_Node $body = null,
\Twig_Node_Expression $location = null, \Twig_Node_Expression $variables =
null, $lineno = 0, $tag = null)
{
parent::__construct(['body' => $body,
'location' => $location, 'variables' =>
$variables], [], $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this)
->write("\$assetFunction =
\$this->env->getFunction('parse_assets')->getCallable();\n")
->write('$assetVariables = ')
->subcompile($this->getNode('variables'))
->raw(";\n")
->write("if (\$assetVariables &&
!is_array(\$assetVariables)) {\n")
->indent()
->write("throw new UnexpectedValueException('{%
{$this->tagName} with x %}: x is not an array');\n")
->outdent()
->write("}\n")
->write('$location = ')
->subcompile($this->getNode('location'))
->raw(";\n")
->write("if (\$location &&
!is_string(\$location)) {\n")
->indent()
->write("throw new UnexpectedValueException('{%
{$this->tagName} in x %}: x is not a string');\n")
->outdent()
->write("}\n")
->write("\$priority =
isset(\$assetVariables['priority']) ?
\$assetVariables['priority'] : 0;\n")
->write("ob_start();\n")
->subcompile($this->getNode('body'))
->write("\$content = ob_get_clean();\n")
->write("\$assetFunction(\$content, \$location,
\$priority);\n");
}
}
PKX[�[���y��Twig/Node/TwigNodeMarkdown.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeMarkdown extends \Twig_Node implements
\Twig_NodeOutputInterface
{
public function __construct(\Twig_Node $body, $lineno, $tag =
'markdown')
{
parent::__construct(['body' => $body], [], $lineno,
$tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('ob_start();' . PHP_EOL)
->subcompile($this->getNode('body'))
->write('$content = ob_get_clean();' . PHP_EOL)
->write('preg_match("/^\s*/", $content,
$matches);' . PHP_EOL)
->write('$lines = explode("\n",
$content);' . PHP_EOL)
->write('$content = preg_replace(\'/^\' .
$matches[0]. \'/\', "", $lines);' . PHP_EOL)
->write('$content = join("\n",
$content);' . PHP_EOL)
->write('echo
$this->env->getExtension(\'Gantry\Component\Twig\TwigExtension\')->markdownFunction($content);'
. PHP_EOL);
}
}
PKY[�[7n^c��Twig/Node/TwigNodePageblock.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodePageblock extends \Twig_Node implements
\Twig_NodeCaptureInterface
{
protected $tagName = 'pageblock';
public function __construct(\Twig_Node $body = null,
\Twig_Node_Expression $location = null, \Twig_Node_Expression $variables =
null, $lineno = 0, $tag = null)
{
parent::__construct(['body' => $body,
'location' => $location, 'variables' =>
$variables], [], $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this)
->write('$pageblockVariables = ')
->subcompile($this->getNode('variables'))
->raw(";\n")
->write("if (\$pageblockVariables &&
!is_array(\$pageblockVariables)) {\n")
->indent()
->write("throw new UnexpectedValueException('{%
{$this->tagName} with x %}: x is not an array');\n")
->outdent()
->write("}\n")
->write('$location = ')
->subcompile($this->getNode('location'))
->raw(";\n")
->write("if (\$location &&
!is_string(\$location)) {\n")
->indent()
->write("throw new UnexpectedValueException('{%
{$this->tagName} in x %}: x is not a string');\n")
->outdent()
->write("}\n")
->write("\$priority =
isset(\$pageblockVariables['priority']) ?
\$pageblockVariables['priority'] : 0;\n")
->write("ob_start();\n")
->subcompile($this->getNode('body'))
->write("\$content = ob_get_clean();\n")
->write("Gantry\Framework\Gantry::instance()['document']->addHtml(\$content,
\$priority, \$location);\n");
}
}
PKY[�[�ܽ���Twig/Node/TwigNodeScripts.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeScripts extends TwigNodeAssets
{
protected $tagName = 'scripts';
}
PKY[�[JtE5��Twig/Node/TwigNodeStyles.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeStyles extends TwigNodeScripts
{
protected $tagName = 'styles';
}
PKY[�[�$�� Twig/Node/TwigNodeSwitch.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeSwitch extends \Twig_Node
{
public function __construct(\Twig_Node $value, \Twig_Node $cases,
\Twig_Node $default = null, $lineno = 0, $tag = null)
{
parent::__construct(array('value' => $value,
'cases' => $cases, 'default' => $default),
array(), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler
->addDebugInfo($this)
->write('switch (')
->subcompile($this->getNode('value'))
->raw(") {\n")
->indent();
foreach ($this->getNode('cases') as $case) {
if (!$case->hasNode('body')) {
continue;
}
foreach ($case->getNode('values') as $value) {
$compiler
->write('case ')
->subcompile($value)
->raw(":\n");
}
$compiler
->write("{\n")
->indent()
->subcompile($case->getNode('body'))
->write("break;\n")
->outdent()
->write("}\n");
}
if ($this->hasNode('default') &&
$this->getNode('default') !== null) {
$compiler
->write("default:\n")
->write("{\n")
->indent()
->subcompile($this->getNode('default'))
->outdent()
->write("}\n");
}
$compiler
->outdent()
->write("}\n");
}
}
PKY[�[�K��Twig/Node/TwigNodeThrow.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeThrow extends \Twig_Node
{
public function __construct(
$code,
\Twig_Node $message,
$lineno = 0,
$tag = null
)
{
parent::__construct(['message' => $message],
['code' => $code], $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler $compiler A Twig_Compiler instance
* @throws \LogicException
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this);
$compiler
->write('throw new \RuntimeException(')
->subcompile($this->getNode('message'))
->write(', ')
->write($this->getAttribute('code') ?: 500)
->write(");\n");
}
}
PKY[�[Bh���Twig/Node/TwigNodeTryCatch.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\Node;
class TwigNodeTryCatch extends \Twig_Node
{
public function __construct(\Twig_Node $try, \Twig_Node $catch = null,
$lineno = 0, $tag = null)
{
parent::__construct(array('try' => $try,
'catch' => $catch), array(), $lineno, $tag);
}
/**
* Compiles the node to PHP.
*
* @param \Twig_Compiler $compiler A Twig_Compiler instance
*/
public function compile(\Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this);
$compiler
->write('try {')
;
$compiler
->indent()
->subcompile($this->getNode('try'))
;
if ($this->hasNode('catch') && null !==
$this->getNode('catch')) {
$compiler
->outdent()
->write('} catch (\Exception $e) {' .
"\n")
->indent()
->write('if
($context[\'gantry\']->debug()) throw $e;' .
"\n")
->write('GANTRY_DEBUGGER &&
method_exists(\'Gantry\\Debugger\', \'addException\')
&& \Gantry\Debugger::addException($e);' . "\n")
->write('$context[\'e\'] = $e;' .
"\n")
->subcompile($this->getNode('catch'))
;
}
$compiler
->outdent()
->write("}\n");
}
}
PKY[�[��5��
�
&Twig/TokenParser/TokenParserAssets.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeScripts;
/**
* Adds javascript / style assets to head/footer/custom location.
*
* {% assets in 'head' with { priority: 2 } %}
* <script type="text/javascript" src="{{
url('gantry-theme://js/my.js') }}"></script>
* <link rel="stylesheet" href="{{
url('gantry-assets://css/font-awesome.min.css') }}"
type="text/css"/>
* {% endassets -%}
*/
class TokenParserAssets extends \Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param \Twig_Token $token A Twig_Token instance
*
* @return \Twig_Node A Twig_Node instance
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
list($location, $variables) = $this->parseArguments($token);
$content = $this->parser->subparse([$this,
'decideBlockEnd'], true);
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeScripts($content, $location, $variables,
$lineno, $this->getTag());
}
/**
* @param \Twig_Token $token
* @return array
*/
protected function parseArguments(\Twig_Token $token)
{
$stream = $this->parser->getStream();
$location = null;
if ($stream->nextIf(\Twig_Token::OPERATOR_TYPE, 'in'))
{
$location =
$this->parser->getExpressionParser()->parseExpression();
} else {
$lineno = $token->getLine();
$location = new
\Twig_Node_Expression_Constant('head', $lineno);
}
if ($stream->nextIf(\Twig_Token::NAME_TYPE, 'with')) {
$variables =
$this->parser->getExpressionParser()->parseExpression();
} else {
$lineno = $token->getLine();
$variables = new \Twig_Node_Expression_Array([], $lineno);
$variables->setAttribute('priority', 0);
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return [$location, $variables];
}
public function decideBlockEnd(\Twig_Token $token)
{
return $token->test('endassets');
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'assets';
}
}
PKY[�[B�$��(Twig/TokenParser/TokenParserMarkdown.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeMarkdown;
/**
* Adds ability to inline markdown between tags.
*
* {% markdown %}
* This is **bold** and this _underlined_
*
* 1. This is a bullet list
* 2. This is another item in that same list
* {% endmarkdown %}
*/
class TokenParserMarkdown extends \Twig_TokenParser
{
/**
* {@inheritdoc}
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this,
'decideMarkdownEnd'), true);
$this->parser->getStream()->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeMarkdown($body, $lineno, $this->getTag());
}
/**
* Decide if current token marks end of Markdown block.
*
* @param \Twig_Token $token
* @return bool
*/
public function decideMarkdownEnd(\Twig_Token $token)
{
return $token->test('endmarkdown');
}
/**
* {@inheritdoc}
*/
public function getTag()
{
return 'markdown';
}
}
PKY[�[I��\ \ )Twig/TokenParser/TokenParserPageblock.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodePageblock;
/**
* Adds javascript / style assets to head/footer/custom location.
*
* {% pageblock in 'bottom' with { priority: 0 } %}
* <div>Bottom HTML</div>
* {% endpageblock -%}
*/
class TokenParserPageblock extends \Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param \Twig_Token $token A Twig_Token instance
*
* @return \Twig_Node A Twig_Node instance
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
list($location, $variables) = $this->parseArguments($token);
$content = $this->parser->subparse([$this,
'decideBlockEnd'], true);
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodePageblock($content, $location, $variables,
$lineno, $this->getTag());
}
/**
* @param \Twig_Token $token
* @return array
*/
protected function parseArguments(\Twig_Token $token)
{
$stream = $this->parser->getStream();
$lineno = $token->getLine();
$location = new
\Twig_Node_Expression_Constant($stream->expect(\Twig_Token::NAME_TYPE)->getValue(),
$lineno);
if ($stream->nextIf(\Twig_Token::NAME_TYPE, 'with')) {
$variables =
$this->parser->getExpressionParser()->parseExpression();
} else {
$lineno = $token->getLine();
$variables = new \Twig_Node_Expression_Array([], $lineno);
$variables->setAttribute('priority', 0);
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return [$location, $variables];
}
public function decideBlockEnd(\Twig_Token $token)
{
return $token->test('endpageblock');
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'pageblock';
}
}
PKY[�[
FX���'Twig/TokenParser/TokenParserScripts.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
/**
* Adds scripts to head/footer/custom location.
*
* {% scripts in 'head' with { priority: 2 } %}
* <script type="text/javascript" src="{{
url('gantry-theme://js/my.js') }}"></script>
* {% endscripts -%}
*/
class TokenParserScripts extends TokenParserAssets
{
public function decideBlockEnd(\Twig_Token $token)
{
return $token->test('endscripts');
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'scripts';
}
}
PKY[�[�++B��&Twig/TokenParser/TokenParserStyles.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
/**
* Adds stylesheets to document.
*
* {% styles with { priority: 2 } %}
* <link rel="stylesheet" href="{{
url('gantry-assets://css/font-awesome.min.css') }}"
type="text/css"/>
* {% endstyles -%}
*/
class TokenParserStyles extends TokenParserAssets
{
public function decideBlockEnd(\Twig_Token $token)
{
return $token->test('endstyles');
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'styles';
}
}
PKY[�[���#��&Twig/TokenParser/TokenParserSwitch.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeSwitch;
/**
* Adds ability use elegant switch instead of ungainly if statements
*
* {% switch type %}
* {% case 'foo' %}
* {{ my_data.foo }}
* {% case 'bar' %}
* {{ my_data.bar }}
* {% default %}
* {{ my_data.default }}
* {% endswitch %}
*/
class TokenParserSwitch extends \Twig_TokenParser
{
/**
* {@inheritdoc}
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$name =
$this->parser->getExpressionParser()->parseExpression();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
// There can be some whitespace between the {% switch %} and first
{% case %} tag.
while ($stream->getCurrent()->getType() ===
\Twig_Token::TEXT_TYPE &&
trim($stream->getCurrent()->getValue()) === '') {
$stream->next();
}
$stream->expect(\Twig_Token::BLOCK_START_TYPE);
$expressionParser = $this->parser->getExpressionParser();
$default = null;
$cases = [];
$end = false;
while (!$end) {
$next = $stream->next();
switch ($next->getValue()) {
case 'case':
$values = [];
while (true) {
$values[] =
$expressionParser->parsePrimaryExpression();
// Multiple allowed values?
if ($stream->test(\Twig_Token::OPERATOR_TYPE,
'or')) {
$stream->next();
} else {
break;
}
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$body = $this->parser->subparse(array($this,
'decideIfFork'));
$cases[] = new \Twig_Node([
'values' => new \Twig_Node($values),
'body' => $body
]);
break;
case 'default':
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$default = $this->parser->subparse(array($this,
'decideIfEnd'));
break;
case 'endswitch':
$end = true;
break;
default:
throw new \Twig_Error_Syntax(sprintf('Unexpected
end of template. Twig was looking for the following tags "case",
"default", or "endswitch" to close the
"switch" block started at line %d)', $lineno), -1);
}
}
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeSwitch($name, new \Twig_Node($cases), $default,
$lineno, $this->getTag());
}
/**
* Decide if current token marks switch logic.
*
* @param \Twig_Token $token
* @return bool
*/
public function decideIfFork(\Twig_Token $token)
{
return $token->test(array('case', 'default',
'endswitch'));
}
/**
* Decide if current token marks end of swtich block.
*
* @param \Twig_Token $token
* @return bool
*/
public function decideIfEnd(\Twig_Token $token)
{
return $token->test(array('endswitch'));
}
/**
* {@inheritdoc}
*/
public function getTag()
{
return 'switch';
}
}
PKY[�[�ʱtt%Twig/TokenParser/TokenParserThrow.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeThrow;
/**
* Handles try/catch in template file.
*
* <pre>
* {% throw 404 'Not Found' %}
* </pre>
*/
class TokenParserThrow extends \Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param \Twig_Token $token A Twig_Token instance
*
* @return \Twig_Node A Twig_Node instance
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$code =
$stream->expect(\Twig_Token::NUMBER_TYPE)->getValue();
$message =
$this->parser->getExpressionParser()->parseExpression();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeThrow($code, $message, $lineno,
$this->getTag());
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'throw';
}
}
PKY[�[�TLL(Twig/TokenParser/TokenParserTryCatch.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig\TokenParser;
use Gantry\Component\Twig\Node\TwigNodeTryCatch;
/**
* Handles try/catch in template file.
*
* <pre>
* {% try %}
* <li>{{ user.get('name') }}</li>
* {% catch %}
* {{ e.message }}
* {% endcatch %}
* </pre>
*/
class TokenParserTryCatch extends \Twig_TokenParser
{
/**
* Parses a token and returns a node.
*
* @param \Twig_Token $token A Twig_Token instance
*
* @return \Twig_Node A Twig_Node instance
*/
public function parse(\Twig_Token $token)
{
$lineno = $token->getLine();
$stream = $this->parser->getStream();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$try = $this->parser->subparse([$this,
'decideCatch']);
$stream->next();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
$catch = $this->parser->subparse([$this,
'decideEnd']);
$stream->next();
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
return new TwigNodeTryCatch($try, $catch, $lineno,
$this->getTag());
}
public function decideCatch(\Twig_Token $token)
{
return $token->test(array('catch'));
}
public function decideEnd(\Twig_Token $token)
{
return $token->test(array('endtry')) ||
$token->test(array('endcatch'));
}
/**
* Gets the tag name associated with this token parser.
*
* @return string The tag name
*/
public function getTag()
{
return 'try';
}
}
PKY[�[�
�Twig/TwigCacheFilesystem.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig;
/**
* Class TwigCacheFilesystem
* @package Gantry\Component\Twig
*
* Replaces \Twig_Cache_Filesystem, needed for being able to change PHP
versions on fly.
*/
class TwigCacheFilesystem implements \Twig_CacheInterface
{
const FORCE_BYTECODE_INVALIDATION = 1;
private $directory;
private $options;
/**
* @param $directory string The root cache directory
* @param $options int A set of options
*/
public function __construct($directory, $options = 0)
{
$this->directory = rtrim($directory,
'\/').'/';
$this->options = $options;
}
/**
* {@inheritdoc}
*/
public function generateKey($name, $className)
{
$hash = hash('sha256', $className . '-' .
PHP_VERSION);
return
$this->directory.$hash[0].$hash[1].'/'.$hash.'.php';
}
/**
* {@inheritdoc}
*/
public function load($key)
{
@include_once $key;
}
/**
* {@inheritdoc}
*/
public function write($key, $content)
{
$dir = dirname($key);
if (!is_dir($dir)) {
if (false === @mkdir($dir, 0777, true) &&
!is_dir($dir)) {
throw new \RuntimeException(sprintf('Unable to create
the cache directory (%s).', $dir));
}
} elseif (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Unable to write in
the cache directory (%s).', $dir));
}
$tmpFile = tempnam($dir, basename($key));
if (false !== @file_put_contents($tmpFile, $content) &&
@rename($tmpFile, $key)) {
@chmod($key, 0666 & ~umask());
if (self::FORCE_BYTECODE_INVALIDATION == ($this->options
& self::FORCE_BYTECODE_INVALIDATION)) {
// Compile cached file into bytecode cache
if (function_exists('opcache_invalidate')) {
// Silence error in case if `opcache.restrict_api`
directive is set.
@opcache_invalidate($key, true);
} elseif (function_exists('apc_compile_file')) {
@apc_compile_file($key);
}
}
return;
}
throw new \RuntimeException(sprintf('Failed to write cache
file "%s".', $key));
}
/**
* {@inheritdoc}
*/
public function getTimestamp($key)
{
if (!file_exists($key)) {
return 0;
}
return (int) @filemtime($key);
}
}
PKY[�[K�
k�Q�QTwig/TwigExtension.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Twig;
use Gantry\Component\Content\Document\HtmlDocument;
use Gantry\Component\Gantry\GantryTrait;
use Gantry\Component\Translator\TranslatorInterface;
use Gantry\Component\Twig\TokenParser\TokenParserPageblock;
use Gantry\Component\Twig\TokenParser\TokenParserAssets;
use Gantry\Component\Twig\TokenParser\TokenParserScripts;
use Gantry\Component\Twig\TokenParser\TokenParserStyles;
use Gantry\Component\Twig\TokenParser\TokenParserTryCatch;
use Gantry\Component\Twig\TokenParser\TokenParserMarkdown;
use Gantry\Component\Twig\TokenParser\TokenParserSwitch;
use Gantry\Component\Twig\TokenParser\TokenParserThrow;
use Gantry\Framework\Gantry;
use Gantry\Framework\Markdown\Parsedown;
use Gantry\Framework\Markdown\ParsedownExtra;
use Gantry\Framework\Request;
use RocketTheme\Toolbox\ArrayTraits\NestedArrayAccess;
class TwigExtension extends \Twig_Extension implements
\Twig_Extension_GlobalsInterface
{
use GantryTrait;
/**
* Register some standard globals
*
* @return array
*/
public function getGlobals()
{
return [
'gantry' => static::gantry(),
];
}
/**
* Return a list of all filters.
*
* @return array
*/
public function getFilters()
{
$filters = [
new \Twig_SimpleFilter('html', [$this,
'htmlFilter']),
new \Twig_SimpleFilter('url', [$this,
'urlFunc']),
new \Twig_SimpleFilter('trans_key', [$this,
'transKeyFilter']),
new \Twig_SimpleFilter('trans', [$this,
'transFilter']),
new \Twig_SimpleFilter('repeat', [$this,
'repeatFilter']),
new \Twig_SimpleFilter('values', [$this,
'valuesFilter']),
new \Twig_SimpleFilter('base64',
'base64_encode'),
new \Twig_SimpleFilter('imagesize', [$this,
'imageSize']),
new \Twig_SimpleFilter('truncate_text', [$this,
'truncateText']),
new \Twig_SimpleFilter('attribute_array', [$this,
'attributeArrayFilter'], ['is_safe' =>
['html']]),
];
if (1 || GANTRY5_PLATFORM !== 'grav') {
$filters = array_merge($filters, [
new \Twig_SimpleFilter('fieldName', [$this,
'fieldNameFilter']),
new \Twig_SimpleFilter('json_decode', [$this,
'jsonDecodeFilter']),
new \Twig_SimpleFilter('truncate_html', [$this,
'truncateHtml']),
new \Twig_SimpleFilter('markdown', [$this,
'markdownFunction'], ['is_safe' =>
['html']]),
new \Twig_SimpleFilter('nicetime', [$this,
'nicetimeFilter']),
// Casting values
new \Twig_SimpleFilter('string', [$this,
'stringFilter']),
new \Twig_SimpleFilter('int', [$this,
'intFilter'], ['is_safe' => ['all']]),
new \Twig_SimpleFilter('bool', [$this,
'boolFilter']),
new \Twig_SimpleFilter('float', [$this,
'floatFilter'], ['is_safe' => ['all']]),
new \Twig_SimpleFilter('array', [$this,
'arrayFilter']),
]);
}
return $filters;
}
/**
* Return a list of all functions.
*
* @return array
*/
public function getFunctions()
{
$functions = [
new \Twig_SimpleFunction('nested', [$this,
'nestedFunc']),
new \Twig_SimpleFunction('parse_assets', [$this,
'parseAssetsFunc']),
new \Twig_SimpleFunction('colorContrast', [$this,
'colorContrastFunc']),
new \Twig_SimpleFunction('get_cookie', [$this,
'getCookie']),
new \Twig_SimpleFunction('preg_match', [$this,
'pregMatch']),
new \Twig_SimpleFunction('imagesize', [$this,
'imageSize']),
new \Twig_SimpleFunction('is_selected', [$this,
'is_selectedFunc']),
new \Twig_SimpleFunction('url', [$this,
'urlFunc']),
];
if (1 || GANTRY5_PLATFORM !== 'grav') {
$functions = array_merge($functions, [
new \Twig_SimpleFunction('array', [$this,
'arrayFilter']),
new \Twig_SimpleFunction('json_decode', [$this,
'jsonDecodeFilter']),
]);
}
return $functions;
}
/**
* @return array
*/
public function getTokenParsers()
{
return [
new TokenParserPageblock(),
new TokenParserAssets(),
new TokenParserScripts(),
new TokenParserStyles(),
new TokenParserThrow(),
new TokenParserTryCatch(),
new TokenParserMarkdown(),
new TokenParserSwitch()
];
}
/**
* Filters field name by changing dot notation into array notation.
*
* @param string $str
* @return string
*/
public function fieldNameFilter($str)
{
$path = explode('.', $str);
return array_shift($path) . ($path ? '[' .
implode('][', $path) . ']' : '');
}
/**
* Translate by using key, default on original string.
*
* @param $str
* @return string
*/
public function transKeyFilter($str)
{
$params = \func_get_args();
array_shift($params);
$key = preg_replace('|[^A-Z0-9]+|', '_',
strtoupper(implode('_', $params)));
$translation = $this->transFilter($key);
return $translation === $key ? $str : $translation;
}
/**
* Translate string.
*
* @param string $str
* @return string
*/
public function transFilter($str)
{
/** @var TranslatorInterface $translator */
static $translator;
$params = \func_get_args();
if (!$translator) {
$translator = self::gantry()['translator'];
}
return \call_user_func_array([$translator, 'translate'],
$params);
}
/**
* Repeat string x times.
*
* @param string $str
* @param int $count
* @return string
*/
public function repeatFilter($str, $count)
{
return str_repeat($str, max(0, (int) $count));
}
/**
* Decodes string from JSON.
*
* @param string $str
* @param bool $assoc
* @param int $depth
* @param int $options
* @return array
*/
public function jsonDecodeFilter($str, $assoc = false, $depth = 512,
$options = 0)
{
return json_decode(html_entity_decode($str), $assoc, $depth,
$options);
}
public function imageSize($src, $attrib = true, $remote = false)
{
// TODO: need to better handle absolute and relative paths
//$url =
Gantry::instance()['document']->url(trim((string) $src),
false, false);
$width = $height = null;
$sizes = ['width' => $width, 'height' =>
$height];
$attr = '';
if (@is_file($src) || $remote) {
try {
list($width, $height,, $attr) = @getimagesize($src);
} catch (\Exception $e) {}
$sizes['width'] = $width;
$sizes['height'] = $height;
}
return $attrib ? $attr : $sizes;
}
/**
* Reindexes values in array.
*
* @param array $array
* @return array
*/
public function valuesFilter(array $array)
{
return array_values($array);
}
/**
* Casts input to string.
*
* @param mixed $input
* @return string
*/
public function stringFilter($input)
{
return (string) $input;
}
/**
* Casts input to int.
*
* @param mixed $input
* @return int
*/
public function intFilter($input)
{
return (int) $input;
}
/**
* Casts input to bool.
*
* @param mixed $input
* @return bool
*/
public function boolFilter($input)
{
return (bool) $input;
}
/**
* Casts input to float.
*
* @param mixed $input
* @return float
*/
public function floatFilter($input)
{
return (float) $input;
}
/**
* Casts input to array.
*
* @param mixed $input
* @return array
*/
public function arrayFilter($input)
{
return (array) $input;
}
/**
* Takes array of attribute keys and values and converts it to properly
escaped HTML attributes.
*
* @example ['data-id' => 'id',
'data-key' => 'key'] => '
data-id="id" data-key="key"'
* @example [['data-id' => 'id'],
['data-key' => 'key']] => '
data-id="id" data-key="key"'
*
* @param string|string[] $input
* @return string
*/
public function attributeArrayFilter($input)
{
if (\is_string($input)) {
return $input;
}
$array = [];
foreach ((array) $input as $key => $value) {
if (\is_array($value)) {
foreach ((array) $value as $key2 => $value2) {
$array[] = HtmlDocument::escape($key2) .
'="' . HtmlDocument::escape($value2, 'html_attr')
. '"';
}
} elseif ($key) {
$array[] = HtmlDocument::escape($key) . '="'
. HtmlDocument::escape($value, 'html_attr') . '"';
}
}
return $array ? ' ' . implode(' ', $array) :
'';
}
public function is_selectedFunc($a, $b)
{
$b = (array) $b;
array_walk(
$b,
function (&$item) {
if (\is_bool($item)) {
$item = (int) $item;
}
$item = (string) $item;
}
);
return \in_array((string) $a, $b, true);
}
/**
* Truncate text by number of characters but can cut off words. Removes
html tags.
*
* @param string $string
* @param int $limit Max number of characters.
*
* @return string
*/
public function truncateText($string, $limit = 150)
{
$platform = Gantry::instance()['platform'];
return $platform->truncate($string, (int) $limit, false);
}
/**
* Truncate text by number of characters but can cut off words.
*
* @param string $string
* @param int $limit Max number of characters.
*
* @return string
*/
public function truncateHtml($string, $limit = 150)
{
$platform = Gantry::instance()['platform'];
return $platform->truncate($string, (int) $limit, true);
}
/**
* @param string $string
* @param bool $block Block or Line processing
* @param array $settings
* @return mixed|string
*/
public function markdownFunction($string, $block = true, array
$settings = null)
{
// Initialize the preferred variant of Parsedown
if (!empty($settings['extra'])) {
$parsedown = new ParsedownExtra($settings);
} else {
$parsedown = new Parsedown($settings);
}
if ($block) {
$string = $parsedown->text($string);
} else {
$string = $parsedown->line($string);
}
return $string;
}
/**
* Get value by using dot notation for nested arrays/objects.
*
* @example {{ nested(array,
'this.is.my.nested.variable')|json_encode }}
*
* @param array $items Array of items.
* @param string $name Dot separated path to the requested
value.
* @param mixed $default Default value (or null).
* @param string $separator Separator, defaults to '.'
* @return mixed Value.
*/
public function nestedFunc($items, $name, $default = null, $separator =
'.')
{
if ($items instanceof NestedArrayAccess) {
return $items->get($name, $default, $separator);
}
$path = explode($separator, $name);
$current = $items;
foreach ($path as $field) {
if (\is_object($current) &&
isset($current->{$field})) {
$current = $current->{$field};
} elseif (\is_array($current) &&
isset($current[$field])) {
$current = $current[$field];
} else {
return $default;
}
}
return $current;
}
/**
* Return URL to the resource.
*
* @example {{
url('theme://images/logo.png')|default('http://www.placehold.it/150x100/f4f4f4')
}}
*
* @param string $input Resource to be located.
* @param bool $domain True to include domain name.
* @param int $timestamp_age Append timestamp to files that are less
than x seconds old. Defaults to a week.
* Use value <= 0 to disable the
feature.
* @return string|null Returns url to the resource or null if
resource was not found.
*/
public function urlFunc($input, $domain = false, $timestamp_age = null)
{
$gantry = Gantry::instance();
return $gantry['document']->url(trim((string) $input),
$domain, $timestamp_age);
}
/**
* Filter stream URLs from HTML input.
*
* @param string $str HTML input to be filtered.
* @param bool $domain True to include domain name.
* @param int $timestamp_age Append timestamp to files that are less
than x seconds old. Defaults to a week.
* Use value <= 0 to disable the
feature.
* @return string Returns modified HTML.
*/
public function htmlFilter($str, $domain = false, $timestamp_age =
null)
{
$gantry = Gantry::instance();
return $gantry['document']->urlFilter($str, $domain,
$timestamp_age);
}
/**
* @param \libXMLError $error
* @param string $input
* @throws \RuntimeException
*/
protected function dealXmlError(\libXMLError $error, $input)
{
switch ($error->level) {
case LIBXML_ERR_WARNING:
$level = 1;
$message = "DOM Warning {$error->code}: ";
break;
case LIBXML_ERR_ERROR:
$level = 2;
$message = "DOM Error {$error->code}: ";
break;
case LIBXML_ERR_FATAL:
$level = 3;
$message = "Fatal DOM Error {$error->code}: ";
break;
default:
$level = 3;
$message = "Unknown DOM Error {$error->code}:
";
}
$message .= "{$error->message} while
parsing:\n{$input}\n";
if ($level <= 2 && !Gantry::instance()->debug()) {
return;
}
throw new \RuntimeException($message, 500);
}
/**
* Move supported document head elements into platform document object,
return all
* unsupported tags in a string.
*
* @param string $input
* @param string $location
* @param int $priority
* @return string
*/
public function parseAssetsFunc($input, $location = 'head',
$priority = 0)
{
if ($location === 'head') {
$scope = 'head';
$html = "<!doctype
html>\n<html><head>{$input}</head><body></body></html>";
} else {
$scope = 'body';
$html = "<!doctype
html>\n<html><head></head><body>{$input}</body></html>";
}
libxml_clear_errors();
$internal = libxml_use_internal_errors(true);
$doc = new \DOMDocument();
$doc->loadHTML($html);
foreach (libxml_get_errors() as $error) {
$this->dealXmlError($error, $html);
}
libxml_clear_errors();
libxml_use_internal_errors($internal);
$raw = [];
/** @var \DomElement $element */
foreach
($doc->getElementsByTagName($scope)->item(0)->childNodes as
$element) {
if (empty($element->tagName)) {
continue;
}
$result = ['tag' => $element->tagName,
'content' => $element->textContent];
foreach ($element->attributes as $attribute) {
$result[$attribute->name] = $attribute->value;
}
$success =
Gantry::instance()['document']->addHeaderTag($result,
$location, (int) $priority);
if (!$success) {
$raw[] = $doc->saveHTML($element);
}
}
return implode("\n", $raw);
}
public function colorContrastFunc($value)
{
$value = str_replace(' ', '', $value);
$rgb = new \stdClass;
$opacity = 1;
if (0 !== strpos($value, 'rgb')) {
$value = str_replace('#', '', $value);
if (\strlen($value) === 3) {
$h0 = str_repeat(substr($value, 0, 1), 2);
$h1 = str_repeat(substr($value, 1, 1), 2);
$h2 = str_repeat(substr($value, 2, 1), 2);
$value = $h0 . $h1 . $h2;
}
$rgb->r = hexdec(substr($value, 0, 2));
$rgb->g = hexdec(substr($value, 2, 2));
$rgb->b = hexdec(substr($value, 4, 2));
} else {
preg_match("/(\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(1\\.|0?\\.?[0-9]?+))?/uim",
$value, $matches);
$rgb->r = $matches[1];
$rgb->g = $matches[2];
$rgb->b = $matches[3];
$opacity = isset($matches[4]) ? $matches[4] : 1;
$opacity = substr($opacity, 0, 1) === '.' ?
'0' . $opacity : $opacity;
}
$yiq = ((($rgb->r * 299) + ($rgb->g * 587) + ($rgb->b *
114)) / 1000) >= 128;
$contrast = $yiq || (!$opacity || (float) $opacity < 0.35);
return $contrast;
}
/**
* Displays a facebook style 'time ago' formatted date/time.
*
* @param string|int $date
* @param bool $long_strings
*
* @return string
*/
public function nicetimeFilter($date, $long_strings = true)
{
static $lengths = [60, 60, 24, 7, 4.35, 12, 10];
static $periods_long = [
'GANTRY5_ENGINE_NICETIME_SECOND',
'GANTRY5_ENGINE_NICETIME_MINUTE',
'GANTRY5_ENGINE_NICETIME_HOUR',
'GANTRY5_ENGINE_NICETIME_DAY',
'GANTRY5_ENGINE_NICETIME_WEEK',
'GANTRY5_ENGINE_NICETIME_MONTH',
'GANTRY5_ENGINE_NICETIME_YEAR',
'GANTRY5_ENGINE_NICETIME_DECADE'
];
static $periods_short = [
'GANTRY5_ENGINE_NICETIME_SEC',
'GANTRY5_ENGINE_NICETIME_MIN',
'GANTRY5_ENGINE_NICETIME_HR',
'GANTRY5_ENGINE_NICETIME_DAY',
'GANTRY5_ENGINE_NICETIME_WK',
'GANTRY5_ENGINE_NICETIME_MO',
'GANTRY5_ENGINE_NICETIME_YR',
'GANTRY5_ENGINE_NICETIME_DEC'
];
if (empty($date)) {
return
$this->transFilter('GANTRY5_ENGINE_NICETIME_NO_DATE_PROVIDED');
}
$periods = $long_strings ? $periods_long : $periods_short;
$now = time();
// check if unix timestamp
if ((string)(int)$date === (string)$date) {
$unix_date = (int)$date;
} else {
$unix_date = strtotime($date);
}
// check validity of date
if (!$unix_date) {
return
$this->transFilter('GANTRY5_ENGINE_NICETIME_BAD_DATE');
}
// is it future date or past date
if ($now > $unix_date) {
$difference = $now - $unix_date;
$tense =
$this->transFilter('GANTRY5_ENGINE_NICETIME_AGO');
} else if ($now === $unix_date) {
$difference = $now - $unix_date;
$tense =
$this->transFilter('GANTRY5_ENGINE_NICETIME_JUST_NOW');
} else {
$difference = $unix_date - $now;
$tense =
$this->transFilter('GANTRY5_ENGINE_NICETIME_FROM_NOW');
}
for ($j = 0; $difference >= $lengths[$j] && $j <
\count($lengths) - 1; $j++) {
$difference /= $lengths[$j];
}
$period = $periods[$j];
$difference = round($difference);
if ($difference !== 1) {
$period .= '_PLURAL';
}
$period = $this->transFilter($period);
if ($now === $unix_date) {
return $tense;
}
return "{$difference} {$period} {$tense}";
}
public function getCookie($name)
{
$gantry = Gantry::instance();
/** @var Request $request */
$request = $gantry['request'];
return $request->cookie[$name];
}
public function pregMatch($pattern, $subject, &$matches = [])
{
preg_match($pattern, $subject, $matches);
return $matches ?: false;
}
}
PKZ[�[��6���Url/Url.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Url;
class Url
{
/**
* UTF8 aware parse_url().
*
* @param string $url
* @param bool $queryArray
* @return array|bool
*/
public static function parse($url, $queryArray = false)
{
$encodedUrl = preg_replace_callback(
'%[^:/@?&=#]+%usD',
function ($matches) { return rawurlencode($matches[0]); },
$url
);
// PHP versions below 5.4.7 have troubles with URLs without scheme,
so lets help by fixing that.
// TODO: This is not needed in PHP >= 5.4.7, but for now we need
to test if the function works.
if ('/' === $encodedUrl[0] && false !==
strpos($encodedUrl, '://')) {
$schemeless = true;
// Fix the path so that parse_url() will not return false.
$parts = parse_url('fake://fake.com' . $encodedUrl);
// Remove the fake values.
unset($parts['scheme'], $parts['host']);
} else {
$parts = parse_url($encodedUrl);
}
if (!$parts) {
return false;
}
// PHP versions below 5.4.7 do not understand schemeless URLs
starting with // either.
if (isset($schemeless) && !isset($parts['host'])
&& 0 === strpos($encodedUrl, '//')) {
// Path is stored in format: //[host]/[path], so let's fix
it.
list($parts['host'], $path) = explode('/',
substr($parts['path'], 2), 2);
$parts['path'] = "/{$path}";
}
foreach($parts as $name => $value) {
$parts[$name] = rawurldecode($value);
}
// Return query string also as an array if requested.
if ($queryArray) {
$parts['vars'] = isset($parts['query']) ?
static::parseQuery($parts['query']) : [];
}
return $parts;
}
/**
* Parse query string and return array.
*
* @param $query
* @return mixed
*/
public static function parseQuery($query)
{
parse_str($query, $vars);
return $vars;
}
/**
* Build parsed URL array.
*
* @param array $parsed_url
* @return string
*/
public static function build(array $parsed_url)
{
// Build query string from variables if they are set.
if (isset($parsed_url['vars'])) {
$parsed_url['query'] =
static::buildQuery($parsed_url['vars']);
}
// Build individual parts of the url.
$scheme = isset($parsed_url['scheme']) ?
$parsed_url['scheme'] . '://' : '';
$host = isset($parsed_url['host']) ?
$parsed_url['host'] : '';
$port = isset($parsed_url['port']) ? ':' .
$parsed_url['port'] : '';
$user = isset($parsed_url['user']) ?
$parsed_url['user'] : '';
$pass = isset($parsed_url['pass']) ? ':' .
$parsed_url['pass'] : '';
$pass = ($user || $pass) ? "{$pass}@" : '';
$path = isset($parsed_url['path']) ?
$parsed_url['path'] : '';
$query = isset($parsed_url['query']) ? '?' .
$parsed_url['query'] : '';
$fragment = isset($parsed_url['fragment']) ?
'#' . $parsed_url['fragment'] : '';
$scheme = $host && !$scheme ? '//' : $scheme;
return
"{$scheme}{$user}{$pass}{$host}{$port}{$path}{$query}{$fragment}";
}
/**
* Build query string from variables.
*
* @param array $vars
* @return null|string
*/
public static function buildQuery(array $vars)
{
$list = [];
foreach ($vars as $key => $var) {
$list[] = $key . '=' . rawurlencode($var);
}
return $list ? implode('&', $list) : null;
}
}
PKZ[�[�H��AAWhoops/SystemFacade.phpnu�[���<?php
/**
* @package Gantry5
* @author RocketTheme http://www.rockettheme.com
* @copyright Copyright (C) 2007 - 2017 RocketTheme, LLC
* @license Dual License: MIT or GNU/GPLv2 and later
*
* http://opensource.org/licenses/MIT
* http://www.gnu.org/licenses/gpl-2.0.html
*
* Gantry Framework code that extends GPL code is considered GNU/GPLv2 and
later
*/
namespace Gantry\Component\Whoops;
class SystemFacade extends \Whoops\Util\SystemFacade
{
protected $registeredPatterns;
protected $whoopsErrorHandler;
protected $whoopsExceptionHandler;
protected $whoopsShutdownHandler;
protected $platformExceptionHandler;
/**
* @param array|string $patterns List or a single regex pattern to
match for silencing errors in particular files.
*/
public function __construct($patterns = [])
{
$this->registeredPatterns = array_map(
function ($pattern) {
return["pattern" => $pattern];
},
(array) $patterns
);
}
/**
* @param callable $handler
* @param int|string $types
*
* @return callable|null
*/
public function setErrorHandler(callable $handler, $types =
'use-php-defaults')
{
// Workaround for PHP 5.5
if ($types === 'use-php-defaults') {
$types = E_ALL | E_STRICT;
}
$this->whoopsErrorHandler = $handler;
return parent::setErrorHandler([$this, 'handleError'],
$types);
}
/**
* @param callable $function
*
* @return void
*/
public function registerShutdownFunction(callable $function)
{
$this->whoopsShutdownHandler = $function;
register_shutdown_function([$this, 'handleShutdown']);
}
/**
* @param callable $handler
*
* @return callable|null
*/
public function setExceptionHandler(callable $handler)
{
$this->whoopsExceptionHandler = $handler;
$this->platformExceptionHandler =
parent::setExceptionHandler([$this, 'handleException']);
return $this->platformExceptionHandler;
}
/**
* Converts generic PHP errors to \ErrorException instances, before
passing them off to be handled.
*
* This method MUST be compatible with set_error_handler.
*
* @param int $level
* @param string $message
* @param string $file
* @param int $line
*
* @return bool
* @throws \ErrorException
*/
public function handleError($level, $message, $file = null, $line =
null)
{
$handler = $this->whoopsErrorHandler;
if (!$this->registeredPatterns) {
// Just forward to parent function is there aren't no
registered patterns.
return $handler($level, $message, $file, $line);
}
// If there are registered patterns, only handle errors if error
matches one of the patterns.
if ($level & error_reporting()) {
foreach ($this->registeredPatterns as $entry) {
$pathMatches = $file &&
preg_match($entry["pattern"], $file);
if ($pathMatches) {
return $handler($level, $message, $file, $line);
}
}
}
// Propagate error to the next handler, allows error_get_last() to
work on silenced errors.
return false;
}
/**
* Handles an exception, ultimately generating a Whoops error page.
*
* @param \Throwable $exception
* @return void
*/
public function handleException($exception)
{
$handler = $this->whoopsExceptionHandler;
// If there are registered patterns, only handle errors if error
matches one of the patterns.
if ($this->registeredPatterns) {
foreach ($this->registeredPatterns as $entry) {
$file = $exception->getFile();
$pathMatches = $file &&
preg_match($entry["pattern"], $file);
if ($pathMatches) {
$handler($exception);
return;
}
}
}
// Propagate error to the next handler.
if ($this->platformExceptionHandler) {
call_user_func_array($this->platformExceptionHandler,
[&$exception]);
}
}
/**
* Special case to deal with Fatal errors and the like.
*/
public function handleShutdown()
{
$handler = $this->whoopsShutdownHandler;
$error = $this->getLastError();
// Ignore core warnings and errors.
if ($error && !($error['type'] &
(E_CORE_WARNING | E_CORE_ERROR))) {
$handler();
}
}
}
PKk�[��fk�3�3ComponentHelper.phpnu�[���PKk�[�3��
�
:4ComponentRecord.phpnu�[���PKk�[��5d��'D?Exception/MissingComponentException.phpnu�[���PKk�[u�(zz7CRouter/RouterBase.phpnu�[���PKk�[�M�6���HRouter/RouterInterface.phpnu�[���PKk�[�2L ��KRouter/RouterLegacy.phpnu�[���PKk�[�`��
TRouter/RouterView.phpnu�[���PKk�[���xx"�iRouter/RouterViewConfiguration.phpnu�[���PKk�[UA*���zRouter/Rules/MenuRules.phpnu�[���PKk�[��`TT{�Router/Rules/NomenuRules.phpnu�[���PKk�[fnJoo�Router/Rules/RulesInterface.phpnu�[���PKk�[_�Y��٧Router/Rules/StandardRules.phpnu�[���PKJ[�[�(r����Admin/HtmlController.phpnu�[���PKJ[�[��p�����Admin/JsonController.phpnu�[���PKJ[�[ܵ����#�Assignments/AbstractAssignments.phpnu�[���PKJ[�[�d�//
W�Assignments/AssignmentFilter.phpnu�[���PKJ[�[3�U���$�Assignments/AssignmentsInterface.phpnu�[���PKJ[�[�)!�99Collection/Collection.phpnu�[���PKJ[�[�?�~~"�Collection/CollectionInterface.phpnu�[���PKK[�[�c��9$9$j
Config/BlueprintForm.phpnu�[���PKK[�[ù����.Config/BlueprintSchema.phpnu�[���PKK[�[�-��&JConfig/CompiledBase.phpnu�[���PKK[�[�ԂDD�bConfig/CompiledBlueprints.phpnu�[���PKK[�[��ͭ
�kConfig/CompiledConfig.phpnu�[���PKK[�[Ѱ�Pdd�uConfig/Config.phpnu�[���PKK[�[ҽ`\!\!��Config/ConfigFileFinder.phpnu�[���PKK[�[��VV4�Config/Validation.phpnu�[���PKK[�[��"�Config/ValidationException.phpnu�[���PKM[�[#NJ����Content/Block/ContentBlock.phpnu�[���PKM[�[{�?:xx'�&Content/Block/ContentBlockInterface.phpnu�[���PKM[�[��ue�2�2�*Content/Block/HtmlBlock.phpnu�[���PKM[�[�v*B��$�]Content/Block/HtmlBlockInterface.phpnu�[���PKM[�[ �Q��i�i!�aContent/Document/HtmlDocument.phpnu�[���PKN[�[,���"�Controller/BaseController.phpnu�[���PKN[�[���00h�Controller/HtmlController.phpnu�[���PKN[�[0s�����Controller/JsonController.phpnu�[���PKN[�[�VVaa)&�Controller/RestfulControllerInterface.phpnu�[���PKN[�[��7���File/CompiledFile.phpnu�[���PKN[�[{BB!File/CompiledYamlFile.phpnu�[���PKN[�[�{�+�+� Filesystem/Folder.phpnu�[���PKO[�[ڀ}e
�5Filesystem/Streams.phpnu�[���PKO[�[����WW�@Gantry/GantryTrait.phpnu�[���PKO[�[�;o�rDGettext/Gettext.phpnu�[���PKO[�[�xх�����PLayout/Layout.phpnu�[���PKO[�[.|�G
��Layout/LayoutReader.phpnu�[���PKO[�[Q�E���O�Layout/Version/Format0.phpnu�[���PKQ[�[��+�#�#�Layout/Version/Format1.phpnu�[���PKQ[�[��]��E�E-
Layout/Version/Format2.phpnu�[���PKQ[�[j픞--=SMenu/AbstractMenu.phpnu�[���PKQ[�[��1D�&�&
��Menu/Item.phpnu�[���PKQ[�[�{{GLGL��Outline/OutlineCollection.phpnu�[���PKR[�[�T�ڍ�(�Position/Module.phpnu�[���PKR[�[�l*�)#)#�Position/Position.phpnu�[���PKR[�[���..f(Position/Positions.phpnu�[���PKR[�[���O���ARemote/Response.phpnu�[���PKR[�[��N@�]Request/Input.phpnu�[���PKS[�[(5����kRequest/Request.phpnu�[���PKT[�[]�>J��rResponse/HtmlResponse.phpnu�[���PKT[�[(�gg&tResponse/JsonResponse.phpnu�[���PKT[�[�~�77ւResponse/RedirectResponse.phpnu�[���PKT[�[ʚ@%��Z�Response/Response.phpnu�[���PKU[�[V�99j�Router/Router.phpnu�[���PKU[�[X}�q&q&�Stylesheet/CssCompiler.phpnu�[���PKU[�[�03��#��Stylesheet/CssCompilerInterface.phpnu�[���PKU[�[�d瑄,�,��Stylesheet/Scss/Compiler.phpnu�[���PKU[�[�}���Stylesheet/ScssCompiler.phpnu�[���PKU[�[�i}}�!System/Messages.phpnu�[���PKV[�[�Y�22�$Theme/AbstractTheme.phpnu�[���PKV[�[�����ATheme/ThemeDetails.phpnu�[���PKX[�[1���%�%5YTheme/ThemeInstaller.phpnu�[���PKX[�[��IA��jTheme/ThemeInterface.phpnu�[���PKX[�[b����Z�Z��Theme/ThemeTrait.phpnu�[���PKX[�[$�E��
�
��Translator/Translator.phpnu�[���PKX[�[�f��GG"�Translator/TranslatorInterface.phpnu�[���PKX[�[�Ϸ���Twig/Node/TwigNodeAssets.phpnu�[���PKX[�[���y���Twig/Node/TwigNodeMarkdown.phpnu�[���PKY[�[7n^c���
Twig/Node/TwigNodePageblock.phpnu�[���PKY[�[�ܽ���yTwig/Node/TwigNodeScripts.phpnu�[���PKY[�[JtE5���Twig/Node/TwigNodeStyles.phpnu�[���PKY[�[�$�� �Twig/Node/TwigNodeSwitch.phpnu�[���PKY[�[�K��D
Twig/Node/TwigNodeThrow.phpnu�[���PKY[�[Bh���
%Twig/Node/TwigNodeTryCatch.phpnu�[���PKY[�[��5��
�
& ,Twig/TokenParser/TokenParserAssets.phpnu�[���PKY[�[B�$��(�6Twig/TokenParser/TokenParserMarkdown.phpnu�[���PKY[�[I��\ \ )?=Twig/TokenParser/TokenParserPageblock.phpnu�[���PKY[�[
FX���'�FTwig/TokenParser/TokenParserScripts.phpnu�[���PKY[�[�++B��&$KTwig/TokenParser/TokenParserStyles.phpnu�[���PKY[�[���#��&GOTwig/TokenParser/TokenParserSwitch.phpnu�[���PKY[�[�ʱtt%�^Twig/TokenParser/TokenParserThrow.phpnu�[���PKY[�[�TLL(RdTwig/TokenParser/TokenParserTryCatch.phpnu�[���PKY[�[�
��kTwig/TwigCacheFilesystem.phpnu�[���PKY[�[K�
k�Q�Q_wTwig/TwigExtension.phpnu�[���PKZ[�[��6���\�Url/Url.phpnu�[���PKZ[�[�H��AAp�Whoops/SystemFacade.phpnu�[���PK^^X!��