winter/modules/cms/classes/ComponentPartial.php
Samuel Georges d1c160f9dc Check both instances to fix #1854
It appears there is no way around this. All directories should be lower case in October, prior to this, October wanted uppercase characters. Make up your mind guy, come on! ;-)
2017-07-01 12:26:55 +10:00

263 lines
6.9 KiB
PHP

<?php namespace Cms\Classes;
use File;
use Lang;
use Cms\Contracts\CmsObject as CmsObjectContract;
use Cms\Helpers\File as FileHelper;
use October\Rain\Extension\Extendable;
use ApplicationException;
/**
* The CMS component partial class. These objects are read-only.
*
* @package october\cms
* @author Alexey Bobkov, Samuel Georges
*/
class ComponentPartial extends Extendable implements CmsObjectContract
{
/**
* @var \Cms\Classes\ComponentBase A reference to the CMS component containing the object.
*/
protected $component;
/**
* @var string The component partial file name.
*/
public $fileName;
/**
* @var string Last modified time.
*/
public $mtime;
/**
* @var string Partial content.
*/
public $content;
/**
* @var int The maximum allowed path nesting level. The default value is 2,
* meaning that files can only exist in the root directory, or in a
* subdirectory. Set to null if any level is allowed.
*/
protected $maxNesting = 2;
/**
* @var array Allowable file extensions.
*/
protected $allowedExtensions = ['htm'];
/**
* @var string Default file extension.
*/
protected $defaultExtension = 'htm';
/**
* Creates an instance of the object and associates it with a CMS component.
* @param \Cms\Classes\ComponentBase $component Specifies the component the object belongs to.
*/
public function __construct(ComponentBase $component)
{
$this->component = $component;
parent::__construct();
}
/**
* Loads the object from a file.
* This method is used in the CMS back-end. It doesn't use any caching.
* @param \Cms\Classes\ComponentBase $component Specifies the component the object belongs to.
* @param string $fileName Specifies the file name, with the extension.
* The file name can contain only alphanumeric symbols, dashes and dots.
* @return mixed Returns a CMS object instance or null if the object wasn't found.
*/
public static function load($component, $fileName)
{
return (new static($component))->find($fileName);
}
/**
* There is not much point caching a component partial, so this behavior
* reverts to a regular load call.
* @param \Cms\Classes\ComponentBase $component
* @param string $fileName
* @return mixed
*/
public static function loadCached($component, $fileName)
{
return static::load($component, $fileName);
}
/**
* Checks if a partial override exists in the supplied theme and returns it.
* Since the beginning of time, October inconsistently checked for overrides
* using the component alias exactly, resulting in a folder with uppercase
* characters, subsequently this method checks for both variants.
*
* @param \Cms\Classes\Theme $theme
* @param \Cms\Classes\ComponentBase $component
* @param string $fileName
* @return mixed
*/
public static function loadOverrideCached($theme, $component, $fileName)
{
$partial = Partial::loadCached($theme, strtolower($component->alias) . '/' . $fileName);
if ($partial === null) {
$partial = Partial::loadCached($theme, $component->alias . '/' . $fileName);
}
return $partial;
}
/**
* Find a single template by its file name.
*
* @param string $fileName
* @return mixed|static
*/
public function find($fileName)
{
$fileName = $this->validateFileName($fileName);
$filePath = $this->getFilePath($fileName);
if (!File::isFile($filePath)) {
return null;
}
if (($content = @File::get($filePath)) === false) {
return null;
}
$this->fileName = $fileName;
$this->mtime = File::lastModified($filePath);
$this->content = $content;
return $this;
}
/**
* Returns true if the specific component contains a matching partial.
* @param \Cms\Classes\ComponentBase $component Specifies a component the file belongs to.
* @param string $fileName Specifies the file name to check.
* @return bool
*/
public static function check(ComponentBase $component, $fileName)
{
$partial = new static($component);
$filePath = $partial->getFilePath($fileName);
if (!strlen(File::extension($filePath))) {
$filePath .= '.'.$partial->getDefaultExtension();
}
return File::isFile($filePath);
}
/**
* Checks the supplied file name for validity.
* @param string $fileName
* @return string
*/
protected function validateFileName($fileName)
{
if (!FileHelper::validatePath($fileName, $this->maxNesting)) {
throw new ApplicationException(Lang::get('cms::lang.cms_object.invalid_file', [
'name' => $fileName
]));
}
if (!strlen(File::extension($fileName))) {
$fileName .= '.'.$this->defaultExtension;
}
return $fileName;
}
/**
* Returns the file content.
* @return string
*/
public function getContent()
{
return $this->content;
}
/**
* Returns the Twig content string.
* @return string
*/
public function getTwigContent()
{
return $this->content;
}
/**
* Returns the key used by the Twig cache.
* @return string
*/
public function getTwigCacheKey()
{
return $this->getFilePath();
}
/**
* Returns the file name.
* @return string
*/
public function getFileName()
{
return $this->fileName;
}
/**
* Returns the default extension used by this template.
* @return string
*/
public function getDefaultExtension()
{
return $this->defaultExtension;
}
/**
* Returns the file name without the extension.
* @return string
*/
public function getBaseFileName()
{
$pos = strrpos($this->fileName, '.');
if ($pos === false) {
return $this->fileName;
}
return substr($this->fileName, 0, $pos);
}
/**
* Returns the absolute file path.
* @param string $fileName Specifies the file name to return the path to.
* @return string
*/
public function getFilePath($fileName = null)
{
if ($fileName === null) {
$fileName = $this->fileName;
}
$component = $this->component;
$path = $component->getPath().'/'.$fileName;
/*
* Check the shared "/partials" directory for the partial
*/
if (!File::isFile($path)) {
$sharedDir = dirname($component->getPath()).'/partials';
$sharedPath = $sharedDir.'/'.$fileName;
if (File::isFile($sharedPath)) {
return $sharedPath;
}
}
return $path;
}
}