diff --git a/CHANGELOG.md b/CHANGELOG.md index 972507d9c5..6d81ab63e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +# v0.9.5 beta +## 11/09/2014 + +1. [](#new) + * Added quality setting to medium for compression configuration of images + * Added new onPageContentProcessed() event that is post-content processing but pre-caching +2. [](#improved) + * Added support for AND and OR taxonomy filtering. AND by default (was OR) + * Added specific clearing options for CLI clear-cache command + * Moved environment method to URI so it can be accessible in plugins and themes + * Set Grav's output variable to public so it can be manipulated in onOutputGenerated event + * Updated vendor libraries to latest versions + * Better handing of 'home' in active menu state detection + * Various PSR code tidying + * Improved some error messages and notices +3. [](#bugfix) + * Force route rebuild when configuration changes + * Fix for 'installed undefined' error in CLI versions command + * Do not remove the JSON/Text error handlers + * Fix for supporting inline JS and CSS when Asset pipeline enabled + * Fix for Data URLs in CSS being badly formed + * Fix Markdown links with fragment and query elements + # v0.9.4 beta ## 10/29/2014 diff --git a/composer.json b/composer.json index 70ad4cbc66..236f322578 100644 --- a/composer.json +++ b/composer.json @@ -27,10 +27,6 @@ { "type": "vcs", "url": "https://github.com/rockettheme/toolbox" - }, - { - "type": "vcs", - "url": "https://github.com/rhukster/minify" } ], "autoload": { diff --git a/system/defines.php b/system/defines.php index 51b2203f2a..8e7b035ef3 100644 --- a/system/defines.php +++ b/system/defines.php @@ -2,7 +2,7 @@ // Some standard defines define('GRAV', true); -define('GRAV_VERSION', '0.9.4'); +define('GRAV_VERSION', '0.9.5'); define('DS', '/'); // Directories and Paths diff --git a/system/src/Grav/Common/Assets.php b/system/src/Grav/Common/Assets.php index c89a6282fb..4f332ab361 100644 --- a/system/src/Grav/Common/Assets.php +++ b/system/src/Grav/Common/Assets.php @@ -338,12 +338,10 @@ public function css($attributes = []) foreach ($this->css_no_pipeline as $file) { $output .= ''."\n"; } - return $output; - } - - - foreach($this->css as $file) { - $output .= '' . "\n"; + } else { + foreach($this->css as $file) { + $output .= '' . "\n"; + } } // Render Inline CSS @@ -387,12 +385,10 @@ public function js($attributes = []) foreach ($this->js_no_pipeline as $file) { $output .= ''."\n"; } - return $output; - } - - - foreach($this->js as $file) { - $output .= '' . "\n"; + } else { + foreach($this->js as $file) { + $output .= '' . "\n"; + } } // Render Inline JS @@ -632,6 +628,10 @@ protected function cssRewrite($file, $relative_path) function($matches) use ($relative_path) { $old_url = $matches[1]; + + // ensure this is not a data url + if (strpos($old_url, 'data:') === 0) return $matches[0]; + $newpath = array(); $paths = explode('/', $old_url); diff --git a/system/src/Grav/Common/Errors/Errors.php b/system/src/Grav/Common/Errors/Errors.php index 591eba2b2d..57dfbd85a4 100644 --- a/system/src/Grav/Common/Errors/Errors.php +++ b/system/src/Grav/Common/Errors/Errors.php @@ -45,8 +45,6 @@ public function resetHandlers() $config = $grav['config']->get('system.errors'); if (isset($config['display']) && !$config['display']) { unset($this->handlerStack['pretty']); - unset($this->handlerStack['text']); - unset($this->handlerStack['json']); $this->handlerStack = array('simple' => new SimplePageHandler()) + $this->handlerStack; } if (isset($config['log']) && !$config['log']) { diff --git a/system/src/Grav/Common/Grav.php b/system/src/Grav/Common/Grav.php index 35c8f6b1fc..8ed8c499dd 100644 --- a/system/src/Grav/Common/Grav.php +++ b/system/src/Grav/Common/Grav.php @@ -25,7 +25,7 @@ class Grav extends Container /** * @var string */ - protected $output; + public $output; /** * @var static @@ -112,7 +112,7 @@ protected static function load(array $values) $medium = $media[$media_file]; // loop through actions for the image and call them - foreach ($c['uri']->query(null,true) as $action => $params) { + foreach ($c['uri']->query(null, true) as $action => $params) { if (in_array($action, Medium::$valid_actions)) { call_user_func_array(array(&$medium, $action), explode(',', $params)); } @@ -294,7 +294,7 @@ public function fireEvent($eventName, Event $event = null) */ public function shutdown() { - if($this['config']->get('system.debugger.shutdown.close_connection')) { + if ($this['config']->get('system.debugger.shutdown.close_connection')) { set_time_limit(0); ignore_user_abort(true); diff --git a/system/src/Grav/Common/Markdown/MarkdownGravLinkTrait.php b/system/src/Grav/Common/Markdown/MarkdownGravLinkTrait.php index 7ac0b20002..1357c686bf 100644 --- a/system/src/Grav/Common/Markdown/MarkdownGravLinkTrait.php +++ b/system/src/Grav/Common/Markdown/MarkdownGravLinkTrait.php @@ -33,7 +33,7 @@ protected function identifyLink($Excerpt) if (!isset($url['host']) && isset($url['path'])) { // convert the URl is required - $Excerpt['element']['attributes']['href'] = $this->convertUrl($url['path']); + $Excerpt['element']['attributes']['href'] = $this->convertUrl(Uri::build_url($url)); } } diff --git a/system/src/Grav/Common/Page/Medium.php b/system/src/Grav/Common/Page/Medium.php index bbee389c7c..f98c0d2c33 100644 --- a/system/src/Grav/Common/Page/Medium.php +++ b/system/src/Grav/Common/Page/Medium.php @@ -114,6 +114,16 @@ public function path() return $output; } + /** + * Sets the quality of the image + * @param Int $quality 0-100 quality + * @return Medium + */ + public function quality($quality) { + $this->quality = $quality; + return $this; + } + /** * Return URL to file. * @@ -149,6 +159,7 @@ public function format($type = null, $quality = 80) $this->type = $type; $this->quality = $quality; + return $this; } /** diff --git a/system/src/Grav/Common/Page/Page.php b/system/src/Grav/Common/Page/Page.php index c99e51f845..6a49b0a563 100644 --- a/system/src/Grav/Common/Page/Page.php +++ b/system/src/Grav/Common/Page/Page.php @@ -358,11 +358,34 @@ public function content($var = null) $this->content = $content; + // Process any post-processing but pre-caching functionality + self::$grav->fireEvent('onPageContentProcessed', new Event(['page' => $this])); + } return $this->content; } + /** + * Needed by the onPageContentProcessed event to get the raw page content + * + * @return string the current page content + */ + public function getRawContent() + { + return $this->content; + } + + /** + * Needed by the onPageContentProcessed event to set the raw page content + * + * @param $content + */ + public function setRawContent($content) + { + $this->content = $content; + } + /** * Get value from a page variable (used mostly for creating edit forms). * @@ -1326,10 +1349,21 @@ public function activeChild() { /** @var Uri $uri */ $uri = self::$grav['uri']; + $config = self::$grav['config']; - if (!$this->home() && (strpos($uri->url(), $this->url()) === 0)) { - return true; + // Special check when item is home + if ($this->home()) { + $paths = $uri->paths(); + $home = ltrim($config->get('system.home.alias'), '/'); + if ($paths[0] == $home) { + return true; + } + } else { + if (strpos($uri->url(), $this->url()) === 0) { + return true; + } } + return false; } @@ -1418,8 +1452,6 @@ public function collection($params = 'content') } } } - - $config->set('system.cache.enabled', false); // TODO: Do we still need this? } } // TODO: END OF MOVE diff --git a/system/src/Grav/Common/Page/Pages.php b/system/src/Grav/Common/Page/Pages.php index 23e30792f8..9b58304e6a 100644 --- a/system/src/Grav/Common/Page/Pages.php +++ b/system/src/Grav/Common/Page/Pages.php @@ -206,7 +206,9 @@ public function sortCollection(Collection $collection, $orderBy, $orderDir = 'as */ public function get($path) { - if (!is_null($path) && !is_string($path)) throw new \Exception(); + if (!is_null($path) && !is_string($path)) { + throw new \Exception(); + } return isset($this->instances[(string) $path]) ? $this->instances[(string) $path] : null; } @@ -319,7 +321,7 @@ public function getList(Page $current = null, $level = 0) * * @return Types */ - static public function getTypes() + public static function getTypes() { if (!self::$types) { self::$types = new Types(); @@ -339,7 +341,7 @@ static public function getTypes() * * @return array */ - static public function types() + public static function types() { $types = self::getTypes(); @@ -351,7 +353,7 @@ static public function types() * * @return array */ - static public function modularTypes() + public static function modularTypes() { $types = self::getTypes(); @@ -363,7 +365,7 @@ static public function modularTypes() * * @return array */ - static public function parents() + public static function parents() { $grav = Grav::instance(); @@ -404,10 +406,11 @@ protected function buildPages() $last_modified = Folder::lastModifiedFile(PAGES_DIR); } - $page_cache_id = md5(USER_DIR.$last_modified); + $page_cache_id = md5(USER_DIR.$last_modified.$config->checksum()); list($this->instances, $this->routes, $this->children, $taxonomy_map, $this->sort) = $cache->fetch($page_cache_id); if (!$this->instances) { + $this->grav['debugger']->addMessage('Page cache missed, rebuilding pages..'); $this->recurse(); $this->buildRoutes(); @@ -418,6 +421,7 @@ protected function buildPages() ); } else { // If pages was found in cache, set the taxonomy + $this->grav['debugger']->addMessage('Page cache hit.'); $taxonomy->taxonomy($taxonomy_map); } } else { @@ -445,7 +449,9 @@ protected function recurse($directory = PAGES_DIR, Page &$parent = null) $config = $this->grav['config']; $page->path($directory); - if ($parent) $page->parent($parent); + if ($parent) { + $page->parent($parent); + } $page->orderDir($config->get('system.pages.order.dir')); $page->orderBy($config->get('system.pages.order.by')); @@ -608,7 +614,7 @@ protected function buildSort($path, array $pages, $order_by = 'default', $manual // handle special case when order_by is random if ($order_by == 'random') { - $list = $this->array_shuffle($list); + $list = $this->arrayShuffle($list); } else { // else just sort the list according to specified key asort($list); @@ -643,12 +649,13 @@ protected function buildSort($path, array $pages, $order_by = 'default', $manual } // Shuffles and associative array - protected function array_shuffle($list) { + protected function arrayShuffle($list) + { $keys = array_keys($list); shuffle($keys); $new = array(); - foreach($keys as $key) { + foreach ($keys as $key) { $new[$key] = $list[$key]; } diff --git a/system/src/Grav/Common/Service/ConfigServiceProvider.php b/system/src/Grav/Common/Service/ConfigServiceProvider.php index a2885876f0..0945ce038c 100644 --- a/system/src/Grav/Common/Service/ConfigServiceProvider.php +++ b/system/src/Grav/Common/Service/ConfigServiceProvider.php @@ -3,6 +3,7 @@ use Grav\Common\Config\Config; use Grav\Common\Grav; +use Grav\Common\Uri; use Grav\Common\Filesystem\Folder; use Pimple\Container; use Pimple\ServiceProviderInterface; @@ -33,7 +34,7 @@ public function register(Container $container) public function loadMasterConfig(Container $container) { - $environment = $this->getEnvironment(); + $environment = $this->getEnvironment($container); $file = CACHE_DIR . 'compiled/config/master-'.$environment.'.php'; $data = is_file($file) ? (array) include $file : []; if ($data) { @@ -54,25 +55,17 @@ public function loadMasterConfig(Container $container) public function loadMasterBlueprints(Container $container) { - $environment = $this->getEnvironment(); + $environment = $this->getEnvironment($container); $file = CACHE_DIR . 'compiled/blueprints/master-'.$environment.'.php'; $data = is_file($file) ? (array) include $file : []; return new Blueprints($data, $container); } - public function getEnvironment() + public function getEnvironment(Container $container) { - if (!$this->environment) { - $address = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '::1'; - - // check for localhost variations - if ($address == '::1' || $address == '127.0.0.1') { - $hostname = 'localhost'; - } else { - $hostname = gethostname(); - } - $this->environment = $hostname; + if (!isset($this->environment)) { + $this->environment = $container['uri']->environment(); } return $this->environment; diff --git a/system/src/Grav/Common/Taxonomy.php b/system/src/Grav/Common/Taxonomy.php index 1224cbee2d..6ea5a35912 100644 --- a/system/src/Grav/Common/Taxonomy.php +++ b/system/src/Grav/Common/Taxonomy.php @@ -71,20 +71,33 @@ public function addTaxonomy(Page $page, $page_taxonomy = null) * particular taxonomy. * * @param array $taxonomies taxonomies to search, eg ['tag'=>['animal','cat']] - * @return Page page object with sub-pages set to contain matches found in the taxonomy map + * @param string $operator can be 'or' or 'and' (defaults to 'or') + * @return Colleciton Collection object set to contain matches found in the taxonomy map */ - public function findTaxonomy($taxonomies) + public function findTaxonomy($taxonomies, $operator = 'and') { - $results = array(); + $matches = []; + $results = []; foreach ((array)$taxonomies as $taxonomy => $items) { foreach ((array) $items as $item) { if (isset($this->taxonomy_map[$taxonomy][$item])) { - $results = array_merge($results, $this->taxonomy_map[$taxonomy][$item]); + $matches[] = $this->taxonomy_map[$taxonomy][$item]; } } } + if (strtolower($operator) == 'or') { + foreach ($matches as $match) { + $results = array_merge($results, $match); + } + } else { + $results = $matches ? array_pop($matches) : []; + foreach ($matches as $match) { + $results = array_intersect_key($results, $match); + } + } + return new Collection($results, ['taxonomies' => $taxonomies]); } diff --git a/system/src/Grav/Common/Themes.php b/system/src/Grav/Common/Themes.php index eb580889c4..f5648391c5 100644 --- a/system/src/Grav/Common/Themes.php +++ b/system/src/Grav/Common/Themes.php @@ -37,7 +37,12 @@ public function init() /** @var Themes $themes */ $themes = $this->grav['themes']; $themes->configure(); - $instance = $themes->load(); + + try { + $instance = $themes->load(); + } catch (\InvalidArgumentException $e) { + throw new \RuntimeException($this->current(). ' theme could not be found'); + } if ($instance instanceof EventSubscriberInterface) { $events->addSubscriber($instance); diff --git a/system/src/Grav/Common/Twig.php b/system/src/Grav/Common/Twig.php index d10636f8e6..acdf04bd02 100644 --- a/system/src/Grav/Common/Twig.php +++ b/system/src/Grav/Common/Twig.php @@ -240,7 +240,7 @@ public function processSite($format = null) try { $output = $this->twig->render($template, $twig_vars); } catch (\Twig_Error_Loader $e) { - throw new \RuntimeException('Twig template not found: '.$template, 404, $e); + throw new \RuntimeException($e->getRawMessage(), 404, $e); } return $output; diff --git a/system/src/Grav/Common/Uri.php b/system/src/Grav/Common/Uri.php index 3e914334d9..4dbdb14d0e 100644 --- a/system/src/Grav/Common/Uri.php +++ b/system/src/Grav/Common/Uri.php @@ -9,6 +9,8 @@ */ class Uri { + public $url; + protected $base; protected $root; protected $bits; @@ -17,7 +19,6 @@ class Uri protected $content_path; protected $path; protected $paths; - protected $url; protected $query; protected $params; @@ -50,6 +51,16 @@ public function __construct() $root_path = substr($uri, 0, strpos($uri, '/', 1)) . $root_path; } + // set hostname + $address = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '::1'; + + // check for localhost variations + if ($address == '::1' || $address == '127.0.0.1') { + $this->host = 'localhost'; + } else { + $this->host = gethostname(); + } + $this->base = $base; $this->root = $base . $root_path; $this->url = $base . $uri; @@ -120,7 +131,7 @@ public function paths($id = null) if (isset($id)) { return $this->paths[$id]; } else { - return implode('/', $this->paths); + return $this->paths; } } @@ -213,7 +224,8 @@ public function url($include_host = false) * * @return String The path of the URI */ - public function path() { + public function path() + { return $this->path; } @@ -222,7 +234,8 @@ public function path() { * * @return String The extension of the URI */ - public function extension($default = null) { + public function extension($default = null) + { if (!$this->extension) { $this->extension = $default; } @@ -234,16 +247,28 @@ public function extension($default = null) { * * @return String The host of the URI */ - public function host() { + public function host() + { return $this->host; } + /** + * Gets the environment name + * + * @return String + */ + public function environment() + { + return $this->host(); + } + /** * Return the base of the URI * * @return String The base of the URI */ - public function base() { + public function base() + { return $this->base; } @@ -340,7 +365,8 @@ public function ip() * @param $parsed_url * @return string */ - public static function build_url($parsed_url) { + public static function build_url($parsed_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'] : ''; diff --git a/system/src/Grav/Console/Cli/ClearCacheCommand.php b/system/src/Grav/Console/Cli/ClearCacheCommand.php index aaad55c9a2..148d24634d 100644 --- a/system/src/Grav/Console/Cli/ClearCacheCommand.php +++ b/system/src/Grav/Console/Cli/ClearCacheCommand.php @@ -17,9 +17,6 @@ class ClearCacheCommand extends Command { - /** - * @var array - */ protected $standard_remove = [ 'cache/twig/', 'cache/doctrine/', @@ -29,15 +26,24 @@ class ClearCacheCommand extends Command 'assets/', ]; - /** - * @var array - */ protected $all_remove = [ 'cache/', 'images/', 'assets/' ]; + protected $assets_remove = [ + 'assets/' + ]; + + protected $images_remove = [ + 'images/' + ]; + + protected $cache_remove = [ + 'cache/' + ]; + /** * */ @@ -46,7 +52,10 @@ protected function configure() $this ->setName("clear-cache") ->setDescription("Clears Grav cache") - ->addOption('all', null, InputOption::VALUE_NONE, 'If set will remove all') + ->addOption('all', null, InputOption::VALUE_NONE, 'If set will remove all including compiled, twig, doctrine caches') + ->addOption('assets-only', null, InputOption::VALUE_NONE, 'If set will remove only assets/*') + ->addOption('images-only', null, InputOption::VALUE_NONE, 'If set will remove only images/*') + ->addOption('cache-only', null, InputOption::VALUE_NONE, 'If set will remove only cache/*') ->setHelp('The clear-cache deletes all cache files'); } @@ -84,6 +93,12 @@ private function cleanPaths(InputInterface $input, OutputInterface $output) if ($input->getOption('all')) { $remove_paths = $this->all_remove; + } elseif ($input->getOption('assets-only')) { + $remove_paths = $this->assets_remove; + } elseif ($input->getOption('images-only')) { + $remove_paths = $this->images_remove; + } elseif ($input->getOption('cache-only')) { + $remove_paths = $this->cache_remove; } else { $remove_paths = $this->standard_remove; } diff --git a/system/src/Grav/Console/Gpm/VersionCommand.php b/system/src/Grav/Console/Gpm/VersionCommand.php index 8840423d24..c1068d8ab2 100644 --- a/system/src/Grav/Console/Gpm/VersionCommand.php +++ b/system/src/Grav/Console/Gpm/VersionCommand.php @@ -58,6 +58,8 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->gpm = new GPM($this->input->getOption('force')); $packages = $this->input->getArgument('package'); + $installed = false; + if (!count($packages)) { $packages = ['grav']; }