| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985 |
- <?php
- /*
- * This file is part of MODX Revolution.
- *
- * Copyright (c) MODX, LLC. All Rights Reserved.
- *
- * For complete copyright and license information, see the COPYRIGHT and LICENSE
- * files found in the top-level directory of this distribution.
- */
- /**
- * Represents an element of source content managed by MODX.
- *
- * These elements are defined by some type of source content that when processed
- * will provide output or some type of logical result based on mutable
- * properties.
- *
- * This class creates an instance of a modElement object. This should not be
- * called directly, but rather extended for derivative modElement classes.
- *
- * @property modMediaSource $Source The associated Media Source, if any.
- *
- * @package modx
- * @abstract Implement a derivative of this class to represent an element which
- * can be processed within the MODX framework.
- * @extends modAccessibleSimpleObject
- */
- class modElement extends modAccessibleSimpleObject {
- /**
- * The property value array for the element.
- * @var array
- */
- public $_properties= null;
- /**
- * The string representation of the element properties.
- * @var string
- */
- public $_propertyString= '';
- /**
- * The source content of the element.
- * @var string
- */
- public $_content= '';
- /**
- * The source of the element.
- * @var string
- */
- public $_source= null;
- /**
- * The output of the element.
- * @var string
- */
- public $_output= '';
- /**
- * The boolean result of the element.
- *
- * This is typically only applicable to elements that use PHP source content.
- * @var boolean
- */
- public $_result= true;
- /**
- * The tag signature of the element instance.
- * @var string
- */
- public $_tag= null;
- /**
- * The character token which helps identify the element class in tag string.
- * @var string
- */
- public $_token= '';
- /**
- * @var boolean If the element is cacheable or not.
- */
- public $_cacheable= true;
- /**
- * @var boolean Indicates if the element was processed already.
- */
- public $_processed= false;
- /**
- * @var array Optional filters that can be used during processing.
- */
- public $_filters= array('input' => null, 'output' => null);
- /**
- * @var string Path to source file location when modElement->isStatic() === true.
- */
- protected $_sourcePath= "";
- /**
- * @var string Source file name when modElement->isStatic() === true.
- */
- protected $_sourceFile= "";
- /**
- * @var array A list of invalid characters in the name of an Element.
- */
- protected $_invalidCharacters = array('!','@','#','$','%','^','&','*',
- '(',')','+','=','[',']','{','}','\'','"',';',':','\\','/','<','>','?'
- ,' ',',','`','~');
- /**
- * Provides custom handling for retrieving the properties field of an Element.
- *
- * {@inheritdoc}
- */
- public function get($k, $format= null, $formatTemplate= null) {
- $value = parent :: get($k, $format, $formatTemplate);
- if ($k === 'properties' && $this->xpdo instanceof modX && $this->xpdo->getParser() && empty($value)) {
- $value = !empty($this->properties) && is_string($this->properties)
- ? $this->xpdo->parser->parsePropertyString($this->properties)
- : null;
- }
- /* automatically translate lexicon descriptions */
- if ($k == 'properties' && !empty($value) && is_array($value)
- && is_object($this->xpdo) && $this->xpdo instanceof modX && $this->xpdo->lexicon) {
- foreach ($value as &$property) {
- if (!empty($property['lexicon'])) {
- if (strpos($property['lexicon'],':') !== false) {
- $this->xpdo->lexicon->load('en:'.$property['lexicon']);
- } else {
- $this->xpdo->lexicon->load('en:core:'.$property['lexicon']);
- }
- $this->xpdo->lexicon->load($property['lexicon']);
- }
- $property['desc_trans'] = $this->xpdo->lexicon($property['desc']);
- $property['area'] = !empty($property['area']) ? $property['area'] : '';
- $property['area_trans'] = !empty($property['area']) ? $this->xpdo->lexicon($property['area']) : '';
- if (!empty($property['options'])) {
- foreach ($property['options'] as &$option) {
- if (empty($option['text']) && !empty($option['name'])) {
- $option['text'] = $option['name'];
- unset($option['name']);
- }
- if (empty($option['value']) && !empty($option[0])) {
- $option['value'] = $option[0];
- unset($option[0]);
- }
- $option['name'] = $this->xpdo->lexicon($option['text']);
- }
- }
- }
- }
- return $value;
- }
- /**
- * Overridden to handle changes to content managed in an external file.
- *
- * {@inheritdoc}
- */
- public function save($cacheFlag = null) {
- if (!$this->getOption(xPDO::OPT_SETUP)) {
- if ($this->staticSourceChanged()) {
- $staticContent = $this->getFileContent();
- if ($staticContent !== $this->get('content')) {
- if ($this->isStaticSourceMutable() && $staticContent === '') {
- $this->setDirty('content');
- } else {
- $this->setContent($staticContent);
- }
- }
- unset($staticContent);
- }
- $staticContentChanged = $this->staticContentChanged();
- if ($staticContentChanged && !$this->isStaticSourceMutable()) {
- $this->setContent($this->getFileContent());
- $staticContentChanged = false;
- }
- /* If element is empty, set to true in order to create an empty static file. */
- $content = $this->get('content');
- if (empty($content) && $this->isStatic()) {
- $staticContentChanged = true;
- }
- }
- /* Set oldPath before saving object. */
- $oldPath = $this->getOldStaticFilePath();
- $saved = parent::save($cacheFlag);
- if (!$this->getOption(xPDO::OPT_SETUP)) {
- if ($saved && $staticContentChanged) {
- $saved = $this->setFileContent($this->get('content'));
- }
- }
- /* Removing old static file when succesfull saved and oldPath has been set. */
- if ($saved && $oldPath && $this->isStaticFilesAutomated()) {
- if (@unlink($oldPath)) {
- $pathinfo = pathinfo($oldPath);
- $this->cleanupStaticFileDirectories($pathinfo['dirname']);
- }
- }
- return $saved;
- }
- /**
- * Determine if static files should be automated for current element class.
- *
- * @return bool
- */
- protected function isStaticFilesAutomated()
- {
- $elements = array(
- 'modTemplate' => 'templates',
- 'modTemplateVar' => 'tvs',
- 'modChunk' => 'chunks',
- 'modSnippet' => 'snippets',
- 'modPlugin' => 'plugins'
- );
- if (!array_key_exists($this->_class, $elements)) {
- return false;
- }
- return (bool) $this->xpdo->getOption('static_elements_automate_' . $elements[$this->_class], null, false);
- }
- /**
- * Constructs a valid tag representation of the element.
- *
- * @return string A tag representation of the element.
- */
- public function getTag() {
- if (empty($this->_tag)) {
- $propTemp = array();
- if (empty($this->_propertyString) && !empty($this->_properties)) {
- foreach ($this->_properties as $key => $value) {
- if (is_scalar($value)) {
- $propTemp[] = trim($key) . '=`' . $value . '`';
- }
- else {
- $propTemp[] = trim($key) . '=`' . md5(uniqid(rand(), true)) . '`';
- }
- }
- if (!empty($propTemp)) {
- $this->_propertyString = '?' . implode('&', $propTemp);
- }
- }
- $tag = '[[';
- $tag.= $this->getToken();
- $tag.= $this->get('name');
- if (!empty($this->_propertyString)) {
- $tag.= $this->_propertyString;
- }
- $tag.= ']]';
- $this->setTag($tag);
- }
- if (empty($this->_tag)) {
- $this->xpdo->log(xPDO::LOG_LEVEL_ERROR, 'Instance of ' . get_class($this) . ' produced an empty tag!');
- }
- return $this->_tag;
- }
- /**
- * Accessor method for the token class var.
- *
- * @return string The token for this element tag.
- */
- public function getToken() {
- return $this->_token;
- }
- /**
- * Setter method for the token class var.
- *
- * @param string $token The token to use for this element tag.
- */
- public function setToken($token) {
- $this->_token = $token;
- }
- /**
- * Setter method for the tag class var.
- *
- * @param string $tag The tag to use for this element.
- */
- public function setTag($tag) {
- $this->_tag = $tag;
- }
- /**
- * Process the element source content to produce a result.
- *
- * @abstract Implement this to define behavior for a MODX content element.
- * @param array|string $properties A set of configuration properties for the
- * element.
- * @param string $content Optional content to use in place of any persistent
- * content associated with the element.
- * @return mixed The result of processing.
- */
- public function process($properties= null, $content= null) {
- $this->xpdo->getParser();
- $this->xpdo->parser->setProcessingElement(true);
- $this->getProperties($properties);
- $this->getTag();
- if ($this->xpdo->getDebug() === true) $this->xpdo->log(xPDO::LOG_LEVEL_DEBUG, "Processing Element: " . $this->get('name') . ($this->_tag ? "\nTag: {$this->_tag}" : "\n") . "\nProperties: " . print_r($this->_properties, true));
- if ($this->isCacheable() && isset ($this->xpdo->elementCache[$this->_tag])) {
- $this->_output = $this->xpdo->elementCache[$this->_tag];
- $this->_processed = true;
- } else {
- $this->filterInput();
- $this->getContent(is_string($content) ? array('content' => $content) : array());
- }
- return $this->_result;
- }
- /**
- * Cache the current output of this element instance by tag signature.
- */
- public function cache() {
- if ($this->isCacheable()) {
- $this->xpdo->elementCache[$this->_tag]= $this->_output;
- }
- }
- /**
- * Get an input filter instance configured for this Element.
- *
- * @return modInputFilter|null An input filter instance (or null if one cannot be loaded).
- */
- public function & getInputFilter() {
- if (!isset ($this->_filters['input']) || !($this->_filters['input'] instanceof modInputFilter)) {
- if (!$inputFilterClass= $this->get('input_filter')) {
- $inputFilterClass = $this->xpdo->getOption('input_filter',null,'filters.modInputFilter');
- }
- if ($filterClass= $this->xpdo->loadClass($inputFilterClass, '', false, true)) {
- if ($filter= new $filterClass($this->xpdo)) {
- $this->_filters['input']= $filter;
- }
- }
- }
- return $this->_filters['input'];
- }
- /**
- * Get an output filter instance configured for this Element.
- *
- * @return modOutputFilter|null An output filter instance (or null if one cannot be loaded).
- */
- public function & getOutputFilter() {
- if (!isset ($this->_filters['output']) || !($this->_filters['output'] instanceof modOutputFilter)) {
- if (!$outputFilterClass= $this->get('output_filter')) {
- $outputFilterClass = $this->xpdo->getOption('output_filter',null,'filters.modOutputFilter');
- }
- if ($filterClass= $this->xpdo->loadClass($outputFilterClass, '', false, true)) {
- if ($filter= new $filterClass($this->xpdo)) {
- $this->_filters['output']= $filter;
- }
- }
- }
- return $this->_filters['output'];
- }
- /**
- * Apply an input filter to an element.
- *
- * This is called by default in {@link modElement::process()} after the
- * element properties have been parsed.
- */
- public function filterInput() {
- $filter = $this->getInputFilter();
- if ($filter !== null && $filter instanceof modInputFilter) {
- $filter->filter($this);
- }
- }
- /**
- * Apply an output filter to an element.
- *
- * Call this method in your {modElement::process()} implementation when it
- * is appropriate, typically once all processing has been completed, but
- * before any caching takes place.
- */
- public function filterOutput() {
- $filter = $this->getOutputFilter();
- if ($filter !== null && $filter instanceof modOutputFilter) {
- $filter->filter($this);
- }
- }
- /**
- * Loads the access control policies applicable to this element.
- *
- * {@inheritdoc}
- */
- public function findPolicy($context = '') {
- $policy = array();
- $enabled = true;
- $context = !empty($context) ? $context : $this->xpdo->context->get('key');
- if ($context === $this->xpdo->context->get('key')) {
- $enabled = (boolean) $this->xpdo->getOption('access_category_enabled', null, true);
- } elseif ($this->xpdo->getContext($context)) {
- $enabled = (boolean) $this->xpdo->contexts[$context]->getOption('access_category_enabled', true);
- }
- if ($enabled) {
- if (empty($this->_policies) || !isset($this->_policies[$context])) {
- $accessTable = $this->xpdo->getTableName('modAccessCategory');
- $policyTable = $this->xpdo->getTableName('modAccessPolicy');
- $categoryClosureTable = $this->xpdo->getTableName('modCategoryClosure');
- $sql = "SELECT Acl.target, Acl.principal, Acl.authority, Acl.policy, Policy.data FROM {$accessTable} Acl " .
- "LEFT JOIN {$policyTable} Policy ON Policy.id = Acl.policy " .
- "JOIN {$categoryClosureTable} CategoryClosure ON CategoryClosure.descendant = :category " .
- "AND Acl.principal_class = 'modUserGroup' " .
- "AND CategoryClosure.ancestor = Acl.target " .
- "AND (Acl.context_key = :context OR Acl.context_key IS NULL OR Acl.context_key = '') " .
- "ORDER BY CategoryClosure.depth DESC, target, principal, authority ASC";
- $bindings = array(
- ':category' => $this->get('category'),
- ':context' => $context,
- );
- $query = new xPDOCriteria($this->xpdo, $sql, $bindings);
- if ($query->stmt && $query->stmt->execute()) {
- while ($row = $query->stmt->fetch(PDO::FETCH_ASSOC)) {
- $policy['modAccessCategory'][$row['target']][] = array(
- 'principal' => $row['principal'],
- 'authority' => $row['authority'],
- 'policy' => $row['data'] ? $this->xpdo->fromJSON($row['data'], true) : array(),
- );
- }
- }
- $this->_policies[$context] = $policy;
- } else {
- $policy = $this->_policies[$context];
- }
- }
- return $policy;
- }
- /**
- * Gets the raw, unprocessed source content for this element.
- *
- * @param array $options An array of options implementations can use to
- * accept language, revision identifiers, or other information to alter the
- * behavior of the method.
- * @return string The raw source content for the element.
- */
- public function getContent(array $options = array()) {
- if (!is_string($this->_content) || $this->_content === '') {
- if (isset($options['content'])) {
- $this->_content = $options['content'];
- } elseif ($this->isStatic()) {
- $this->_content = $this->getFileContent($options);
- if ($this->_content !== $this->_fields['content']) {
- $this->setContent($this->_content);
- if (!$this->isNew()) {
- $this->save();
- }
- }
- } else {
- $this->_content = $this->get('content');
- }
- }
- return $this->_content;
- }
- /**
- * Set the raw source content for this element.
- *
- * @param mixed $content The source content; implementations can decide if
- * it can only be a string, or some other source from which to retrieve it.
- * @param array $options An array of options implementations can use to
- * accept language, revision identifiers, or other information to alter the
- * behavior of the method.
- * @return boolean True indicates the content was set.
- */
- public function setContent($content, array $options = array()) {
- return $this->set('content', $content);
- }
- /**
- * Get the absolute path to the static source file for this instance.
- *
- * @param array $options An array of options.
- * @return string|boolean The absolute path to the static source file or false if not static.
- */
- public function getSourceFile(array $options = array()) {
- if ($this->isStatic() && (empty($this->_sourceFile) || $this->getOption('recalculate_source_file', $options, $this->staticSourceChanged()))) {
- $filename = $this->get('static_file');
- if (!empty($filename)) {
- $array = array();
- if ($this->xpdo->getParser() && $this->xpdo->parser->collectElementTags($filename, $array)) {
- $this->xpdo->parser->processElementTags('', $filename);
- }
- }
- if ($this->get('source') > 0) {
- /** @var modMediaSource $source */
- $source = $this->getOne('Source');
- if ($source && $source->get('is_stream')) {
- $source->initialize();
- $filename = $source->getBasePath().$filename;
- }
- }
- if (!file_exists($filename) && $this->get('source') < 1) {
- $this->getSourcePath($options);
- $this->_sourceFile= $this->_sourcePath . $filename;
- } else {
- $this->_sourceFile= $filename;
- }
- }
- return $this->isStatic() ? $this->_sourceFile : false;
- }
- /**
- * Get the absolute path location the source file is located relative to.
- *
- * @param array $options An array of options.
- * @return string The absolute path the sourceFile is relative to.
- */
- public function getSourcePath(array $options = array()) {
- $array = array();
- $this->_sourcePath= $this->xpdo->getOption('element_static_path', $options, $this->xpdo->getOption('components_path', $options, MODX_CORE_PATH . 'components/'));
- if ($this->xpdo->getParser() && $this->xpdo->parser->collectElementTags($this->_sourcePath, $array)) {
- $this->xpdo->parser->processElementTags('', $this->_sourcePath);
- }
- return $this->_sourcePath;
- }
- /**
- * Get the content stored in an external file for this instance.
- *
- * @param array $options An array of options.
- * @return bool|string The content or false if the content could not be retrieved.
- */
- public function getFileContent(array $options = array()) {
- $content = "";
- if ($this->isStatic()) {
- $sourceFile = $this->getSourceFile($options);
- if ($sourceFile && file_exists($sourceFile)) {
- $content = file_get_contents($sourceFile);
- }
- }
- return $content;
- }
- /**
- * Set external file content from this instance.
- *
- * @param string $content The content to set.
- * @param array $options An array of options.
- * @return bool|int The number of bytes written to file or false on failure.
- */
- public function setFileContent($content, array $options = array()) {
- $set = false;
- if ($this->isStatic()) {
- $sourceFile = $this->getSourceFile($options);
- if ($sourceFile) {
- $set = $this->xpdo->cacheManager->writeFile($sourceFile, $content);
- }
- }
- return $set;
- }
- /**
- * Get the properties for this element instance for processing.
- *
- * @param array|string $properties An array or string of properties to
- * apply.
- * @return array A simple array of properties ready to use for processing.
- */
- public function getProperties($properties = null) {
- $this->xpdo->getParser();
- $this->_properties= $this->xpdo->parser->parseProperties($this->get('properties'));
- $set= $this->getPropertySet();
- if (!empty($set)) {
- $this->_properties= array_merge($this->_properties, $set);
- }
- if ($this->get('property_preprocess')) {
- foreach ($this->_properties as $pKey => $pValue) {
- if ($this->xpdo->parser->processElementTags('', $pValue, $this->xpdo->parser->isProcessingUncacheable())) {
- $this->_properties[$pKey]= $pValue;
- }
- }
- }
- if (!empty($properties)) {
- $this->_properties= array_merge($this->_properties, $this->xpdo->parser->parseProperties($properties));
- }
- return $this->_properties;
- }
- /**
- * Gets a named property set related to this element instance.
- *
- * If a setName parameter is not provided, this function will attempt to
- * extract a setName from the element name using the @ symbol to delimit the
- * name of the property set.
- *
- * Here is an example of an element tag using the @ modifier to specify a
- * property set name:
- * [[ElementName@PropertySetName:FilterCommand=`FilterModifier`?
- * &PropertyKey1=`PropertyValue1`
- * &PropertyKey2=`PropertyValue2`
- * ]]
- *
- * @access public
- * @param string|null $setName An explicit property set name to search for.
- * @return array|null An array of properties or null if no set is found.
- */
- public function getPropertySet($setName = null) {
- $propertySet= null;
- $name = $this->get('name');
- if (strpos($name, '@') !== false) {
- $psName= '';
- $split= xPDO :: escSplit('@', $name);
- if ($split && isset($split[1])) {
- $name= $split[0];
- $psName= $split[1];
- $filters= xPDO :: escSplit(':', $setName);
- if ($filters && isset($filters[1]) && !empty($filters[1])) {
- $psName= $filters[0];
- $name.= ':' . $filters[1];
- }
- $this->set('name', $name);
- }
- if (!empty($psName)) {
- $psObj= $this->xpdo->getObjectGraph('modPropertySet', '{"Elements":{}}', array(
- 'Elements.element' => $this->id,
- 'Elements.element_class' => $this->_class,
- 'modPropertySet.name' => $psName
- ));
- if ($psObj) {
- $propertySet= $this->xpdo->parser->parseProperties($psObj->get('properties'));
- }
- }
- }
- if (!empty($setName)) {
- $propertySetObj= $this->xpdo->getObjectGraph('modPropertySet', '{"Elements":{}}', array(
- 'Elements.element' => $this->id,
- 'Elements.element_class' => $this->_class,
- 'modPropertySet.name' => $setName
- ));
- if ($propertySetObj) {
- if (is_array($propertySet)) {
- $propertySet= array_merge($propertySet, $this->xpdo->parser->parseProperties($propertySetObj->get('properties')));
- } else {
- $propertySet= $this->xpdo->parser->parseProperties($propertySetObj->get('properties'));
- }
- }
- }
- return $propertySet;
- }
- /**
- * Set default properties for this element instance.
- *
- * @access public
- * @param array|string $properties A property array or property string.
- * @param boolean $merge Indicates if properties should be merged with
- * existing ones.
- * @return boolean true if the properties are set.
- */
- public function setProperties($properties, $merge = false) {
- $set = false;
- $propertiesArray = array();
- if (is_string($properties)) {
- $properties = $this->xpdo->parser->parsePropertyString($properties);
- }
- if (is_array($properties)) {
- foreach ($properties as $propKey => $property) {
- if (is_array($property) && isset($property[5])) {
- $key = $property[0];
- $propertyArray = array(
- 'name' => $property[0],
- 'desc' => $property[1],
- 'type' => $property[2],
- 'options' => $property[3],
- 'value' => $property[4],
- 'lexicon' => !empty($property[5]) ? $property[5] : null,
- 'area' => !empty($property[6]) ? $property[6] : '',
- );
- } elseif (is_array($property) && isset($property['value'])) {
- $key = $property['name'];
- $propertyArray = array(
- 'name' => $property['name'],
- 'desc' => isset($property['description']) ? $property['description'] : (isset($property['desc']) ? $property['desc'] : ''),
- 'type' => isset($property['xtype']) ? $property['xtype'] : (isset($property['type']) ? $property['type'] : 'textfield'),
- 'options' => isset($property['options']) ? $property['options'] : array(),
- 'value' => $property['value'],
- 'lexicon' => !empty($property['lexicon']) ? $property['lexicon'] : null,
- 'area' => !empty($property['area']) ? $property['area'] : '',
- );
- } else {
- $key = $propKey;
- $propertyArray = array(
- 'name' => $propKey,
- 'desc' => '',
- 'type' => 'textfield',
- 'options' => array(),
- 'value' => $property,
- 'lexicon' => null,
- 'area' => '',
- );
- }
- if (!empty($propertyArray['options'])) {
- foreach ($propertyArray['options'] as $optionKey => &$option) {
- if (empty($option['text']) && !empty($option['name'])) $option['text'] = $option['name'];
- unset($option['menu'],$option['name']);
- }
- }
- if ($propertyArray['type'] == 'combo-boolean' && is_numeric($propertyArray['value'])) {
- $propertyArray['value'] = (boolean)$propertyArray['value'];
- }
- $propertiesArray[$key] = $propertyArray;
- }
- if ($merge && !empty($propertiesArray)) {
- $existing = $this->get('properties');
- if (is_array($existing) && !empty($existing)) {
- $propertiesArray = array_merge($existing, $propertiesArray);
- }
- }
- $set = $this->set('properties', $propertiesArray);
- }
- return $set;
- }
- /**
- * Add a property set to this element, making it available for use.
- *
- * @access public
- * @param string|modPropertySet $propertySet A modPropertySet object or the
- * name of a modPropertySet object to create a relationship with.
- * @return boolean True if a relationship was created or already exists.
- */
- public function addPropertySet($propertySet) {
- $added= false;
- if (!empty($propertySet)) {
- if (is_string($propertySet)) {
- $propertySet = $this->xpdo->getObject('modPropertySet', array('name' => $propertySet));
- }
- if (is_object($propertySet) && $propertySet instanceof modPropertySet) {
- if (!$this->isNew() && !$propertySet->isNew() && $this->xpdo->getCount('modElementPropertySet', array('element' => $this->get('id'), 'element_class' => $this->_class, 'property_set' => $propertySet->get('id')))) {
- $added = true;
- } else {
- if ($propertySet->isNew()) $propertySet->save();
- /** @var modElementPropertySet $link */
- $link= $this->xpdo->newObject('modElementPropertySet');
- $link->set('element', $this->get('id'));
- $link->set('element_class', $this->_class);
- $link->set('property_set', $propertySet->get('id'));
- $added = $link->save();
- }
- }
- }
- return $added;
- }
- /**
- * Remove a property set from this element, making it unavailable for use.
- *
- * @access public
- * @param string|modPropertySet $propertySet A modPropertySet object or the
- * name of a modPropertySet object to dissociate from.
- * @return boolean True if a relationship was destroyed.
- */
- public function removePropertySet($propertySet) {
- $removed = false;
- if (!empty($propertySet)) {
- if (is_string($propertySet)) {
- $propertySet = $this->xpdo->getObject('modPropertySet', array('name' => $propertySet));
- }
- if (is_object($propertySet) && $propertySet instanceof modPropertySet) {
- $removed = $this->xpdo->removeObject('modElementPropertySet', array('element' => $this->get('id'), 'element_class' => $this->_class, 'property_set' => $propertySet->get('id')));
- }
- }
- return $removed;
- }
- /**
- * Indicates if the element is cacheable.
- *
- * @access public
- * @return boolean True if the element can be stored to or retrieved from
- * the element cache.
- */
- public function isCacheable() {
- return $this->_cacheable;
- }
- /**
- * Sets the runtime cacheability of the element.
- *
- * @access public
- * @param boolean $cacheable Indicates the value to set for cacheability of
- * this element.
- */
- public function setCacheable($cacheable = true) {
- $this->_cacheable = (boolean) $cacheable;
- }
- /**
- * Get the Source for this Element
- *
- * @param string $contextKey
- * @param boolean $fallbackToDefault
- * @return modMediaSource|null
- */
- public function getSource($contextKey = '',$fallbackToDefault = true) {
- if (empty($contextKey)) $contextKey = $this->xpdo->context->get('key');
- $source = $this->_source;
- if (empty($source)) {
- $c = $this->xpdo->newQuery('sources.modMediaSource');
- $c->innerJoin('sources.modMediaSourceElement','SourceElement');
- $c->where(array(
- 'SourceElement.object' => $this->get('id'),
- 'SourceElement.object_class' => $this->_class,
- 'SourceElement.context_key' => $contextKey,
- ));
- $source = $this->xpdo->getObject('sources.modMediaSource',$c);
- if (!$source && $fallbackToDefault) {
- $source = modMediaSource::getDefaultSource($this->xpdo);
- }
- $this->setSource($source);
- }
- return $source;
- }
- /**
- * Setter method for the source class var.
- *
- * @param string $source The source to use for this element.
- */
- public function setSource($source) {
- $this->_source = $source;
- }
- /**
- * Get the stored sourceCache for a context
- *
- * @param string $contextKey
- * @param array $options
- * @return array
- */
- public function getSourceCache($contextKey = '',array $options = array()) {
- /** @var modCacheManager $cacheManager */
- $cacheManager = $this->xpdo->getCacheManager();
- if (!$cacheManager || !($cacheManager instanceof modCacheManager)) return array();
- if (empty($contextKey)) $contextKey = $this->xpdo->context->get('key');
- return $cacheManager->getElementMediaSourceCache($this,$contextKey,$options);
- }
- /**
- * Indicates if the instance has content in an external file.
- *
- * @return boolean True if the instance has content stored in an external file.
- */
- public function isStatic() {
- return $this->get('static');
- }
- /**
- * Indicates if the content has changed and the Element has a mutable static source.
- *
- * @return boolean
- */
- public function staticContentChanged() {
- return $this->isStatic() && $this->isDirty('content');
- }
- /**
- * Check if directories are empty after moving a static element and remove empty directories.
- *
- * @param $dirname
- */
- public function cleanupStaticFileDirectories($dirname) {
- $contents = array_diff(scandir($dirname), array('..', '.', '.DS_Store'));
- @unlink($dirname .'/.DS_Store');
- if (count($contents) === 0) {
- if (is_dir($dirname)) {
- if (rmdir($dirname)) {
- /* Check if parent directory is also empty. */
- $this->cleanupStaticFileDirectories(dirname($dirname));
- }
- }
- }
- }
- /**
- * Returns static file path if the file path or source has changed.
- */
- public function getOldStaticFilePath() {
- $oldFilePath = '';
- $sourceId = 0;
- $result = $this->xpdo->getObject($this->_class, array('id' => $this->_fields['id']));
- if ($result) {
- $staticFilePath = $result->get('static_file');
- $sourceId = $result->get('source');
- if ($staticFilePath !== $this->_fields['static_file'] || $sourceId !== $this->_fields['source']) {
- $oldFilePath = $staticFilePath;
- }
- }
- if (!empty($oldFilePath)) {
- if ($sourceId > 0) {
- /** @var modMediaSource $source */
- $source = $this->xpdo->getObject('sources.modFileMediaSource', array('id' => $sourceId));
- if ($source && $source->get('is_stream')) {
- $source->initialize();
- $oldFilePath = $source->getBasePath() . $oldFilePath;
- }
- }
- if (!file_exists($oldFilePath) && $this->get('source') < 1) {
- $this->getSourcePath();
- $oldFilePath = $this->_sourcePath . $oldFilePath;
- }
- }
- return $oldFilePath;
- }
- /**
- * Indicates if the static source has changed.
- *
- * @return boolean
- */
- public function staticSourceChanged() {
- return $this->isStatic() && ($this->isDirty('static') || $this->isDirty('static_file') || $this->isDirty('source'));
- }
- /**
- * Return if the static source is mutable.
- *
- * @return boolean True if the source file is mutable.
- */
- public function isStaticSourceMutable() {
- $isMutable = false;
- $sourceFile = $this->getSourceFile();
- if ($sourceFile) {
- if (file_exists($sourceFile)) {
- $isMutable = is_writable($sourceFile) && !is_dir($sourceFile);
- } else {
- $sourceDir = dirname($sourceFile);
- $i = 100;
- while (!empty($sourceDir)) {
- if (file_exists($sourceDir) && is_dir($sourceDir)) {
- $isMutable = is_writable($sourceDir);
- if ($isMutable) break;
- }
- if ($sourceDir != '/') {
- $sourceDir = dirname($sourceDir);
- } else {
- break;
- }
- $i--;
- if ($i < 0) break;
- }
- }
- }
- return $isMutable;
- }
- /**
- * Ensure the static source cannot browse the protected configuration directory
- *
- * @return boolean True if is a valid source path
- */
- public function isStaticSourceValidPath() {
- $isValid = true;
- $sourceFile = $this->getSourceFile();
- if ($sourceFile) {
- $sourceDirectory = rtrim(dirname($sourceFile),'/');
- $configDirectory = rtrim($this->xpdo->getOption('core_path',null,MODX_CORE_PATH).'config/','/');
- if ($sourceDirectory == $configDirectory) {
- $isValid = false;
- }
- }
- return $isValid;
- }
- }
|