Seditio Source
Root |
./othercms/xenForo 2.2.8/src/XF/DevelopmentOutput/Template.php
<?php

namespace XF\DevelopmentOutput;

use
XF\Mvc\Entity\Entity;
use
XF\Template\Templater;

use function
count;

class
Template extends AbstractHandler implements \XF\Template\WatcherInterface
{
    protected
$templatesWatched = [];
    protected
$templatesActioned = [];

    protected function
getTypeDir()
    {
        return
'templates';
    }

    public function
export(Entity $template)
    {
        if (!
$this->isRelevant($template))
        {
            return
true;
        }

       
$metadata = [
           
'version_id' => $template->version_id,
           
'version_string' => $template->version_string
       
];

       
$fileName = $this->getFileName($template);
        return
$this->developmentOutput->writeFile($this->getTypeDir(), $template->addon_id, $fileName, $template->template, $metadata, true);
    }

    protected function
getEntityForImport($parts, $addOnId, $json, array $options)
    {
        list(
$type, $title) = $parts;

       
$template = \XF::em()->getFinder('XF:Template')
            ->
where([
               
'type' => $type,
               
'title' => $title,
               
'style_id' => 0
           
])->fetchOne();
        if (!
$template)
        {
           
$template = \XF::em()->create('XF:Template');
        }

       
$this->prepareEntityForImport($template, $options);

        return
$template;
    }

    public function
import($name, $addOnId, $contents, array $metadata, array $options = [])
    {
       
$parts = preg_split('#[:/\\\\]#', $name, 2);
        if (
count($parts) == 1)
        {
            throw new \
InvalidArgumentException("Template $name does not contain a type component");
        }

        list(
$type, $title) = $parts;

       
$template = $this->getEntityForImport($parts, $addOnId, null, $options);
       
$template->setOption('check_duplicate', false);
       
$template->setOption('report_modification_errors', false);

       
$template->set('title', $title, ['forceSet' => true]);
       
$template->set('type', $type, ['forceSet' => true]);
       
$template->set('style_id', 0, ['forceSet' => true]);
       
$template->set('addon_id', $addOnId, ['forceSet' => true]);
       
$template->set('template', $contents, ['forceSet' => true]);

       
$contentsChanged = (
            !isset(
$metadata['hash'])
            ||
$this->developmentOutput->hashContents($contents) != $metadata['hash']
        );

       
// We only use the metadata version if we're told we can or if it appears to match our version of the template.
        // If our version of the template differs, then we potentially need to update the template version. This approach
        // should avoid situations where templates get updated but their version does not.
       
$useMetaVersion = (empty($options['ignore_meta_version']) && !$contentsChanged);
       
$usedMetaVersion = false;

        if (
$useMetaVersion && isset($metadata['version_id']) && isset($metadata['version_string']))
        {
           
$template->version_id = $metadata['version_id'];
           
$template->version_string = $metadata['version_string'];

           
$usedMetaVersion = true;
        }

       
$template->preSave();

        if (
$template->isChanged('version_id') && !$usedMetaVersion)
        {
           
// we need to write this back to the dev output
           
$template->getBehavior('XF:DevOutputWritable')->setOption('write_dev_output', true);
        }

       
$template->save();
       
// this will update the metadata itself

       
return $template;
    }

    protected function
isRelevant(Entity $entity, $new = true)
    {
       
$styleId = $new ? $entity->getValue('style_id') : $entity->getExistingValue('style_id');
        return
parent::isRelevant($entity, $new) && !$styleId;
    }

    public function
getFileName(Entity $template, $new = true)
    {
       
$title = $new ? $template->getValue('title') : $template->getExistingValue('title');
       
$type = $new ? $template->getValue('type') : $template->getExistingValue('type');

        return
$this->convertTemplateNameToFile($type, $title);
    }

    public function
convertTemplateFileToName($name)
    {
        if (
substr($name, -5) == '.html')
        {
           
$name = substr($name, 0, -5);
        }

       
$name = str_replace('/', ':', $name);

        return
$name;
    }

    public function
convertTemplateNameToFile($type, $name)
    {
        if (!
strpos($name, '.'))
        {
           
$name = "$name.html";
        }

        return
$type . '/' . $name;
    }

    public function
watchTemplate(Templater $templater, $type, $name)
    {
       
$fileName = $this->convertTemplateNameToFile($type, $name);

        if (isset(
$this->templatesWatched[$fileName]))
        {
            return
false;
        }

       
$typeDir = $this->getTypeDir();
       
$actionTaken = false;

        foreach (
$this->developmentOutput->getTypeMetadata($typeDir) AS $addOnId => $addOnMeta)
        {
           
$fullPath = $this->developmentOutput->getFilePath($typeDir, $addOnId, $fileName);
            if (
file_exists($fullPath))
            {
               
$contents = file_get_contents($fullPath);
               
$hash = $this->developmentOutput->hashContents($contents);

               
$templateMeta = $addOnMeta[$fileName] ?? [];
               
$metaHash = $templateMeta ? $templateMeta['hash'] : null;

                if (!
$metaHash || $hash !== $metaHash)
                {
                   
// metadata doesn't exist or has a different hash - template has been added
                    // or edited so the version needs to be updated
                   
$recompile = true;
                   
$ignoreMetaVersion = true;
                }
                else
                {
                   
// metadata matches -- we can accept the metadata hash but might still need to recompile
                   
$recompile = false;
                   
$ignoreMetaVersion = false;

                   
$compiledFile = $templater->getTemplateFilePath($type, $name, 0);
                    if (!
file_exists($compiledFile))
                    {
                       
$recompile = true;
                    }
                    else
                    {
                       
$compiledData = file_get_contents($compiledFile);
                        if (
preg_match('#<?php\s+// FROM HASH: ([^\s]+)#s', $compiledData, $match))
                        {
                            if (
$match[1] !== $hash)
                            {
                               
$recompile = true;
                            }
                        }
                        else
                        {
                           
$recompile = true;
                        }
                    }
                }

                if (
$recompile)
                {
                   
$this->import(
                       
"$type:$name", $addOnId, $contents, $templateMeta,
                        [
'ignore_meta_version' => $ignoreMetaVersion]
                    );
                   
$actionTaken = true;
                }
            }
            else if (isset(
$addOnMeta[$fileName]))
            {
               
$this->developmentOutput->removeMetadata($typeDir, $addOnId, $fileName);
               
$actionTaken = true;
            }
        }

       
$this->templatesWatched[$fileName] = true;

        if (
$actionTaken)
        {
           
$this->templatesActioned[$fileName] = true;
        }

        return
$actionTaken;
    }

    public function
hasActionedTemplates()
    {
        return !empty(
$this->templatesActioned);
    }
}