Вход Регистрация
Файл: library/XenForo/DataWriter/Phrase.php
Строк: 370
<?php

/**
* Data writer for phrases.
*
* @package XenForo_Phrase
*/
class XenForo_DataWriter_Phrase extends XenForo_DataWriter
{
    
/**
     * Option that takes the path to the development template output directory.
     * If not specified, output will not be written. Default determined based
     * on config settings.
     *
     * @var string
     */
    
const OPTION_DEV_OUTPUT_DIR 'devOutputDir';

    
/**
     * Option that controls whether language-related caches will be rebuild.
     * Defaults to true.
     *
     * @var string
     */
    
const OPTION_REBUILD_LANGUAGE_CACHE 'rebuildLanguageCache';

    
/**
     * Option that controls whether templates that use this phrase should be recompiled.
     * This can be a slow process if updating a lot of phrases. Defaults to true.
     *
     * @var string
     */
    
const OPTION_FULL_RECOMPILE 'fullRecompile';

    
/**
     * Controls whether templates including this phrase are recompiled on change.
     * Defaults to true.
     *
     * @var string
     */
    
const OPTION_RECOMPILE_TEMPLATE 'recompileTemplate';

    
/**
     * Controls whether effective phrase values are compiled for this phrase on change.
     * Defaults to true.
     *
     * @var string
     */
    
const OPTION_RECOMPILE_PHRASE 'recompilePhrase';

    
/**
     * Option that controls if phrase map is rebuild when phrase is changed. Defaults to true.
     *
     * @var string
     */
    
const OPTION_REBUILD_PHRASE_MAP 'rebuildPhraseMap';

    
/**
     * If false, duplicate checking is disabled. An error will occur on dupes. Defaults to true.
     *
     * @var string
     */
    
const OPTION_CHECK_DUPLICATE 'checkDuplicate';

    
/**
     * Title of the phrase that will be created when a call to set the
     * existing data fails (when the data doesn't exist).
     *
     * @var string
     */
    
protected $_existingDataErrorPhrase 'requested_phrase_not_found';

    
/**
    * Gets the fields that are defined for the table. See parent for explanation.
    *
    * @return array
    */
    
protected function _getFields()
    {
        return array(
            
'xf_phrase' => array(
                
'phrase_id'    => array('type' => self::TYPE_UINT,   'autoIncrement' => true),
                
'language_id'  => array('type' => self::TYPE_UINT,   'required' => true),
                
'title'        => array('type' => self::TYPE_BINARY'required' => true'maxLength' => 100,
                    
'verification' => array('$this''_verifyTitle'),
                    
'requiredError' => 'please_enter_valid_title'
                
),
                
'phrase_text'  => array('type' => self::TYPE_STRING'default' => '''noTrim' => true),
                
'global_cache' => array('type' => self::TYPE_BOOLEAN'default' => 0),
                
'addon_id'     => array('type' => self::TYPE_STRING'maxLength' => 25'default' => ''),
                
'version_id'   => array('type' => self::TYPE_UINT'default' => 0),
                
'version_string' => array('type' => self::TYPE_STRING,  'maxLength' => 30'default' => '')
            )
        );
    }

    
/**
    * Gets the actual existing data out of data that was passed in. See parent for explanation.
    *
    * @param mixed
    *
    * @return array|false
    */
    
protected function _getExistingData($data)
    {
        if (!
$phrase_id $this->_getExistingPrimaryKey($data))
        {
            return 
false;
        }

        return array(
'xf_phrase' => $this->_getPhraseModel()->getPhraseById($phrase_id));
    }

    
/**
    * Gets SQL condition to update the existing record.
    *
    * @return string
    */
    
protected function _getUpdateCondition($tableName)
    {
        return 
'phrase_id = ' $this->_db->quote($this->getExisting('phrase_id'));
    }

    
/**
    * Gets the default set of options for this data writer.
    * If in debug mode and we have a development directory config, we set the
    * dev output directory automatically.
    *
    * @return array
    */
    
protected function _getDefaultOptions()
    {
        
$options = array(
            
self::OPTION_DEV_OUTPUT_DIR => '',
            
self::OPTION_REBUILD_LANGUAGE_CACHE => true,
            
self::OPTION_RECOMPILE_PHRASE => true,
            
self::OPTION_RECOMPILE_TEMPLATE => true,
            
self::OPTION_REBUILD_PHRASE_MAP => true,
            
self::OPTION_CHECK_DUPLICATE => true
        
);

        if (
XenForo_Application::debugMode())
        {
            
$options[self::OPTION_DEV_OUTPUT_DIR] = $this->_getPhraseModel()->getPhraseDevelopmentDirectory();
        }

        return 
$options;
    }

    
/**
     * Sets an option. If the OPTION_FULL_RECOMPILE option is specified, other options are
     * set instead.
     *
     * @param string $name
     * @param mixed $value
     */
    
public function setOption($name$value)
    {
        if (
$name === self::OPTION_FULL_RECOMPILE)
        {
            
parent::setOption(self::OPTION_RECOMPILE_PHRASE$value);
            
parent::setOption(self::OPTION_RECOMPILE_TEMPLATE$value);
        }
        else
        {
            
parent::setOption($name$value);
        }
    }

    
/**
     * Verifies that the phrase title ID is valid.
     *
     * @param string $title
     *
     * @return boolean
     */
    
protected function _verifyTitle(&$title)
    {
        if (
preg_match('/[^a-zA-Z0-9_]/'$title))
        {
            
$this->error(new XenForo_Phrase('please_enter_title_using_only_alphanumeric'), 'title');
            return 
false;
        }

        return 
true;
    }

    
/**
     * Pre-save handling.
     */
    
protected function _preSave()
    {
        if (
$this->getOption(self::OPTION_CHECK_DUPLICATE))
        {
            if (
$this->isChanged('title') || $this->isChanged('language_id'))
            {
                
$existing $this->_getPhraseModel()->getPhraseInLanguageByTitle($this->get('title'), $this->get('language_id'));
                if (
$existing)
                {
                    
$this->error(new XenForo_Phrase('phrase_titles_must_be_unique_in_language'), 'title');
                }
                else if (
$this->get('title'))
                {
                    
// check for an existing phrase by this title and make sure the case is unchanged
                    
$effective $this->_getPhraseModel()->getEffectivePhraseValuesInAllLanguages(array($this->get('title')));
                    if (
$effective)
                    {
                        
$effective reset($effective);
                        list(
$title) = each($effective);
                        
$this->set('title'$title);
                    }
                }
            }
        }

        if (
            (
$this->isChanged('addon_id') || $this->isChanged('title') || $this->isChanged('phrase_text'))
            && !
$this->isChanged('version_id')
        )
        {
            
$this->updateVersionId();
        }
    }

    
/**
    * Post-save handler.
    */
    
protected function _postSave()
    {
        
$phraseModel $this->_getPhraseModel();

        if (
$this->getOption(self::OPTION_REBUILD_PHRASE_MAP))
        {
            if (
$this->isChanged('title'))
            {
                
$phraseModel->buildPhraseMap($this->get('title'));
                if (
$existingTitle $this->getExisting('title'))
                {
                    
$phraseModel->buildPhraseMap($existingTitle);
                }
            }
            else if (
$this->isChanged('language_id'))
            {
                
$phraseModel->buildPhraseMap($this->get('title'));
            }
        }

        if (
$this->getOption(self::OPTION_RECOMPILE_PHRASE))
        {
            
$this->_recompilePhrase();
        }
        if (
$this->getOption(self::OPTION_RECOMPILE_TEMPLATE))
        {
            
$this->_recompileTemplatesIncludingPhrase();
        }

        
$this->_rebuildLanguageCaches();

        if (
$devDir $this->_getDevOutputDir())
        {
            
$this->_writeDevFileOutput($devDir);
        }
    }

    
/**
     * Rebuilds the language caches, if the option is enabled.
     */
    
protected function _rebuildLanguageCaches()
    {
        if (
$this->getOption(self::OPTION_REBUILD_LANGUAGE_CACHE))
        {
            
$this->_getLanguageModel()->rebuildLanguageCaches();
        }
    }

    
/**
     * Helper to get the developer data output directory only if it is enabled
     * and applicable to this situation.
     *
     * @return string
     */
    
protected function _getDevOutputDir()
    {
        if (
$this->get('language_id') == && $this->get('addon_id') == 'XenForo')
        {
            return 
$this->getOption(self::OPTION_DEV_OUTPUT_DIR);
        }
        else
        {
            return 
'';
        }
    }

    
/**
    * Writes the development file output to the specified directory. This will write
    * each template into an individual file for easier tracking in source control.
    *
    * @param string Path to directory to write to
    */
    
protected function _writeDevFileOutput($dir)
    {
        
$title $this->get('title');
        
$newFile $dir '/' $title '.txt';

        if (!
is_dir($dir) || !is_writable($dir))
        {
            throw new 
XenForo_Exception("Phrase development directory $dir is not writable");
        }

        
$fp fopen($newFile'w');
        
fwrite($fp$this->get('phrase_text'));
        
fclose($fp);

        
$this->_writeMetaDataDevFileOutput($dir$title$this->getMergedData());

        if (
$this->isUpdate() && $this->isChanged('title'))
        {
            
$this->_deleteExistingDevFile($dir);
        }
    }

    protected function 
_writeMetaDataDevFileOutput($dir$title$data)
    {
        
$metaDataFile $dir '/_metadata.xml';
        
XenForo_Helper_DevelopmentXml::writeMetaDataOutput(
            
$metaDataFile$title$data, array('global_cache''version_id''version_string')
        );
    }

    protected function 
_recompilePhrase()
    {
        
$this->_getPhraseModel()->compileNamedPhraseInLanguageTree($this->get('title'), $this->get('language_id'));
    }

    
/**
     * Recompiles all templates (admin and public) that include this phrase.
     */
    
protected function _recompileTemplatesIncludingPhrase()
    {
        
XenForo_Template_Compiler::resetPhraseCache();

        
$templateModel $this->_getTemplateModel();
        
$adminTemplateModel $this->_getAdminTemplateModel();
        
$emailTemplateModel $this->_getEmailTemplateModel();

        
$title $this->get('title');

        
$templateModel->compileTemplatesThatIncludePhrase($title);
        
$adminTemplateModel->compileAdminTemplatesThatIncludePhrase($title);
        
$emailTemplateModel->compileEmailTemplatesThatIncludePhrase($title);

        if (
$this->isChanged('title') && $this->isUpdate())
        {
            
$existingTitle $this->getExisting('title');

            
$templateModel->compileTemplatesThatIncludePhrase($existingTitle);
            
$adminTemplateModel->compileAdminTemplatesThatIncludePhrase($existingTitle);
            
$emailTemplateModel->compileEmailTemplatesThatIncludePhrase($existingTitle);
        }
    }

    protected function 
_buildPhraseMap()
    {
        
$phraseModel $this->_getPhraseModel();
        
$phraseModel->buildPhraseMap($this->get('phrase_id'), $this->get('language_id'), $this->get('title'));
    }

    
/**
     * Post-delete handler.
     */
    
protected function _postDelete()
    {
        
$dataChanged $this->_deleteMappedData();
        if (
$dataChanged && $this->getOption(self::OPTION_RECOMPILE_PHRASE))
        {
            
$this->_recompilePhrase();
        }

        if (
$this->getOption(self::OPTION_RECOMPILE_TEMPLATE))
        {
            
$this->_recompileTemplatesIncludingPhrase();
        }

        
$this->_rebuildLanguageCaches();

        if (
$devDir $this->_getDevOutputDir())
        {
            
$this->_deleteExistingDevFile($devDir);
        }
    }

    protected function 
_deleteMappedData()
    {
        
$phraseModel $this->_getPhraseModel();

        
$mappedPhrases $phraseModel->getMappedPhrasesByPhraseId($this->get('phrase_id'));
        if (
$mappedPhrases)
        {
            
$myPhraseMapId 0;
            
$phraseMapIds = array();
            
$languageIds = array();
            foreach (
$mappedPhrases AS $mappedPhrase)
            {

                if (
$mappedPhrase['language_id'] == $this->get('language_id'))
                {
                    
$myPhraseMapId $mappedPhrase['phrase_map_id'];
                }

                
$phraseMapIds[] = $mappedPhrase['phrase_map_id'];
                
$languageIds[] = $mappedPhrase['language_id'];
            }

            
$phraseMapIdsQuoted $this->_db->quote($phraseMapIds);

            
$parentMappedPhrase $phraseModel->getParentMappedPhraseByTitle($this->get('title'), $this->get('language_id'));

            if (
$parentMappedPhrase)
            {
                
// point everything pointing at this phrase to the parent
                
$this->_db->update('xf_phrase_map',
                    array(
'phrase_id' => $parentMappedPhrase['phrase_id']),
                    
'phrase_map_id IN (' $phraseMapIdsQuoted ')'
                
);
                return 
true;
            }
            else
            {
                
// no parent, remove phrase - this should primarily happen when deleting a master or custom phrase
                
$this->_db->delete('xf_phrase_map''phrase_map_id IN (' $phraseMapIdsQuoted ')');
                
$this->_db->delete('xf_phrase_compiled',
                    
'language_id IN (' $this->_db->quote($languageIds) . ') AND title = ' $this->_db->quote($this->get('title'))
                );
            }
        }

        return 
false;
    }

    
/**
     * Deletes the corresponding file when a template is deleted from the database
     *
     * @param string Path to admin templates directory
     */
    
protected function _deleteExistingDevFile($dir)
    {
        
$existingTitle $this->getExisting('title');
        
$fileName $dir '/' $existingTitle '.txt';

        if (
file_exists($fileName))
        {
            if (!
is_writable($fileName))
            {
                throw new 
XenForo_Exception("Phrase development file $dir is not writable");
            }
            
unlink($fileName);

            
$this->_writeMetaDataDevFileOutput($dir$existingTitlefalse);
        }
    }

    
/**
     * Gets the language model object.
     *
     * @return XenForo_Model_Language
     */
    
protected function _getLanguageModel()
    {
        return 
$this->getModelFromCache('XenForo_Model_Language');
    }

    
/**
     * Gets the template model.
     *
     * @return XenForo_Model_Template
     */
    
protected function _getTemplateModel()
    {
        return 
$this->getModelFromCache('XenForo_Model_Template');
    }

    
/**
     * Gets the admin template model.
     *
     * @return XenForo_Model_AdminTemplate
     */
    
protected function _getAdminTemplateModel()
    {
        return 
$this->getModelFromCache('XenForo_Model_AdminTemplate');
    }

    
/**
     * @return XenForo_Model_EmailTemplate
     */
    
protected function _getEmailTemplateModel()
    {
        return 
$this->getModelFromCache('XenForo_Model_EmailTemplate');
    }
}
Онлайн: 2
Реклама