PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/atk4/lib/AbstractObject.php

https://github.com/mahimarathore/mahi
PHP | 996 lines | 538 code | 54 blank | 404 comment | 91 complexity | 6d150fff2da6461f5c44a9f1dcca7178 MD5 | raw file
Possible License(s): AGPL-3.0, MPL-2.0-no-copyleft-exception
  1. <?php // vim:ts=4:sw=4:et:fdm=marker
  2. /**
  3. * A base class for all objects/classes in Agile Toolkit.
  4. * Do not directly inherit from this class, instead use one of
  5. * AbstractModel, AbstractController or AbstractView
  6. *
  7. * @link http://agiletoolkit.org/learn/intro
  8. *//*
  9. ==ATK4===================================================
  10. This file is part of Agile Toolkit 4
  11. http://agiletoolkit.org/
  12. (c) 2008-2013 Agile Toolkit Limited <info@agiletoolkit.org>
  13. Distributed under Affero General Public License v3 and
  14. commercial license.
  15. See LICENSE or LICENSE_COM for more information
  16. =====================================================ATK4=*/
  17. abstract class AbstractObject
  18. {
  19. public $settings=array('extension'=>'.html');
  20. /** Reference to the current model. Read only. Use setModel() */
  21. public $model;
  22. /** Reference to the current controller. Read only. Use setController() */
  23. public $controller;
  24. /** Exception class to use when $this->exception() is called */
  25. public $default_exception='BaseException';
  26. /** Default controller to initialize when calling setModel() */
  27. public $default_controller=null;
  28. // {{{ Object hierarchy management
  29. /** Unique object name */
  30. public $name;
  31. /** Name of the object in owner's element array */
  32. public $short_name;
  33. /** short_name => object hash of children objects */
  34. public $elements = array ();
  35. /** Link to object into which we added this object */
  36. public $owner;
  37. /** Always points to current API */
  38. public $api;
  39. /**
  40. * When this object is added, owner->elements[$this->short_name]
  41. * will be == $this;
  42. */
  43. public $auto_track_element=false;
  44. /** To make sure you have called parent::init() properly */
  45. public $_initialized=false;
  46. /**
  47. * Initialize object. Always call parent Do not call directly
  48. *
  49. * @return void
  50. */
  51. function init()
  52. {
  53. /**
  54. * This method is called for initialization
  55. */
  56. $this->_initialized=true;
  57. }
  58. /* \section Object Management Methods */
  59. /**
  60. * Clones associated controller and model. If cloning views, add them to
  61. * the owner
  62. *
  63. * @return AbstractObject Copy this object
  64. */
  65. function __clone()
  66. {
  67. if ($this->model && is_object($this->model)) {
  68. $this->model=clone $this->model;
  69. }
  70. if ($this->controller && is_object($this->controller)) {
  71. $this->controller=clone $this->controller;
  72. }
  73. }
  74. /**
  75. * Converts into string "Object View(myapp_page_view)"
  76. *
  77. * @return string
  78. */
  79. function __toString()
  80. {
  81. return "Object " . get_class($this) . "(" . $this->name . ")";
  82. }
  83. /**
  84. * Removes object from parent and prevents it from renedring
  85. * \code
  86. * $view = $this->add('View');
  87. * $view -> destroy();
  88. * \endcode
  89. *
  90. * @return void
  91. */
  92. function destroy()
  93. {
  94. foreach ($this->elements as $el) {
  95. if ($el instanceof AbstractObject) {
  96. $el->destroy();
  97. }
  98. }
  99. if (@$this->model && $this->model instanceof AbstractObject) {
  100. $this->model->destroy();
  101. unset($this->model);
  102. }
  103. if (@$this->controller
  104. && $this->controller instanceof AbstractObject
  105. ) {
  106. $this->controller->destroy();
  107. unset($this->controller);
  108. }
  109. $this->owner->_removeElement($this->short_name);
  110. }
  111. /**
  112. * Remove child element if it exists
  113. *
  114. * @param string $short_name short name of the element
  115. *
  116. * @return $this
  117. */
  118. function removeElement($short_name)
  119. {
  120. if (is_object($this->elements[$short_name])) {
  121. $this->elements[$short_name]->destroy();
  122. } else {
  123. unset($this->elements[$short_name]);
  124. }
  125. return $this;
  126. }
  127. /**
  128. * Actually removes the element
  129. *
  130. * @param string $short_name short name
  131. *
  132. * @return \AbstractObject
  133. * @private
  134. */
  135. function _removeElement($short_name)
  136. {
  137. unset($this->elements[$short_name]);
  138. return $this;
  139. }
  140. /**
  141. * Creates one more instance of $this object
  142. *
  143. * @param array $properties Set initial properties for new object
  144. *
  145. * @return \AbstractObject
  146. */
  147. function newInstance($properties=null)
  148. {
  149. return $this->owner->add(get_class($this), $properties);
  150. }
  151. /**
  152. * Creates new object and adds it as a child. Returns new object.
  153. *
  154. * @param string $class Name of the new class
  155. * @param array|string $short_name Short name or array of properties
  156. * @param string $template_spot Tag where output will appear
  157. * @param array|string $template_branch Redefine template
  158. *
  159. * @link http://agiletoolkit.org/learn/understand/base/adding
  160. * @return \AbstractObject
  161. */
  162. function add($class, $short_name = null,
  163. $template_spot = null, $template_branch = null
  164. ) {
  165. if (is_array($short_name)) {
  166. $di_config=$short_name;
  167. $short_name=@$di_config['name'];
  168. unset($di_config['name']);
  169. } else {
  170. $di_config=array();
  171. }
  172. if (is_object($class)) {
  173. // Object specified, just add the object, do not create anything
  174. if (!($class instanceof AbstractObject)) {
  175. throw $this->exception(
  176. 'You may only add objects based on AbstractObject'
  177. );
  178. }
  179. if (!$class->short_name) {
  180. throw $this->exception(
  181. 'Cannot add existing object, without short_name'
  182. );
  183. }
  184. $this->elements[$class->short_name] = $class;
  185. if ($class instanceof AbstractView) {
  186. $class->owner->elements[$class->short_name]=true;
  187. }
  188. $class->owner = $this;
  189. if ($class instanceof AbstractView) {
  190. $class->initializeTemplate($template_spot, $template_branch);
  191. }
  192. return $class;
  193. }
  194. if (!is_string($class) || !$class) {
  195. throw $this->exception("Class is not valid")
  196. ->addMoreInfo('class', $class);
  197. }
  198. $class = str_replace('/','\\',$class);
  199. if ($class[0]=='.') {
  200. // Relative class name specified, extract current namespace
  201. // and make new class name relative to this namespace
  202. $ns = get_class($this);
  203. $ns = substr($ns, 0, strrpos($ns, '\\'));
  204. $class = $ns . '\\' . substr($class, 2);
  205. }
  206. if (!$short_name) {
  207. $short_name = str_replace('\\', '_', strtolower($class));
  208. }
  209. $short_name=$this->_unique($this->elements, $short_name);
  210. if (isset ($this->elements[$short_name])) {
  211. if ($this->elements[$short_name] instanceof AbstractView) {
  212. /*
  213. * AbstractView classes shouldn't be created with the same
  214. * name. If someone would still try to do that, it should
  215. * generate error. Obviously one of those wouldn't be
  216. * displayed or other errors would occur
  217. */
  218. throw $this->exception("Element with this name already exists")
  219. ->addMoreInfo('name', $short_name)
  220. ->addThis($this);
  221. }
  222. }
  223. // Separate out namespace ????????????????????
  224. $class_name_nodash=str_replace('-', '', $class);
  225. if (!class_exists($class_name_nodash, false)
  226. && isset($this->api->pathfinder)
  227. ) {
  228. $this->api->pathfinder->loadClass($class);
  229. }
  230. $element = new $class_name_nodash();
  231. if (!($element instanceof AbstractObject)) {
  232. throw $this->exception(
  233. "You can add only classes based on AbstractObject"
  234. );
  235. }
  236. foreach ($di_config as $key=>$val) {
  237. $element->$key=$val;
  238. }
  239. $element->owner = $this;
  240. $element->api = $this->api;
  241. $element->name = $this->_shorten($this->name . '_' . $short_name);
  242. $element->short_name = $short_name;
  243. if (!$element->auto_track_element) {
  244. // dont store extra reference to models and controlers
  245. // for purposes of better garbage collection
  246. $this->elements[$short_name]=true;
  247. } else {
  248. $this->elements[$short_name]=$element;
  249. }
  250. // Initialize template before init() starts
  251. if ($element instanceof AbstractView) {
  252. $element->initializeTemplate($template_spot, $template_branch);
  253. }
  254. // Avoid using this hook. Agile Toolkit creates LOTS of objects,
  255. // so you'll get significantly slower code if you try to use this
  256. $this->api->hook('beforeObjectInit', array(&$element));
  257. // Initialize element
  258. $element->init();
  259. // Make sure init()'s parent was called. Popular coder's mistake
  260. if (!$element->_initialized) {
  261. throw $element->exception(
  262. 'You should call parent::init() when you override it'
  263. )
  264. ->addMoreInfo('object_name', $element->name)
  265. ->addMoreInfo('class', get_class($element));
  266. }
  267. return $element;
  268. }
  269. /**
  270. * Find child element by their short name. Use in chaining. Exception
  271. * if not found.
  272. *
  273. * @param string $short_name Short name of the child element
  274. *
  275. * @return AbstractObject
  276. */
  277. function getElement($short_name)
  278. {
  279. if (!isset ($this->elements[$short_name])) {
  280. throw $this->exception("Child element not found")
  281. ->addMoreInfo('element', $short_name);
  282. }
  283. return $this->elements[$short_name];
  284. }
  285. /**
  286. * Find child element. Use in condition.
  287. *
  288. * @param string $short_name Short name of the child element
  289. *
  290. * @return AbstractModel
  291. */
  292. function hasElement($short_name)
  293. {
  294. return isset($this->elements[$short_name])?
  295. $this->elements[$short_name]
  296. :false;
  297. }
  298. /**
  299. * Names object accordingly. May not work on some objects
  300. *
  301. * @param string $short_name Short name of the child element
  302. *
  303. * @return AbstractModel $this
  304. */
  305. function rename($short_name)
  306. {
  307. unset($this->owner->elements[$this->short_name]);
  308. $this->name = $this->name . '_' . $short_name;
  309. $this->short_name = $short_name;
  310. if (!$this->auto_track_element) {
  311. $this->owner->elements[$short_name]=true;
  312. } else {
  313. $this->owner->elements[$short_name]=$this;
  314. }
  315. return $this;
  316. }
  317. // }}}
  318. // {{{ Model and Controller handling
  319. /**
  320. * Associate controller with the object.
  321. *
  322. * @param string|object $controller Class or instance of controller
  323. * @param string|array $name Name or property for new controller
  324. *
  325. * @return AbstractController Newly added controller
  326. */
  327. function setController($controller, $name=null)
  328. {
  329. $controller=$this->api->normalizeClassName($controller,'Controller');
  330. return $this->add($controller, $name);
  331. }
  332. /**
  333. * Associate model with object.
  334. *
  335. * @param string|object $model Class or instance of model
  336. *
  337. * @return AbstractModel Newly added Model
  338. */
  339. function setModel($model)
  340. {
  341. $model = $this->api->normalizeClassName($model,'Model');
  342. $this->model=$this->add($model);
  343. return $this->model;
  344. }
  345. /**
  346. * Return current model
  347. *
  348. * @return AbstractModel Currently associated model object
  349. */
  350. function getModel()
  351. {
  352. return $this->model;
  353. }
  354. // }}}
  355. // {{{ Session management: http://agiletoolkit.org/doc/session
  356. /**
  357. * Remember data in object-relevant session data
  358. *
  359. * @param string $key Key for the data
  360. * @param mixed $value Value
  361. *
  362. * @return AbstractObject $this
  363. */
  364. function memorize($key, $value)
  365. {
  366. if (!isset ($value)) {
  367. return $this->recall($key);
  368. }
  369. $this->api->initializeSession();
  370. return $_SESSION['o'][$this->name][$key] = $value;
  371. }
  372. /**
  373. * Similar to memorize, but will associate first non-nul argument
  374. *
  375. * @param string $key Key for the data
  376. * @param mixed $value1 Possible value for data
  377. * @param mixed $value2 Possible value for data
  378. * @param mixed $value3 Possible value for data
  379. *
  380. * @return AbstractObject $this
  381. */
  382. function learn($key, $value1 = null, $value2 = null, $value3 = null)
  383. {
  384. if (isset ($value1)) {
  385. return $this->memorize($key, $value1);
  386. } elseif (isset ($value2)) {
  387. return $this->memorize($key, $value2);
  388. } else {
  389. return $this->memorize($key, $value3);
  390. }
  391. }
  392. /**
  393. * Forget session data for arg $key. If $key is omitted will forget
  394. * all associated session data
  395. *
  396. * @param string $key Optional key for data to forget
  397. *
  398. * @return AbstractObject $this
  399. */
  400. function forget($key = null)
  401. {
  402. $this->api->initializeSession();
  403. if (isset ($key)) {
  404. unset ($_SESSION['o'][$this->name][$key]);
  405. } else {
  406. unset ($_SESSION['o'][$this->name]);
  407. }
  408. }
  409. /**
  410. * Returns session data for this object. If not previously set, then
  411. * $default is returned
  412. *
  413. * @param string $key Data Key
  414. * @param mixed $default Default value
  415. *
  416. * @return mixed Previously memorized data or $default
  417. */
  418. function recall($key, $default = null)
  419. {
  420. $this->api->initializeSession(false);
  421. if (!isset ($_SESSION['o'][$this->name][$key])
  422. ||is_null($_SESSION['o'][$this->name][$key])
  423. ) {
  424. return $default;
  425. } else {
  426. return $_SESSION['o'][$this->name][$key];
  427. }
  428. }
  429. // }}}
  430. // {{{ Exception handling: http://agiletoolkit.org/doc/exception
  431. /**
  432. * Returns relevant exception class. Use this method with "throw"
  433. *
  434. * @param string $message Static text of exception.
  435. * @param string $type Exception class or class postfix
  436. * @param string $code Optional error code
  437. *
  438. * @return BaseException
  439. */
  440. function exception($message,$type=null,$code=null)
  441. {
  442. if (!$type) {
  443. $type=$this->default_exception;
  444. } elseif ($type[0]=='_') {
  445. $type=$this->default_exception.'_'.substr($type, 1);
  446. } else {
  447. $type='Exception_'.$type;
  448. }
  449. // Localization support
  450. $message=$this->api->_($message);
  451. if ($type=='Exception') {
  452. $type='BaseException';
  453. }
  454. $e=new $type($message,$code);
  455. $e->owner=$this;
  456. $e->api=$this->api;
  457. $e->init();
  458. return $e;
  459. }
  460. // }}}
  461. // {{{ Code which can be potentially obsoleted
  462. /**
  463. * Reports fatal error. Use ->exception instead
  464. *
  465. * @param string $error error text
  466. * @param int $shift relative offset in backtrace
  467. *
  468. * @return void Should stop execution
  469. * @obsolete
  470. */
  471. function fatal($error, $shift = 0)
  472. {
  473. return $this->upCall(
  474. 'outputFatal', array (
  475. $error,
  476. $shift
  477. )
  478. );
  479. }
  480. /**
  481. * Records debug information
  482. *
  483. * @param string $msg information
  484. *
  485. * @return void
  486. * @obsolete
  487. */
  488. function info($msg)
  489. {
  490. /**
  491. * Call this function to send some information to API. Example:
  492. *
  493. * $this->info("User tried buying traffic without enough money in bank");
  494. */
  495. if (!$this->api->hook('outputInfo', array($msg, $this))) {
  496. $this->upCall('outputInfo', $msg);
  497. }
  498. }
  499. /**
  500. * Turns on debug mode for this object. Using first argument as string
  501. * is obsolete
  502. *
  503. * @param bool|string $msg "true" to start debugging
  504. * @param string $file obsolete
  505. * @param string $line obsolete
  506. *
  507. * @return void
  508. */
  509. function debug($msg=true, $file = null, $line = null)
  510. {
  511. if ($msg===true) {
  512. $this->debug=true;
  513. return $this;
  514. }
  515. // The rest of this method is obsolete
  516. if ((isset ($this->debug) && $this->debug)
  517. || (isset ($this->api->debug) && $this->api->debug)
  518. ) {
  519. $this->upCall(
  520. 'outputDebug', array (
  521. $msg,
  522. $file,
  523. $line
  524. )
  525. );
  526. }
  527. }
  528. /**
  529. * Records warning
  530. *
  531. * @param string $msg information
  532. * @param int $shift relative offset in backtrace
  533. *
  534. * @return void
  535. * @obsolete
  536. */
  537. function warning($msg, $shift = 0)
  538. {
  539. $this->upCall(
  540. 'outputWarning', array (
  541. $msg,
  542. $shift
  543. )
  544. );
  545. }
  546. /////////////// C r o s s c a l l s ///////////////////////
  547. /**
  548. * Call specified method for this class and all parents up to api
  549. *
  550. * @param string $type information
  551. * @param array $args relative offset in backtrace
  552. *
  553. * @return void
  554. * @obsolete
  555. */
  556. function upCall($type, $args = array ())
  557. {
  558. /**
  559. * Try to handle something on our own and in case we are not
  560. * able, pass to parent. Such as messages, notifications and request
  561. * for additional info or descriptions are passed this way.
  562. */
  563. if (method_exists($this, $type)) {
  564. return call_user_func_array(
  565. array (
  566. $this,
  567. $type
  568. ), $args
  569. );
  570. }
  571. if (!$this->owner) {
  572. return false;
  573. }
  574. return $this->owner->upCall($type, $args);
  575. }
  576. // }}}
  577. // {{{ Hooks: http://agiletoolkit.org/doc/hooks
  578. public $hooks = array ();
  579. /**
  580. * If priority is negative, then hooks will be executed in reverse order
  581. *
  582. * @param string $hook_spot Hook identifier to bind on
  583. * @param callable $callable Will be called on hook()
  584. * @param array $arguments Arguments are passed to $callable
  585. * @param int $priority Lower priority is called sooner
  586. *
  587. * @return AbstractObject $this
  588. */
  589. function addHook($hook_spot, $callable, $arguments=array(), $priority = 5)
  590. {
  591. if (!is_array($arguments)) {
  592. throw $this->exception('Incorrect arguments');
  593. }
  594. if (is_string($hook_spot) && strpos($hook_spot, ',')!==false) {
  595. $hook_spot=explode(',', $hook_spot);
  596. }
  597. if (is_array($hook_spot)) {
  598. foreach ($hook_spot as $h) {
  599. $this->addHook($h, $callable, $arguments, $priority);
  600. }
  601. return $this;
  602. }
  603. if (!is_callable($callable)
  604. && ($callable instanceof AbstractObject
  605. && !$callable->hasMethod($hook_spot))
  606. ) {
  607. throw $this->exception('Hook does not exist');
  608. }
  609. if (is_object($callable) && !is_callable($callable)) {
  610. $callable=array($callable,$hook_spot);
  611. // short for addHook('test',$this); to call $this->test();
  612. }
  613. if ($priority>=0) {
  614. $this->hooks[$hook_spot][$priority][] = array($callable,$arguments);
  615. } else {
  616. if (!$this->hooks[$hook_spot][$priority]) {
  617. $this->hooks[$hook_spot][$priority]=array();
  618. }
  619. array_unshift(
  620. $this->hooks[$hook_spot][$priority],
  621. array($callable,$arguments)
  622. );
  623. }
  624. return $this;
  625. }
  626. /**
  627. * Delete all hooks for specified spot
  628. *
  629. * @param string $hook_spot Hook identifier to bind on
  630. *
  631. * @return AbstractObject $this
  632. */
  633. function removeHook($hook_spot)
  634. {
  635. unset($this->hooks[$hook_spot]);
  636. return $this;
  637. }
  638. /**
  639. * Execute all callables assigned to $hook_spot
  640. *
  641. * @param string $hook_spot Hook identifier
  642. * @param array $arg Additional arguments to callables
  643. *
  644. * @return mixed Array of responses or value specified to breakHook
  645. */
  646. function hook($hook_spot, $arg = array ())
  647. {
  648. if (!is_array($arg)) {
  649. throw $this->exception(
  650. 'Incorrect arguments, or hook does not exist'
  651. );
  652. }
  653. $return=array();
  654. if ($arg===undefined) {
  655. $arg=array();
  656. }
  657. try{
  658. if (isset ($this->hooks[$hook_spot])) {
  659. if (is_array($this->hooks[$hook_spot])) {
  660. foreach ($this->hooks[$hook_spot] as $prio => $_data) {
  661. foreach ($_data as $data) {
  662. // Our extentsion.
  663. if (is_string($data[0])
  664. && !preg_match(
  665. '/^[a-zA-Z_][a-zA-Z0-9_]*$/',
  666. $data[0]
  667. )
  668. ) {
  669. $result = eval ($data[0]);
  670. } elseif (is_callable($data[0])) {
  671. $result = call_user_func_array(
  672. $data[0],
  673. array_merge(
  674. array($this),
  675. $arg,
  676. $data[1]
  677. )
  678. );
  679. } else {
  680. if (!is_array($data[0])) {
  681. $data[0] = array (
  682. 'STATIC',
  683. $data[0]
  684. );
  685. }
  686. throw $this->exception(
  687. "Cannot call hook. Function might not exist"
  688. )
  689. ->addMoreInfo('hook', $hook_spot)
  690. ->addMoreInfo('arg1', $data[0][0])
  691. ->addMoreInfo('arg2', $data[0][1]);
  692. }
  693. $return[]=$result;
  694. }
  695. }
  696. }
  697. }
  698. }catch(Exception_Hook $e){
  699. return $e->return_value;
  700. }
  701. return $return;
  702. }
  703. /**
  704. * When called from inside a hook callable, will stop execution of other
  705. * callables on same hook. The passed argument will be returned by the
  706. * hook method
  707. *
  708. * @param mixed $return What would hook() return?
  709. *
  710. * @return void Never returns
  711. */
  712. function breakHook($return)
  713. {
  714. $e=$this->exception(null, 'Hook');
  715. $e->return_value=$return;
  716. throw $e;
  717. }
  718. // }}}
  719. // {{{ Dynamic Methods: http://agiletoolkit.org/learn/dynamic
  720. /**
  721. * Call method is used to display exception for non-existant methods and
  722. * provides ability to extend objects with addMethod()
  723. *
  724. * @param string $method Name of the method
  725. * @param array $arguments Arguments
  726. *
  727. * @return mixed
  728. */
  729. function __call($method,$arguments)
  730. {
  731. if (($ret=$this->tryCall($method, $arguments))) {
  732. return $ret[0];
  733. }
  734. throw $this->exception(
  735. "Method is not defined for this object", 'Logic'
  736. )
  737. ->addMoreInfo('class', get_class($this))
  738. ->addMoreInfo("method", $method)
  739. ->addMoreInfo("arguments", $arguments);
  740. }
  741. /**
  742. * attempts to call dynamic method, returns array containing result or false
  743. *
  744. * @param string $method Name of the method
  745. * @param array $arguments Arguments
  746. *
  747. * @return mixed
  748. */
  749. function tryCall($method,$arguments)
  750. {
  751. if ($ret=$this->hook('method-'.$method, $arguments)) {
  752. return $ret;
  753. }
  754. array_unshift($arguments, $this);
  755. if (($ret=$this->api->hook('global-method-'.$method, $arguments))) {
  756. return $ret;
  757. }
  758. }
  759. /**
  760. * Add new method for this object
  761. *
  762. * @param string|array $name Name of new method of $this object
  763. * @param callable $callable Callback
  764. *
  765. * @return AbstractObject $this
  766. */
  767. function addMethod($name,$callable)
  768. {
  769. if (is_string($name) && strpos($name, ',')!==false) {
  770. $name=explode(',', $name);
  771. }
  772. if (is_array($name)) {
  773. foreach ($name as $h) {
  774. $this->addMethod($h, $callable);
  775. }
  776. return $this;
  777. }
  778. if (is_object($callable) && !is_callable($callable)) {
  779. $callable=array($callable,$name);
  780. }
  781. if ($this->hasMethod($name)) {
  782. throw $this->exception('Registering method twice');
  783. }
  784. $this->addHook('method-'.$name, $callable);
  785. }
  786. /**
  787. * Return if this object have specified method (either native or dynamic)
  788. *
  789. * @param string $name Name of the method
  790. *
  791. * @return bool
  792. */
  793. function hasMethod($name)
  794. {
  795. return method_exists($this, $name)
  796. || isset($this->hooks['method-'.$name])
  797. || isset($this->api->hooks['global-method-'.$name]);
  798. }
  799. /**
  800. * Remove dynamically registered method
  801. *
  802. * @param string $name Name of the method
  803. *
  804. * @return AbstractObject $this
  805. */
  806. function removeMethod($name)
  807. {
  808. $this->removeHook('method-'.$name);
  809. }
  810. // }}}
  811. // {{{ Logger: to be moved out
  812. /**
  813. * Output string into log file
  814. *
  815. * @param string $var var
  816. * @param string $msg msg
  817. *
  818. * @return void
  819. * @obsolete
  820. */
  821. function logVar($var, $msg="")
  822. {
  823. $this->api->getLogger()->logVar($var, $msg);
  824. }
  825. /**
  826. * Output string into info file
  827. *
  828. * @param string $info info
  829. * @param string $msg msg
  830. *
  831. * @return void
  832. * @obsolete
  833. */
  834. function logInfo($info, $msg="")
  835. {
  836. $this->api->getLogger()->logLine($msg.' '.$info."\n");
  837. }
  838. /**
  839. * Output string into error file
  840. *
  841. * @param string $error error
  842. * @param string $msg msg
  843. *
  844. * @return void
  845. * @obsolete
  846. */
  847. function logError($error,$msg="")
  848. {
  849. if (is_object($error)) {
  850. // we got exception object obviously
  851. $error=$error->getMessage();
  852. }
  853. $this->api->getLogger()->logLine($msg.' '.$error."\n", null, 'error');
  854. }
  855. // }}}
  856. /**
  857. * A handy shortcut for foreach(){ .. } code. Make your callable return
  858. * "false" if you would like to break the loop.
  859. *
  860. * @param callable $callable will be executed for each member
  861. *
  862. * @return AbstractObject $this
  863. */
  864. function each($callable)
  865. {
  866. if (!($this instanceof Iterator)) {
  867. throw $this->exception('Calling each() on non-iterative object');
  868. }
  869. foreach ($this as $value) {
  870. if (call_user_func($callable, $value) === false) {
  871. break;
  872. }
  873. }
  874. return $this;
  875. }
  876. /**
  877. * Method used internally for shortening object names.
  878. *
  879. * @param string $desired Desired name of new objects
  880. *
  881. * @return string shortened name of new object.
  882. */
  883. function _shorten($desired)
  884. {
  885. if (strlen($desired)>$this->api->max_name_length
  886. && $this->api->max_name_length!==false) {
  887. $len=$this->api->max_name_length-10;
  888. if ($len<5) {
  889. $len=$this->api->max_name_length;
  890. }
  891. $key=substr($desired, 0, $len);
  892. $rest=substr($desired, $len);
  893. if (!$this->api->unique_hashes[$key]) {
  894. $this->api->unique_hashes[$key]
  895. =count($this->api->unique_hashes)+1;
  896. }
  897. $desired=$this->api->unique_hashes[$key].'__'.$rest;
  898. };
  899. return $desired;
  900. }
  901. /**
  902. * This funcion given the associative $array and desired new key will return
  903. * the best matching key which is not yet in the arary. For example if you have
  904. * array('foo'=>x,'bar'=>x) and $desired is 'foo' function will return 'foo_2'.
  905. * If 'foo_2' key also exists in that array, then 'foo_3' is returned and so on.
  906. *
  907. * @param array &$array Reference to array which stores key=>value pairs
  908. * @param string $desired Desired key for new object
  909. *
  910. * @return string unique key for new object
  911. */
  912. function _unique(&$array,$desired=null)
  913. {
  914. $postfix=1;
  915. $attempted_key=$desired;
  916. if (!is_array($array)) {
  917. throw $this->exception('not array');
  918. }
  919. while (array_key_exists($attempted_key, $array)) {
  920. // already used, move on
  921. $attempted_key=($desired?$desired:'undef').'_'.(++$postfix);
  922. }
  923. return $attempted_key;
  924. }
  925. /** Always call parent if you redefine this */
  926. function __destruct()
  927. {
  928. }
  929. /**
  930. * Do not serialize objects
  931. *
  932. * @return mixed
  933. */
  934. function __sleep()
  935. {
  936. return array('name');
  937. }
  938. }