diff --git a/modules/cms/classes/CmsCompoundObject.php b/modules/cms/classes/CmsCompoundObject.php index f09b1d131..ce776d1a9 100644 --- a/modules/cms/classes/CmsCompoundObject.php +++ b/modules/cms/classes/CmsCompoundObject.php @@ -1,10 +1,12 @@ parseComponentSettings(); + $this->validateSettings(); $this->parseSettings(); } @@ -95,6 +98,21 @@ class CmsCompoundObject extends CmsObject return new CmsObjectCollection($models); } + /** + * If the model is loaded with an invalid INI section, the invalid content will be + * passed as a special attribute. Look for it, then locate the failure reason. + * + * @return void + */ + protected function validateSettings() + { + if (isset($this->attributes[SectionParser::ERROR_INI])) { + CmsException::mask($this, 200); + Ini::parse($this->attributes[SectionParser::ERROR_INI]); + CmsException::unmask(); + } + } + /** * Parses the settings array. * Child classes can override this method in order to update diff --git a/modules/cms/classes/CmsException.php b/modules/cms/classes/CmsException.php index 7227d89be..e8d415b3f 100644 --- a/modules/cms/classes/CmsException.php +++ b/modules/cms/classes/CmsException.php @@ -2,8 +2,8 @@ use File; use Twig_Error; -use Cms\Classes\SectionParser; use October\Rain\Exception\ApplicationException; +use October\Rain\Halcyon\Processors\SectionParser; use Exception; /** @@ -110,7 +110,7 @@ class CmsException extends ApplicationException if (strpos($message, 'Unknown') === false) { return false; } - if (strpos($exception->getFile(), 'SectionParser.php') === false) { + if (strpos($exception->getFile(), 'Ini.php') === false) { return false; } diff --git a/modules/cms/classes/SectionParser.php b/modules/cms/classes/SectionParser.php deleted file mode 100644 index a0b26de07..000000000 --- a/modules/cms/classes/SectionParser.php +++ /dev/null @@ -1,174 +0,0 @@ - - * INI settings section - * == - * PHP code section - * == - * Twig markup section - * - * If the content has only 2 sections they are considered as settings and Twig. - * If there is only a single section, it is considered as Twig. - * @param string $content Specifies the file content. - * @return array Returns an array with the following indexes: 'settings', 'markup', 'code'. - * The 'markup' and 'code' elements contain strings. The 'settings' element contains the - * parsed INI file as array. If the content string doesn't contain a section, the corresponding - * result element has null value. - */ - public static function parse($content) - { - $sections = preg_split('/^={2,}\s*/m', $content, -1); - $count = count($sections); - foreach ($sections as &$section) { - $section = trim($section); - } - - $result = [ - 'settings' => [], - 'code' => null, - 'markup' => null - ]; - - if ($count >= 3) { - $result['settings'] = Ini::parse($sections[0], true); - $result['code'] = $sections[1]; - - $result['code'] = preg_replace('/^\s*\<\?php/', '', $result['code']); - $result['code'] = preg_replace('/^\s*\<\?/', '', $result['code']); - $result['code'] = preg_replace('/\?\>\s*$/', '', $result['code']); - - $result['markup'] = $sections[2]; - } - elseif ($count == 2) { - $result['settings'] = Ini::parse($sections[0], true); - $result['markup'] = $sections[1]; - } - elseif ($count == 1) { - $result['markup'] = $sections[0]; - } - - return $result; - } - - /** - * Same as parse method, except the line number where the respective section - * begins is returned. - * @param string $content Specifies the file content. - * @return array Returns an array with the following indexes: 'settings', 'markup', 'code'. - */ - public static function parseOffset($content) - { - $content = Str::normalizeEol($content); - $sections = preg_split('/^={2,}\s*/m', $content, -1); - $count = count($sections); - - $result = [ - 'settings' => null, - 'code' => null, - 'markup' => null - ]; - - if ($count >= 3) { - $result['settings'] = self::adjustLinePosition($content); - $result['code'] = self::calculateLinePosition($content); - $result['markup'] = self::calculateLinePosition($content, 2); - } - elseif ($count == 2) { - $result['settings'] = self::adjustLinePosition($content); - $result['markup'] = self::calculateLinePosition($content); - } - elseif ($count == 1) { - $result['markup'] = 1; - } - - return $result; - } - - /** - * Returns the line number of a found instance of CMS object section separator (==). - * @param string $content Object content - * @param int $instance Which instance to look for - * @return int The line number the instance was found. - */ - private static function calculateLinePosition($content, $instance = 1) - { - $count = 0; - $lines = explode(PHP_EOL, $content); - foreach ($lines as $number => $line) { - if (trim($line) == self::SECTION_SEPARATOR) { - $count++; - } - - if ($count == $instance) { - return static::adjustLinePosition($content, $number); - } - } - - return null; - } - - /** - * Pushes the starting line number forward since it is not always directly - * after the separator (==). There can be an opening tag or white space in between - * where the section really begins. - * @param string $content Object content - * @param int $startLine The calculated starting line from calculateLinePosition() - * @return int The adjusted line number. - */ - private static function adjustLinePosition($content, $startLine = -1) - { - // Account for the separator itself. - $startLine++; - - $lines = array_slice(explode(PHP_EOL, $content), $startLine); - foreach ($lines as $line) { - $line = trim($line); - - /* - * Empty line - */ - if ($line == '') { - $startLine++; - continue; - } - - /* - * PHP line - */ - if ($line == '