PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Varien/Object.php

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 835 lines | 397 code | 64 blank | 374 comment | 52 complexity | 4f1f5be02d88e61362fcaed4ad188a28 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  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@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Varien
  22. * @package Varien_Object
  23. * @copyright Copyright (c) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Varien Object
  28. *
  29. * @category Varien
  30. * @package Varien_Object
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Varien_Object implements ArrayAccess
  34. {
  35. /**
  36. * Object attributes
  37. *
  38. * @var array
  39. */
  40. protected $_data = array();
  41. /**
  42. * Data changes flag (true after setData|unsetData call)
  43. * @var $_hasDataChange bool
  44. */
  45. protected $_hasDataChanges = false;
  46. /**
  47. * Original data that was loaded
  48. *
  49. * @var array
  50. */
  51. protected $_origData;
  52. /**
  53. * Name of object id field
  54. *
  55. * @var string
  56. */
  57. protected $_idFieldName = null;
  58. /**
  59. * Setter/Getter underscore transformation cache
  60. *
  61. * @var array
  62. */
  63. protected static $_underscoreCache = array();
  64. /**
  65. * Object delete flag
  66. *
  67. * @var boolean
  68. */
  69. protected $_isDeleted = false;
  70. /**
  71. * Constructor
  72. *
  73. * By default is looking for first argument as array and assignes it as object attributes
  74. * This behaviour may change in child classes
  75. *
  76. */
  77. public function __construct()
  78. {
  79. $args = func_get_args();
  80. if (empty($args[0])) {
  81. $args[0] = array();
  82. }
  83. $this->_data = $args[0];
  84. $this->_construct();
  85. }
  86. /**
  87. * Internal constructor not depended on params. Can be used for object initialization
  88. */
  89. protected function _construct()
  90. {
  91. }
  92. /**
  93. * Set _isDeleted flag value (if $isDeleted param is defined) and return current flag value
  94. *
  95. * @param boolean $isDeleted
  96. * @return boolean
  97. */
  98. public function isDeleted($isDeleted=null)
  99. {
  100. $result = $this->_isDeleted;
  101. if (!is_null($isDeleted)) {
  102. $this->_isDeleted = $isDeleted;
  103. }
  104. return $result;
  105. }
  106. /**
  107. * Get data change status
  108. *
  109. * @return bool
  110. */
  111. public function hasDataChanges()
  112. {
  113. return $this->_hasDataChanges;
  114. }
  115. /**
  116. * set name of object id field
  117. *
  118. * @param string $name
  119. * @return Varien_Object
  120. */
  121. public function setIdFieldName($name)
  122. {
  123. $this->_idFieldName = $name;
  124. return $this;
  125. }
  126. /**
  127. * Retrieve name of object id field
  128. *
  129. * @param string $name
  130. * @return Varien_Object
  131. */
  132. public function getIdFieldName()
  133. {
  134. return $this->_idFieldName;
  135. }
  136. /**
  137. * Retrieve object id
  138. *
  139. * @return mixed
  140. */
  141. public function getId()
  142. {
  143. if ($this->getIdFieldName()) {
  144. return $this->_getData($this->getIdFieldName());
  145. }
  146. return $this->_getData('id');
  147. }
  148. /**
  149. * Set object id field value
  150. *
  151. * @param mixed $value
  152. * @return Varien_Object
  153. */
  154. public function setId($value)
  155. {
  156. if ($this->getIdFieldName()) {
  157. $this->setData($this->getIdFieldName(), $value);
  158. } else {
  159. $this->setData('id', $value);
  160. }
  161. return $this;
  162. }
  163. /**
  164. * Add data to the object.
  165. *
  166. * Retains previous data in the object.
  167. *
  168. * @param array $arr
  169. * @return Varien_Object
  170. */
  171. public function addData(array $arr)
  172. {
  173. foreach($arr as $index=>$value) {
  174. $this->setData($index, $value);
  175. }
  176. return $this;
  177. }
  178. /**
  179. * Overwrite data in the object.
  180. *
  181. * $key can be string or array.
  182. * If $key is string, the attribute value will be overwritten by $value
  183. *
  184. * If $key is an array, it will overwrite all the data in the object.
  185. *
  186. * @param string|array $key
  187. * @param mixed $value
  188. * @return Varien_Object
  189. */
  190. public function setData($key, $value=null)
  191. {
  192. $this->_hasDataChanges = true;
  193. if(is_array($key)) {
  194. $this->_data = $key;
  195. } else {
  196. $this->_data[$key] = $value;
  197. }
  198. return $this;
  199. }
  200. /**
  201. * Unset data from the object.
  202. *
  203. * $key can be a string only. Array will be ignored.
  204. *
  205. * @param string $key
  206. * @return Varien_Object
  207. */
  208. public function unsetData($key=null)
  209. {
  210. $this->_hasDataChanges = true;
  211. if (is_null($key)) {
  212. $this->_data = array();
  213. } else {
  214. unset($this->_data[$key]);
  215. }
  216. return $this;
  217. }
  218. /**
  219. * Retrieves data from the object
  220. *
  221. * If $key is empty will return all the data as an array
  222. * Otherwise it will return value of the attribute specified by $key
  223. *
  224. * If $index is specified it will assume that attribute data is an array
  225. * and retrieve corresponding member.
  226. *
  227. * @param string $key
  228. * @param string|int $index
  229. * @return mixed
  230. */
  231. public function getData($key='', $index=null)
  232. {
  233. if (''===$key) {
  234. return $this->_data;
  235. }
  236. $default = null;
  237. // accept a/b/c as ['a']['b']['c']
  238. if (strpos($key,'/')) {
  239. $keyArr = explode('/', $key);
  240. $data = $this->_data;
  241. foreach ($keyArr as $i=>$k) {
  242. if ($k==='') {
  243. return $default;
  244. }
  245. if (is_array($data)) {
  246. if (!isset($data[$k])) {
  247. return $default;
  248. }
  249. $data = $data[$k];
  250. } elseif ($data instanceof Varien_Object) {
  251. $data = $data->getData($k);
  252. } else {
  253. return $default;
  254. }
  255. }
  256. return $data;
  257. }
  258. // legacy functionality for $index
  259. if (isset($this->_data[$key])) {
  260. if (is_null($index)) {
  261. return $this->_data[$key];
  262. }
  263. $value = $this->_data[$key];
  264. if (is_array($value)) {
  265. //if (isset($value[$index]) && (!empty($value[$index]) || strlen($value[$index]) > 0)) {
  266. /**
  267. * If we have any data, even if it empty - we should use it, anyway
  268. */
  269. if (isset($value[$index])) {
  270. return $value[$index];
  271. }
  272. return null;
  273. } elseif (is_string($value)) {
  274. $arr = explode("\n", $value);
  275. return (isset($arr[$index]) && (!empty($arr[$index]) || strlen($arr[$index]) > 0)) ? $arr[$index] : null;
  276. } elseif ($value instanceof Varien_Object) {
  277. return $value->getData($index);
  278. }
  279. return $default;
  280. }
  281. return $default;
  282. }
  283. /**
  284. * Get value from _data array without parse key
  285. *
  286. * @param string $key
  287. * @return mixed
  288. */
  289. protected function _getData($key)
  290. {
  291. return isset($this->_data[$key]) ? $this->_data[$key] : null;
  292. }
  293. /**
  294. * Set object data with calling setter method
  295. *
  296. * @param string $key
  297. * @param mixed $args
  298. * @return Varien_Object
  299. */
  300. public function setDataUsingMethod($key, $args=array())
  301. {
  302. $method = 'set'.$this->_camelize($key);
  303. $this->$method($args);
  304. return $this;
  305. }
  306. /**
  307. * Get object data by key with calling getter method
  308. *
  309. * @param string $key
  310. * @param mixed $args
  311. * @return mixed
  312. */
  313. public function getDataUsingMethod($key, $args=null)
  314. {
  315. $method = 'get'.$this->_camelize($key);
  316. return $this->$method($args);
  317. }
  318. /**
  319. * Fast get data or set default if value is not available
  320. *
  321. * @param string $key
  322. * @param mixed $default
  323. * @return mixed
  324. */
  325. public function getDataSetDefault($key, $default)
  326. {
  327. if (!isset($this->_data[$key])) {
  328. $this->_data[$key] = $default;
  329. }
  330. return $this->_data[$key];
  331. }
  332. /**
  333. * If $key is empty, checks whether there's any data in the object
  334. * Otherwise checks if the specified attribute is set.
  335. *
  336. * @param string $key
  337. * @return boolean
  338. */
  339. public function hasData($key='')
  340. {
  341. if (empty($key) || !is_string($key)) {
  342. return !empty($this->_data);
  343. }
  344. return array_key_exists($key, $this->_data);
  345. }
  346. /**
  347. * Convert object attributes to array
  348. *
  349. * @param array $arrAttributes array of required attributes
  350. * @return array
  351. */
  352. public function __toArray(array $arrAttributes = array())
  353. {
  354. if (empty($arrAttributes)) {
  355. return $this->_data;
  356. }
  357. $arrRes = array();
  358. foreach ($arrAttributes as $attribute) {
  359. if (isset($this->_data[$attribute])) {
  360. $arrRes[$attribute] = $this->_data[$attribute];
  361. }
  362. else {
  363. $arrRes[$attribute] = null;
  364. }
  365. }
  366. return $arrRes;
  367. }
  368. /**
  369. * Public wrapper for __toArray
  370. *
  371. * @param array $arrAttributes
  372. * @return array
  373. */
  374. public function toArray(array $arrAttributes = array())
  375. {
  376. return $this->__toArray($arrAttributes);
  377. }
  378. /**
  379. * Set required array elements
  380. *
  381. * @param array $arr
  382. * @param array $elements
  383. * @return array
  384. */
  385. protected function _prepareArray(&$arr, array $elements=array())
  386. {
  387. foreach ($elements as $element) {
  388. if (!isset($arr[$element])) {
  389. $arr[$element] = null;
  390. }
  391. }
  392. return $arr;
  393. }
  394. /**
  395. * Convert object attributes to XML
  396. *
  397. * @param array $arrAttributes array of required attributes
  398. * @param string $rootName name of the root element
  399. * @return string
  400. */
  401. protected function __toXml(array $arrAttributes = array(), $rootName = 'item', $addOpenTag=false, $addCdata=true)
  402. {
  403. $xml = '';
  404. if ($addOpenTag) {
  405. $xml.= '<?xml version="1.0" encoding="UTF-8"?>'."\n";
  406. }
  407. if (!empty($rootName)) {
  408. $xml.= '<'.$rootName.'>'."\n";
  409. }
  410. $xmlModel = new Varien_Simplexml_Element('<node></node>');
  411. $arrData = $this->toArray($arrAttributes);
  412. foreach ($arrData as $fieldName => $fieldValue) {
  413. if ($addCdata === true) {
  414. $fieldValue = "<![CDATA[$fieldValue]]>";
  415. } else {
  416. $fieldValue = $xmlModel->xmlentities($fieldValue);
  417. }
  418. $xml.= "<$fieldName>$fieldValue</$fieldName>"."\n";
  419. }
  420. if (!empty($rootName)) {
  421. $xml.= '</'.$rootName.'>'."\n";
  422. }
  423. return $xml;
  424. }
  425. /**
  426. * Public wrapper for __toXml
  427. *
  428. * @param array $arrAttributes
  429. * @param string $rootName
  430. * @return string
  431. */
  432. public function toXml(array $arrAttributes = array(), $rootName = 'item', $addOpenTag=false, $addCdata=true)
  433. {
  434. return $this->__toXml($arrAttributes, $rootName, $addOpenTag, $addCdata);
  435. }
  436. /**
  437. * Convert object attributes to JSON
  438. *
  439. * @param array $arrAttributes array of required attributes
  440. * @return string
  441. */
  442. protected function __toJson(array $arrAttributes = array())
  443. {
  444. $arrData = $this->toArray($arrAttributes);
  445. $json = Zend_Json::encode($arrData);
  446. return $json;
  447. }
  448. /**
  449. * Public wrapper for __toJson
  450. *
  451. * @param array $arrAttributes
  452. * @return string
  453. */
  454. public function toJson(array $arrAttributes = array())
  455. {
  456. return $this->__toJson($arrAttributes);
  457. }
  458. /**
  459. * Convert object attributes to string
  460. *
  461. * @param array $arrAttributes array of required attributes
  462. * @param string $valueSeparator
  463. * @return string
  464. */
  465. // public function __toString(array $arrAttributes = array(), $valueSeparator=',')
  466. // {
  467. // $arrData = $this->toArray($arrAttributes);
  468. // return implode($valueSeparator, $arrData);
  469. // }
  470. /**
  471. * Public wrapper for __toString
  472. *
  473. * Will use $format as an template and substitute {{key}} for attributes
  474. *
  475. * @param string $format
  476. * @return string
  477. */
  478. public function toString($format='')
  479. {
  480. if (empty($format)) {
  481. $str = implode(', ', $this->getData());
  482. } else {
  483. preg_match_all('/\{\{([a-z0-9_]+)\}\}/is', $format, $matches);
  484. foreach ($matches[1] as $var) {
  485. $format = str_replace('{{'.$var.'}}', $this->getData($var), $format);
  486. }
  487. $str = $format;
  488. }
  489. return $str;
  490. }
  491. /**
  492. * Set/Get attribute wrapper
  493. *
  494. * @param string $method
  495. * @param array $args
  496. * @return mixed
  497. */
  498. public function __call($method, $args)
  499. {
  500. switch (substr($method, 0, 3)) {
  501. case 'get' :
  502. //Varien_Profiler::start('GETTER: '.get_class($this).'::'.$method);
  503. $key = $this->_underscore(substr($method,3));
  504. $data = $this->getData($key, isset($args[0]) ? $args[0] : null);
  505. //Varien_Profiler::stop('GETTER: '.get_class($this).'::'.$method);
  506. return $data;
  507. case 'set' :
  508. //Varien_Profiler::start('SETTER: '.get_class($this).'::'.$method);
  509. $key = $this->_underscore(substr($method,3));
  510. $result = $this->setData($key, isset($args[0]) ? $args[0] : null);
  511. //Varien_Profiler::stop('SETTER: '.get_class($this).'::'.$method);
  512. return $result;
  513. case 'uns' :
  514. //Varien_Profiler::start('UNS: '.get_class($this).'::'.$method);
  515. $key = $this->_underscore(substr($method,3));
  516. $result = $this->unsetData($key);
  517. //Varien_Profiler::stop('UNS: '.get_class($this).'::'.$method);
  518. return $result;
  519. case 'has' :
  520. //Varien_Profiler::start('HAS: '.get_class($this).'::'.$method);
  521. $key = $this->_underscore(substr($method,3));
  522. //Varien_Profiler::stop('HAS: '.get_class($this).'::'.$method);
  523. return isset($this->_data[$key]);
  524. }
  525. throw new Varien_Exception("Invalid method ".get_class($this)."::".$method."(".print_r($args,1).")");
  526. }
  527. /**
  528. * Attribute getter (deprecated)
  529. *
  530. * @param string $var
  531. * @return mixed
  532. */
  533. public function __get($var)
  534. {
  535. $var = $this->_underscore($var);
  536. return $this->getData($var);
  537. }
  538. /**
  539. * Attribute setter (deprecated)
  540. *
  541. * @param string $var
  542. * @param mixed $value
  543. */
  544. public function __set($var, $value)
  545. {
  546. $var = $this->_underscore($var);
  547. $this->setData($var, $value);
  548. }
  549. /**
  550. * checks whether the object is empty
  551. *
  552. * @return boolean
  553. */
  554. public function isEmpty()
  555. {
  556. if (empty($this->_data)) {
  557. return true;
  558. }
  559. return false;
  560. }
  561. /**
  562. * Converts field names for setters and geters
  563. *
  564. * $this->setMyField($value) === $this->setData('my_field', $value)
  565. * Uses cache to eliminate unneccessary preg_replace
  566. *
  567. * @param string $name
  568. * @return string
  569. */
  570. protected function _underscore($name)
  571. {
  572. if (isset(self::$_underscoreCache[$name])) {
  573. return self::$_underscoreCache[$name];
  574. }
  575. #Varien_Profiler::start('underscore');
  576. $result = strtolower(preg_replace('/(.)([A-Z])/', "$1_$2", $name));
  577. #Varien_Profiler::stop('underscore');
  578. self::$_underscoreCache[$name] = $result;
  579. return $result;
  580. }
  581. protected function _camelize($name)
  582. {
  583. return uc_words($name, '');
  584. }
  585. /**
  586. * serialize object attributes
  587. *
  588. * @param array $attributes
  589. * @param string $valueSeparator
  590. * @param string $fieldSeparator
  591. * @param string $quote
  592. * @return string
  593. */
  594. public function serialize($attributes = array(), $valueSeparator='=', $fieldSeparator=' ', $quote='"')
  595. {
  596. $res = '';
  597. $data = array();
  598. if (empty($attributes)) {
  599. $attributes = array_keys($this->_data);
  600. }
  601. foreach ($this->_data as $key => $value) {
  602. if (in_array($key, $attributes)) {
  603. $data[] = $key . $valueSeparator . $quote . $value . $quote;
  604. }
  605. }
  606. $res = implode($fieldSeparator, $data);
  607. return $res;
  608. }
  609. /**
  610. * Get object loaded data (original data)
  611. *
  612. * @param string $key
  613. * @return mixed
  614. */
  615. public function getOrigData($key=null)
  616. {
  617. if (is_null($key)) {
  618. return $this->_origData;
  619. }
  620. return isset($this->_origData[$key]) ? $this->_origData[$key] : null;
  621. }
  622. /**
  623. * Initialize object original data
  624. *
  625. * @param string $key
  626. * @param mixed $data
  627. * @return Varien_Object
  628. */
  629. public function setOrigData($key=null, $data=null)
  630. {
  631. if (is_null($key)) {
  632. $this->_origData = $this->_data;
  633. } else {
  634. $this->_origData[$key] = $data;
  635. }
  636. return $this;
  637. }
  638. /**
  639. * Compare object data with original data
  640. *
  641. * @param string $field
  642. * @return boolean
  643. */
  644. public function dataHasChangedFor($field)
  645. {
  646. $newData = $this->getData($field);
  647. $origData = $this->getOrigData($field);
  648. return $newData!=$origData;
  649. }
  650. /**
  651. * Clears data changes status
  652. *
  653. * @param boolean $value
  654. * @return Varien_Object
  655. */
  656. public function setDataChanges($value)
  657. {
  658. $this->_hasDataChanges = (bool)$value;
  659. return $this;
  660. }
  661. /**
  662. * Present object data as string in debug mode
  663. *
  664. * @param mixed $data
  665. * @param array $objects
  666. * @return string
  667. */
  668. public function debug($data=null, &$objects=array())
  669. {
  670. if (is_null($data)) {
  671. $hash = spl_object_hash($this);
  672. if (!empty($objects[$hash])) {
  673. return '*** RECURSION ***';
  674. }
  675. $objects[$hash] = true;
  676. $data = $this->getData();
  677. }
  678. $debug = array();
  679. foreach ($data as $key=>$value) {
  680. if (is_scalar($value)) {
  681. $debug[$key] = $value;
  682. } elseif (is_array($value)) {
  683. $debug[$key] = $this->debug($value, $objects);
  684. } elseif ($value instanceof Varien_Object) {
  685. $debug[$key.' ('.get_class($value).')'] = $value->debug(null, $objects);
  686. }
  687. }
  688. return $debug;
  689. }
  690. /**
  691. * Implementation of ArrayAccess::offsetSet()
  692. *
  693. * @link http://www.php.net/manual/en/arrayaccess.offsetset.php
  694. * @param string $offset
  695. * @param mixed $value
  696. */
  697. public function offsetSet($offset, $value)
  698. {
  699. $this->_data[$offset] = $value;
  700. }
  701. /**
  702. * Implementation of ArrayAccess::offsetExists()
  703. *
  704. * @link http://www.php.net/manual/en/arrayaccess.offsetexists.php
  705. * @param string $offset
  706. * @return boolean
  707. */
  708. public function offsetExists($offset)
  709. {
  710. return isset($this->_data[$offset]);
  711. }
  712. /**
  713. * Implementation of ArrayAccess::offsetUnset()
  714. *
  715. * @link http://www.php.net/manual/en/arrayaccess.offsetunset.php
  716. * @param string $offset
  717. */
  718. public function offsetUnset($offset)
  719. {
  720. unset($this->_data[$offset]);
  721. }
  722. /**
  723. * Implementation of ArrayAccess::offsetGet()
  724. *
  725. * @link http://www.php.net/manual/en/arrayaccess.offsetget.php
  726. * @param string $offset
  727. * @return mixed
  728. */
  729. public function offsetGet($offset)
  730. {
  731. return isset($this->_data[$offset]) ? $this->_data[$offset] : null;
  732. }
  733. /**
  734. * Enter description here...
  735. *
  736. * @param string $field
  737. * @return boolean
  738. */
  739. public function isDirty($field=null)
  740. {
  741. if (empty($this->_dirty)) {
  742. return false;
  743. }
  744. if (is_null($field)) {
  745. return true;
  746. }
  747. return isset($this->_dirty[$field]);
  748. }
  749. /**
  750. * Enter description here...
  751. *
  752. * @param string $field
  753. * @param boolean $flag
  754. * @return Varien_Object
  755. */
  756. public function flagDirty($field, $flag=true)
  757. {
  758. if (is_null($field)) {
  759. foreach ($this->getData() as $field=>$value) {
  760. $this->flagDirty($field, $flag);
  761. }
  762. } else {
  763. if ($flag) {
  764. $this->_dirty[$field] = true;
  765. } else {
  766. unset($this->_dirty[$field]);
  767. }
  768. }
  769. return $this;
  770. }
  771. }