Вход Регистрация
Файл: concrete5.7.5.6/concrete/vendor/anahkiasen/html-object/src/HtmlObject/Traits/TreeObject.php
Строк: 349
<?php
namespace HtmlObjectTraits;

use 
Closure;
use 
HtmlObjectElement;
use 
HtmlObjectText;

/**
 * An abstract class to create and manage trees of objects
 */
abstract class TreeObject
{
  
/**
   * Parent of the object
   *
   * @var TreeObject
   */
  
protected $parent;

  
/**
   * The name of the child for the parent
   *
   * @var string
   */
  
public $parentIndex;

  
/**
   * Children of the object
   *
   * @var array
   */
  
protected $children = array();

  
// Defaults
  ////////////////////////////////////////////////////////////////////

  /**
   * Default element for nested children
   *
   * @var string
   */
  
protected $defaultChild;

  
////////////////////////////////////////////////////////////////////
  /////////////////////////////// PARENT /////////////////////////////
  ////////////////////////////////////////////////////////////////////

  /**
   * Get the Element's parent
   *
   * @param integer $levels The number of levels to go back up
   *
   * @return Element
   */
  
public function getParent($levels null)
  {
    if (!
$levels) return $this->parent;

    
$subject $this;
    for (
$i 0$i <= $levels$i++) {
      
$subject $subject->getParent();
    }

    return 
$subject;
  }

  
/**
   * Set the parent of the element
   *
   * @param TreeObject $parent
   *
   * @return TreeObject
   */
  
public function setParent(TreeObject $parent)
  {
    
$this->parent $parent;

    return 
$this;
  }

  
/**
   * Check if an object has a parent
   *
   * @return boolean
   */
  
public function hasParent()
  {
    return (bool) 
$this->parent;
  }

  
////////////////////////////////////////////////////////////////////
  ////////////////////////////// CHILDREN ////////////////////////////
  ////////////////////////////////////////////////////////////////////

  // Get
  ////////////////////////////////////////////////////////////////////

  /**
   * Get a specific child of the element
   *
   * @param string $name The Element's name
   *
   * @return Element
   */
  
public function getChild($name)
  {
    
// Direct fetching
    
$child Helpers::arrayGet($this->getChildren(), $name);
    if (
$child) {
      return 
$child;
    }

    
// Dot notation
    
$children explode('.'$name);
    if (
sizeof($children) == 1) {
      return 
Helpers::arrayGet($this->getChildren(), $children[0]);
    }

    
// Recursive fetching
    
$subject $this;
    foreach (
$children as $child) {
      if (!
$subject) {
        return;
      }

      
$subject $subject->getChild($child);
    }

    return 
$subject;
  }

  
/**
   * Check if an Element has a Child
   *
   * @param string $name The child's name
   *
   * @return boolean
   */
  
public function hasChild($name)
  {
    return (bool) 
$this->getChild($name);
  }

  
/**
   * Get all children
   *
   * @return array
   */
  
public function getChildren()
  {
    return 
$this->children;
  }

  
/**
   * Check if the object has children
   *
   * @return boolean
   */
  
public function hasChildren()
  {
    return !
is_null($this->children) and !empty($this->children);
  }

  
/**
   * Check if a given element is after another sibling
   *
   * @param integer|string $sibling The sibling
   *
   * @return boolean
   */
  
public function isAfter($sibling)
  {
    
$children array_keys($this->getParent()->getChildren());
    
$child    array_search($this->parentIndex$children);
    
$sibling  array_search($sibling$children);

    return 
$child $sibling;
  }

  
// Set
  ////////////////////////////////////////////////////////////////////

