PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Zend/Feed/Element.php

https://bitbucket.org/acidel/buykoala
PHP | 437 lines | 190 code | 50 blank | 197 comment | 36 complexity | a8e0d150ac93abc0d2ce9dd5a731230f MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Feed
  17. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  18. * @license http://framework.zend.com/license/new-bsd New BSD License
  19. * @version $Id: Element.php 20104 2010-01-06 21:26:01Z matthew $
  20. */
  21. /**
  22. * Wraps a DOMElement allowing for SimpleXML-like access to attributes.
  23. *
  24. * @category Zend
  25. * @package Zend_Feed
  26. * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  27. * @license http://framework.zend.com/license/new-bsd New BSD License
  28. */
  29. class Zend_Feed_Element implements ArrayAccess
  30. {
  31. /**
  32. * @var DOMElement
  33. */
  34. protected $_element;
  35. /**
  36. * @var string Character encoding to utilize
  37. */
  38. protected $_encoding = 'UTF-8';
  39. /**
  40. * @var Zend_Feed_Element
  41. */
  42. protected $_parentElement;
  43. /**
  44. * @var boolean
  45. */
  46. protected $_appended = true;
  47. /**
  48. * Zend_Feed_Element constructor.
  49. *
  50. * @param DOMElement $element The DOM element we're encapsulating.
  51. * @return void
  52. */
  53. public function __construct($element = null)
  54. {
  55. $this->_element = $element;
  56. }
  57. /**
  58. * Get a DOM representation of the element
  59. *
  60. * Returns the underlying DOM object, which can then be
  61. * manipulated with full DOM methods.
  62. *
  63. * @return DOMDocument
  64. */
  65. public function getDOM()
  66. {
  67. return $this->_element;
  68. }
  69. /**
  70. * Update the object from a DOM element
  71. *
  72. * Take a DOMElement object, which may be originally from a call
  73. * to getDOM() or may be custom created, and use it as the
  74. * DOM tree for this Zend_Feed_Element.
  75. *
  76. * @param DOMElement $element
  77. * @return void
  78. */
  79. public function setDOM(DOMElement $element)
  80. {
  81. $this->_element = $this->_element->ownerDocument->importNode($element, true);
  82. }
  83. /**
  84. * Set the parent element of this object to another
  85. * Zend_Feed_Element.
  86. *
  87. * @param Zend_Feed_Element $element
  88. * @return void
  89. */
  90. public function setParent(Zend_Feed_Element $element)
  91. {
  92. $this->_parentElement = $element;
  93. $this->_appended = false;
  94. }
  95. /**
  96. * Appends this element to its parent if necessary.
  97. *
  98. * @return void
  99. */
  100. protected function ensureAppended()
  101. {
  102. if (!$this->_appended) {
  103. $this->_parentElement->getDOM()->appendChild($this->_element);
  104. $this->_appended = true;
  105. $this->_parentElement->ensureAppended();
  106. }
  107. }
  108. /**
  109. * Get an XML string representation of this element
  110. *
  111. * Returns a string of this element's XML, including the XML
  112. * prologue.
  113. *
  114. * @return string
  115. */
  116. public function saveXml()
  117. {
  118. // Return a complete document including XML prologue.
  119. $doc = new DOMDocument($this->_element->ownerDocument->version,
  120. $this->_element->ownerDocument->actualEncoding);
  121. $doc->appendChild($doc->importNode($this->_element, true));
  122. return $doc->saveXML();
  123. }
  124. /**
  125. * Get the XML for only this element
  126. *
  127. * Returns a string of this element's XML without prologue.
  128. *
  129. * @return string
  130. */
  131. public function saveXmlFragment()
  132. {
  133. return $this->_element->ownerDocument->saveXML($this->_element);
  134. }
  135. /**
  136. * Get encoding
  137. *
  138. * @return string
  139. */
  140. public function getEncoding()
  141. {
  142. return $this->_encoding;
  143. }
  144. /**
  145. * Set encoding
  146. *
  147. * @param string $value Encoding to use
  148. * @return Zend_Feed_Element
  149. */
  150. public function setEncoding($value)
  151. {
  152. $this->_encoding = (string) $value;
  153. return $this;
  154. }
  155. /**
  156. * Map variable access onto the underlying entry representation.
  157. *
  158. * Get-style access returns a Zend_Feed_Element representing the
  159. * child element accessed. To get string values, use method syntax
  160. * with the __call() overriding.
  161. *
  162. * @param string $var The property to access.
  163. * @return mixed
  164. */
  165. public function __get($var)
  166. {
  167. $nodes = $this->_children($var);
  168. $length = count($nodes);
  169. if ($length == 1) {
  170. return new Zend_Feed_Element($nodes[0]);
  171. } elseif ($length > 1) {
  172. return array_map(create_function('$e', 'return new Zend_Feed_Element($e);'), $nodes);
  173. } else {
  174. // When creating anonymous nodes for __set chaining, don't
  175. // call appendChild() on them. Instead we pass the current
  176. // element to them as an extra reference; the child is
  177. // then responsible for appending itself when it is
  178. // actually set. This way "if ($foo->bar)" doesn't create
  179. // a phantom "bar" element in our tree.
  180. if (strpos($var, ':') !== false) {
  181. list($ns, $elt) = explode(':', $var, 2);
  182. $node = $this->_element->ownerDocument->createElementNS(Zend_Feed::lookupNamespace($ns), $elt);
  183. } else {
  184. $node = $this->_element->ownerDocument->createElement($var);
  185. }
  186. $node = new self($node);
  187. $node->setParent($this);
  188. return $node;
  189. }
  190. }
  191. /**
  192. * Map variable sets onto the underlying entry representation.
  193. *
  194. * @param string $var The property to change.
  195. * @param string $val The property's new value.
  196. * @return void
  197. * @throws Zend_Feed_Exception
  198. */
  199. public function __set($var, $val)
  200. {
  201. $this->ensureAppended();
  202. $nodes = $this->_children($var);
  203. if (!$nodes) {
  204. if (strpos($var, ':') !== false) {
  205. list($ns, $elt) = explode(':', $var, 2);
  206. $node = $this->_element->ownerDocument->createElementNS(Zend_Feed::lookupNamespace($ns),
  207. $var, htmlspecialchars($val, ENT_NOQUOTES, $this->getEncoding()));
  208. $this->_element->appendChild($node);
  209. } else {
  210. $node = $this->_element->ownerDocument->createElement($var,
  211. htmlspecialchars($val, ENT_NOQUOTES, $this->getEncoding()));
  212. $this->_element->appendChild($node);
  213. }
  214. } elseif (count($nodes) > 1) {
  215. /**
  216. * @see Zend_Feed_Exception
  217. */
  218. #require_once 'Zend/Feed/Exception.php';
  219. throw new Zend_Feed_Exception('Cannot set the value of multiple tags simultaneously.');
  220. } else {
  221. $nodes[0]->nodeValue = $val;
  222. }
  223. }
  224. /**
  225. * Map isset calls onto the underlying entry representation.
  226. *
  227. * @param string $var
  228. * @return boolean
  229. */
  230. public function __isset($var)
  231. {
  232. // Look for access of the form {ns:var}. We don't use
  233. // _children() here because we can break out of the loop
  234. // immediately once we find something.
  235. if (strpos($var, ':') !== false) {
  236. list($ns, $elt) = explode(':', $var, 2);
  237. foreach ($this->_element->childNodes as $child) {
  238. if ($child->localName == $elt && $child->prefix == $ns) {
  239. return true;
  240. }
  241. }
  242. } else {
  243. foreach ($this->_element->childNodes as $child) {
  244. if ($child->localName == $var) {
  245. return true;
  246. }
  247. }
  248. }
  249. }
  250. /**
  251. * Get the value of an element with method syntax.
  252. *
  253. * Map method calls to get the string value of the requested
  254. * element. If there are multiple elements that match, this will
  255. * return an array of those objects.
  256. *
  257. * @param string $var The element to get the string value of.
  258. * @param mixed $unused This parameter is not used.
  259. * @return mixed The node's value, null, or an array of nodes.
  260. */
  261. public function __call($var, $unused)
  262. {
  263. $nodes = $this->_children($var);
  264. if (!$nodes) {
  265. return null;
  266. } elseif (count($nodes) > 1) {
  267. return $nodes;
  268. } else {
  269. return $nodes[0]->nodeValue;
  270. }
  271. }
  272. /**
  273. * Remove all children matching $var.
  274. *
  275. * @param string $var
  276. * @return void
  277. */
  278. public function __unset($var)
  279. {
  280. $nodes = $this->_children($var);
  281. foreach ($nodes as $node) {
  282. $parent = $node->parentNode;
  283. $parent->removeChild($node);
  284. }
  285. }
  286. /**
  287. * Returns the nodeValue of this element when this object is used
  288. * in a string context.
  289. *
  290. * @return string
  291. */
  292. public function __toString()
  293. {
  294. return $this->_element->nodeValue;
  295. }
  296. /**
  297. * Finds children with tagnames matching $var
  298. *
  299. * Similar to SimpleXML's children() method.
  300. *
  301. * @param string $var Tagname to match, can be either namespace:tagName or just tagName.
  302. * @return array
  303. */
  304. protected function _children($var)
  305. {
  306. $found = array();
  307. // Look for access of the form {ns:var}.
  308. if (strpos($var, ':') !== false) {
  309. list($ns, $elt) = explode(':', $var, 2);
  310. foreach ($this->_element->childNodes as $child) {
  311. if ($child->localName == $elt && $child->prefix == $ns) {
  312. $found[] = $child;
  313. }
  314. }
  315. } else {
  316. foreach ($this->_element->childNodes as $child) {
  317. if ($child->localName == $var) {
  318. $found[] = $child;
  319. }
  320. }
  321. }
  322. return $found;
  323. }
  324. /**
  325. * Required by the ArrayAccess interface.
  326. *
  327. * @param string $offset
  328. * @return boolean
  329. */
  330. public function offsetExists($offset)
  331. {
  332. if (strpos($offset, ':') !== false) {
  333. list($ns, $attr) = explode(':', $offset, 2);
  334. return $this->_element->hasAttributeNS(Zend_Feed::lookupNamespace($ns), $attr);
  335. } else {
  336. return $this->_element->hasAttribute($offset);
  337. }
  338. }
  339. /**
  340. * Required by the ArrayAccess interface.
  341. *
  342. * @param string $offset
  343. * @return string
  344. */
  345. public function offsetGet($offset)
  346. {
  347. if (strpos($offset, ':') !== false) {
  348. list($ns, $attr) = explode(':', $offset, 2);
  349. return $this->_element->getAttributeNS(Zend_Feed::lookupNamespace($ns), $attr);
  350. } else {
  351. return $this->_element->getAttribute($offset);
  352. }
  353. }
  354. /**
  355. * Required by the ArrayAccess interface.
  356. *
  357. * @param string $offset
  358. * @param string $value
  359. * @return string
  360. */
  361. public function offsetSet($offset, $value)
  362. {
  363. $this->ensureAppended();
  364. if (strpos($offset, ':') !== false) {
  365. list($ns, $attr) = explode(':', $offset, 2);
  366. // DOMElement::setAttributeNS() requires $qualifiedName to have a prefix
  367. return $this->_element->setAttributeNS(Zend_Feed::lookupNamespace($ns), $offset, $value);
  368. } else {
  369. return $this->_element->setAttribute($offset, $value);
  370. }
  371. }
  372. /**
  373. * Required by the ArrayAccess interface.
  374. *
  375. * @param string $offset
  376. * @return boolean
  377. */
  378. public function offsetUnset($offset)
  379. {
  380. if (strpos($offset, ':') !== false) {
  381. list($ns, $attr) = explode(':', $offset, 2);
  382. return $this->_element->removeAttributeNS(Zend_Feed::lookupNamespace($ns), $attr);
  383. } else {
  384. return $this->_element->removeAttribute($offset);
  385. }
  386. }
  387. }