src/Document.php
<?php
namespace VKBansal\FrontMatter;
/**
* FrontMatter Document
* @package VKBansal\FrontMatter\Document
* @version 1.3.0
* @author Vivek Kumar Bansal <contact@vkbansal.me>
* @license MIT
*/
class Document implements \ArrayAccess, \IteratorAggregate
{
/**
* Constants for Document::merge() behaviour
*/
const MERGE_CONFIG = 0;
const MERGE_CONTENT_REPLACE = 1;
const MERGE_CONTENT_APPEND = 2;
const MERGE_ALL_REPLACE = 3;
const MERGE_ALL_APPEND = 4;
/**
* Constants for Document::inherit() behaviour
*/
const INHERIT_CONFIG = 5;
const INHERIT_CONTENT_REPLACE = 6;
const INHERIT_CONTENT_APPEND = 7;
const INHERIT_ALL_REPLACE = 8;
const INHERIT_ALL_APPEND = 9;
/**
* Content of the document
* @var string
*/
private $content;
/**
* Config of the document
* @var array
*/
private $config;
/**
* Document Constructor
* @param string $content content/body of the document
* @param array $config config/header of the document
*/
public function __construct($content = '', $config = [])
{
$this->content = $content;
$this->config = $config;
}
/**
* @see "http://php.net/manual/en/language.oop5.magic.php#object.tostring"
* @return string
*/
public function __toString()
{
return $this->getContent();
}
/**
* @see "http://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members"
* @return mixed
*/
public function __get($name)
{
return $this->config[$name];
}
/**
* @see "http://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members"
*/
public function __set($name, $value)
{
$this->config[$name] = $value;
}
/**
* @see "http://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members"
* @return boolean
*/
public function __isset($name)
{
return isset($this->config[$name]);
}
/**
* @see "http://php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members"
*/
public function __unset($name)
{
unset($this->config[$name]);
}
/**
* Whether or not an offset exists.
* This method is executed when using isset() or empty() on objects implementing ArrayAccess.
* @see "http://php.net/manual/en/arrayaccess.offsetexists.php"
*/
public function offsetExists($offset)
{
return isset($this->config[$offset]);
}
/**
* Returns the value at specified offset.
* This method is executed when checking if offset is empty().
* @see http://php.net/manual/en/arrayaccess.offsetget.php
*/
public function offsetGet($offset)
{
return $this->config[$offset];
}
/**
* Assigns a value to the specified offset.
* @see "http://php.net/manual/en/arrayaccess.offsetset.php"
*/
public function offsetSet($offset, $value)
{
$this->config[$offset] = $value;
}
/**
* Unsets an offset.
* @see "http://php.net/manual/en/arrayaccess.offsetunset.php"
*/
public function offsetUnset($offset)
{
unset($this->config[$offset]);
}
/**
* @see "http://php.net/manual/en/class.iteratoraggregate.php"
* @return \ArrayIterator
*/
public function getIterator()
{
return new \ArrayIterator($this->config);
}
/**
* Get header/config of the document
* @param mixed $varName Name of the property to get
* @return mixed if name is specified, returns specific property else returns full config/header
*/
public function getConfig($varName = null)
{
if ($varName !== null && array_key_exists($varName, $this->config)) {
return $this->config[$varName];
}
return $this->config;
}
/**
* Set header/config of the document
* @param mixed $property If an array is provided, header is replaced. If a string is provided, the poperty is replaced/set.
* @param mixed $value Value of the property to set
* @return $this
*/
public function setConfig($property, $value = null)
{
if (is_array($property)) {
$this->config = $property;
} elseif (is_string($property)) {
$this->config[$property] = $value;
}
return $this;
}
/**
* Get the content of the document
* @return string Content of the document
*/
public function getContent()
{
return $this->content;
}
/**
* Set the content of the document
* @param string $content Content of the document
* @return $this
*/
public function setContent($content)
{
$this->content = $content;
return $this;
}
/**
* Inherit from parent document
* @param Document $parent Document to be inherited
* @param int $mode Inherit Mode
* @return $this
*/
public function inherit(Document $parent, $mode = self::INHERIT_CONFIG)
{
if (in_array($mode, [self::INHERIT_CONFIG, self::INHERIT_ALL_APPEND, self::INHERIT_ALL_REPLACE])) {
$this->config = $this->mergeRecursive($parent->getConfig(), $this->config);
}
if (in_array($mode, [self::INHERIT_ALL_REPLACE, self::INHERIT_CONTENT_REPLACE])) {
$this->content = $parent->getContent();
}
if (in_array($mode, [self::INHERIT_ALL_APPEND, self::INHERIT_CONTENT_APPEND])) {
$this->content = $parent->getContent().$this->content;
}
return $this;
}
/**
* Merge current document with given document
* @param Document $document Document to be merged in
* @param int $mode Merge mode
* @return $this
*/
public function merge(Document $document, $mode = self::MERGE_CONFIG)
{
if (in_array($mode, [self::MERGE_CONFIG, self::MERGE_ALL_APPEND, self::MERGE_ALL_REPLACE])) {
$this->config = $this->mergeRecursive($this->config, $document->getConfig());
}
if (in_array($mode, [self::MERGE_ALL_REPLACE, self::MERGE_CONTENT_REPLACE])) {
$this->content = $document->getContent();
}
if (in_array($mode, [self::MERGE_ALL_APPEND, self::MERGE_CONTENT_APPEND])) {
$this->content .= $document->getContent();
}
return $this;
}
/**
* Recursively merges second array into first
* @param array $itemA Array to be merged in
* @param array $itemB Array to be merged
* @return array merged array
*/
private function mergeRecursive($itemA, $itemB)
{
foreach ($itemB as $key => $value) {
if (is_integer($key)) {
$itemA[] = $value;
} elseif (array_key_exists($key, $itemA) && is_array($itemA[$key]) && is_array($value)) {
$itemA[$key] = $this->mergeRecursive($itemA[$key], $value);
} else {
$itemA[$key] = $value;
}
}
return $itemA;
}
}