  /**
   * Nests an object withing the current object
   *
   * @param Tag|string $element    An element name or an Tag
   * @param string     $value      The Tag's alias or the element's content
   * @param array      $attributes
   *
   * @return Tag
   */
  
public function nest($element$value null$attributes = array())
  {
    
// Alias for nestChildren
    
if (is_array($element)) {
      return 
$this->nestChildren($element);
    }

    
// Transform the element
    
if (!($element instanceof TreeObject)) {
      
$element $this->createTagFromString($element$value$attributes);
    }

    
// If we seek to nest into a child, get the child and nest
    
if ($this->hasChild($value)) {
      
$element $this->getChild($value)->nest($element);
    }

    return 
$this->setChild($element$value);
  }

  
/**
   * Nest an array of objects/values
   *
   * @param array $children
   */
  
public function nestChildren($children)
  {
    if (!
is_array($children)) {
      return 
$this;
    }

    foreach (
$children as $element => $value) {
      if (
is_numeric($element)) {
        if(
$value instanceof TreeObject$this->setChild($value);
        elseif(
$this->defaultChild$this->nest($this->defaultChild$value);
      } else {
        if(
$value instanceof TreeObject$this->setChild($value$element);
        else 
$this->nest($element$value);
      }
    }

    return 
$this;
  }

  
/**
   * Add an object to the current object
   *
   * @param string|TreeObject  $child The child
   * @param string             $name  Its name
   * @param boolean            $flat
   *
   * @return TreeObject
   */
  
public function setChild($child$name null$flat false)
  {
    if (!
$name) {
      
$name sizeof($this->children);
    }

    
// Get subject of the setChild
    
if (!$flat) {
      
$subject explode('.'$name);
      
$name    array_pop($subject);
      
$subject implode('.'$subject);
      
$subject $subject $this->getChild($subject) : $this;
    } else {
      
$subject $this;
    }

    return 
$this->insertChildAtPosition($child$name$subject);
  }

  
// Prepend or append
  ////////////////////////////////////////////////////////////////////

  /**
   * Append to an element
   *
   * @param Element $child
   * @param string  $name
   * @param string  $to
   *
   * @return self
   */
  
public function appendChild($child$name null$to null)
  {
    return 
$this->insertChildAtPosition($child$namenull$to);
  }

  
/**
   * Prepend to an element
   *
   * @param Element $child
   * @param string  $name
   * @param string  $to
   *
   * @return self
   */
  
public function prependChild($child$name null$to 0)
  {
    return 
$this->insertChildAtPosition($child$namenull$totrue);
  }

  
/**
   * Prepend or append to self/child
   *
   * @param Closure  $onSubject
   * @param Element  $child
   * @param string   $name
   * @param string   $to
   * @param boolean  $before
   *
   * @return self
   */
  
protected function insertChildAtPosition($child$name null$subject null$position null$before false)
  {
    
// Get default child name
    
$subject $subject ?: $this;
    
$name    $name ?: sizeof($this->children);

    
// Bind parent to child
    
if ($child instanceof TreeObject) {
      
$child->setParent($subject);
    }

    
// Add object to children
    
$child->parentIndex $name;

    
// If the position is a child name, get its index
    
$before   $before 1;
    
$position is_null($position) ? sizeof($subject->children) : $position;
    if (
is_string($position)) {
      
$position array_search($positionarray_keys($subject->children));
    }

    
// Slice and recompose children
    
$subject->children =
      
array_slice($subject->children0$position $beforetrue) +
      array(
$name => $child) +
      
array_slice($subject->children$positionsizeof($subject->children), true);

    return 
$this;
  }

  
////////////////////////////////////////////////////////////////////
  ////////////////////////////// HELPERS /////////////////////////////
  ////////////////////////////////////////////////////////////////////

  /**
   * Creates an Element or a TextNode from an element/value combo
   *
   * @param string $element    The element/string
   * @param string $value      The element's content
   * @param array  $attributes
   *
   * @return TreeObject
   */
  
protected function createTagFromString($element$value null$attributes = array())
  {
    
// If it's an element/value, create the element
    
if (strpos($element'<') === false and !$this->hasChild($value) and Helpers::isKnownTag($element)) {
      return new 
Element($element$value$attributes);
    }

    
// Else create a text element
    
if ($this->hasChild($value) or !$value) {
      return new 
Text($element);
    }

    return new 
Text($value);
  }
}
Онлайн: 1
Реклама