PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/extensions/pogostick/base/CPSComponent.php

http://ps-yii-extensions.googlecode.com/
PHP | 393 lines | 178 code | 41 blank | 174 comment | 28 complexity | b704545d698352c57ab07dc0964f62fb MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the psYiiExtensions package.
  4. *
  5. * @copyright Copyright &copy; 2009-2010 Pogostick, LLC
  6. * @link http://www.pogostick.com Pogostick, LLC.
  7. * @license http://www.pogostick.com/licensing
  8. */
  9. /**
  10. * CPSComponent is the base class for all psYiiExtensions.
  11. * It contains functionality to call behavior methods without the need for chaining.
  12. * All PSComponents have a preinit() method that is called during construction.
  13. *
  14. * @package psYiiExtensions
  15. * @subpackage base
  16. *
  17. * @author Jerry Ablan <jablan@pogostick.com>
  18. * @version SVN $Id: CPSComponent.php 406 2010-11-08 15:30:07Z jerryablan@gmail.com $
  19. * @since v1.0.0
  20. *
  21. * @filesource
  22. *
  23. * @property-read string $internalName The internal name of the component.
  24. * @property boolean $debugMode Enable trace-level debugging
  25. */
  26. class CPSComponent extends CApplicationComponent implements IPSComponent
  27. {
  28. //********************************************************************************
  29. //* Properties
  30. //********************************************************************************
  31. /**
  32. * The internal name of the component.
  33. * @var string
  34. */
  35. protected $_internalName;
  36. public function getInternalName() { return $this->_internalName; }
  37. public function setInternalName( $value ) { $this->_internalName = $value; }
  38. /**
  39. * Tracks the status of debug mode for component
  40. * @var boolean Enable/disable debug mode
  41. */
  42. protected $_debugMode = false;
  43. public function getDebugMode() { return $this->_debugMode; }
  44. public function setDebugMode( $value ) { $this->_debugMode = $value; }
  45. //********************************************************************************
  46. //* Member Variables
  47. //********************************************************************************
  48. /**
  49. * Tracks if this component has been initialized yet.
  50. * @var boolean
  51. */
  52. protected $_initialized = false;
  53. /**
  54. * Our behaviors. Cached for speed here...
  55. * @var array
  56. */
  57. protected $_behaviorList = array();
  58. //********************************************************************************
  59. //* Yii Overrides
  60. //********************************************************************************
  61. /**
  62. * Constructs a component.
  63. */
  64. public function __construct( $config = array() )
  65. {
  66. // Set any properties via standard config array
  67. if ( is_array( $config ) && ! empty( $config ) )
  68. $this->_loadConfiguration( $config );
  69. // Preinitialize, called before afterConstruct
  70. $this->preinit();
  71. }
  72. /**
  73. * Preinitialize the component
  74. * Override to add your own functionality before init() is called.
  75. */
  76. public function preinit()
  77. {
  78. // Create our internal name
  79. PS::createInternalName( $this );
  80. // Attach our default Behavior
  81. $this->attachBehavior( 'psComponent', 'pogostick.behaviors.CPSComponentBehavior' );
  82. }
  83. /**
  84. * Initialize our component.
  85. */
  86. public function init()
  87. {
  88. if ( ! $this->_initialized )
  89. {
  90. // Now call parent's init...
  91. parent::init();
  92. // Call our behaviors init()
  93. foreach ( $this->_behaviorList as $_name )
  94. $this->asa( $_name )->init();
  95. // We are now...
  96. $this->_initialized = true;
  97. }
  98. }
  99. /**
  100. * Attaches an Behavior to this component.
  101. * This method will create the Behavior object based on the given
  102. * configuration. After that, the Behavior object will be initialized
  103. * by calling its {@link IPSBehavior::attach} method.
  104. *
  105. * @param string $name the Behavior's name. It should uniquely identify this Behavior.
  106. * @param mixed $behavior the Behavior configuration. This is passed as the first parameter to {@link YiiBase::createComponent} to create the Behavior object.
  107. * @return IPSBehavior the Behavior object
  108. */
  109. public function attachBehavior( $name, $behavior )
  110. {
  111. // Attach the Behavior at the parent and add options here, then cache
  112. if ( null !== ( $_component = parent::attachBehavior( $name, $behavior ) ) )
  113. $this->_behaviorList[] = $name;
  114. return $_component;
  115. }
  116. /**
  117. * Alias for setOptions
  118. * @param array $optionList
  119. * @see setOptions
  120. */
  121. public function configure( $optionList = array() )
  122. {
  123. $this->setOptions( $optionList );
  124. }
  125. /**
  126. * Determines whether a property can be read.
  127. * A property can be read if the class has a getter method
  128. * for the property name. Note, property name is case-insensitive.
  129. * @param string the property name
  130. * @return boolean whether the property can be read
  131. * @see canSetProperty
  132. */
  133. public function canGetProperty( $name )
  134. {
  135. parent::canGetProperty( $name ) || $this->hasProperty( $name );
  136. }
  137. /**
  138. * Determines whether a property can be set.
  139. * A property can be written if the class has a setter method
  140. * for the property name. Note, property name is case-insensitive.
  141. * @param string the property name
  142. * @return boolean whether the property can be written
  143. * @see canGetProperty
  144. */
  145. public function canSetProperty( $name )
  146. {
  147. parent::canSetProperty( $name ) || $this->hasProperty( $name );
  148. }
  149. /**
  150. * Determines whether a property is defined.
  151. * A property is defined if there is a getter or setter method
  152. * defined in the class. Note, property names are case-insensitive.
  153. * @param string the property name
  154. * @return boolean whether the property is defined
  155. * @see canGetProperty
  156. * @see canSetProperty
  157. */
  158. public function hasProperty( $name )
  159. {
  160. if ( parent::hasProperty( $name ) )
  161. return true;
  162. foreach ( $this->_behaviorList as $_behaviorName )
  163. {
  164. if ( ( $_behavior = $this->asa( $_behaviorName ) ) instanceof IPSOptionContainer && $_behavior->contains( $name ) && $_behavior->getEnabled() )
  165. return true;
  166. }
  167. return false;
  168. }
  169. //********************************************************************************
  170. //* Magic Methods
  171. //********************************************************************************
  172. /**
  173. * Gets an option from the collection or passes through to parent.
  174. * @param string $name the option, property or event name
  175. * @return mixed
  176. * @throws CException if the property or event is not defined
  177. * @see __set
  178. */
  179. public function __get( $name )
  180. {
  181. try
  182. {
  183. return parent::__get( $name );
  184. }
  185. catch ( CException $_ex )
  186. {
  187. // Didn't work. Try our behavior cache...
  188. foreach ( $this->_behaviorList as $_behaviorName )
  189. {
  190. if ( ( $_behavior = $this->asa( $_behaviorName ) ) instanceof IPSOptionContainer && $_behavior->contains( $name ) )
  191. return $_behavior->getValue( $name );
  192. }
  193. // If we get here, then bubble the exception...
  194. throw $_ex;
  195. }
  196. }
  197. /**
  198. * Sets value of a component option or property.
  199. * @param string $name the property, option or event name
  200. * @param mixed $oValue the property value or callback
  201. * @throws CException if the property/event is not defined or the property is read only.
  202. * @see __get
  203. */
  204. public function __set( $name, $value )
  205. {
  206. try
  207. {
  208. parent::__set( $name, $value );
  209. }
  210. catch ( CException $_ex )
  211. {
  212. // Didn't work. Try our behavior cache...
  213. foreach ( $this->_behaviorList as $_behaviorName )
  214. {
  215. if ( ( $_behavior = $this->asa( $_behaviorName ) ) instanceof IPSOptionContainer && $_behavior->contains( $name ) )
  216. return $_behavior->setValue( $name, $value );
  217. }
  218. // If we get here, then bubble the exception...
  219. throw $_ex;
  220. }
  221. }
  222. /**
  223. * Test to see if an option is set.
  224. * @param string $name
  225. */
  226. public function __isset( $name )
  227. {
  228. // Then behaviors
  229. foreach ( $this->_behaviorList as $_behavior )
  230. {
  231. if ( ( $_component = $this->asa( $_behavior ) ) instanceof IPSOptionContainer && $_component->contains( $name ) )
  232. return $_component->getValue( $name ) !== null;
  233. }
  234. return parent::__isset( $name );
  235. }
  236. /**
  237. * Unset an option
  238. * @param string $name
  239. */
  240. public function __unset( $name )
  241. {
  242. // Then behaviors
  243. foreach ( $this->_behaviorList as $_behavior )
  244. {
  245. if ( ( $_component = $this->asa( $_behavior ) ) instanceof IPSOptionContainer && $_component->contains( $name ) )
  246. {
  247. $_component->unsetOption( $name );
  248. return;
  249. }
  250. }
  251. // Try dad
  252. parent::__unset( $name );
  253. }
  254. /**
  255. * Calls the named method which is not a class method.
  256. * Do not call this method. This is a PHP magic method that we override
  257. * @param string $name The method name
  258. * @param array $parameterList The method parameters
  259. * @throws CPSOptionException if the property/event is not defined or the property is read only.
  260. * @see __call
  261. * @return mixed The method return value
  262. */
  263. public function __call( $name, $parameterList )
  264. {
  265. $_oEvent = null;
  266. try
  267. {
  268. // Look for behavior methods
  269. foreach ( $this->_behaviorList as $_behavior )
  270. {
  271. if ( $_component = $this->asa( $_behavior ) )
  272. {
  273. if ( method_exists( $_component, $name ) )
  274. return call_user_func_array( array( $_component, $name ), $parameterList );
  275. }
  276. }
  277. }
  278. catch ( CPSOptionException $_ex ) { /* Ignore and pass through */ }
  279. // Pass on to dad
  280. return parent::__call( $name, $parameterList );
  281. }
  282. /**
  283. * Checks if a component has an attached behavior
  284. * @param string $class
  285. * @returns boolean
  286. */
  287. public function hasBehavior( $class )
  288. {
  289. // Look for behavior methods
  290. foreach ( $this->_behaviorList as $_behavior )
  291. {
  292. if ( null !== ( $_component = $this->asa( $_behavior ) ) )
  293. {
  294. if ( $_component instanceof $class )
  295. return true;
  296. }
  297. // Check for nicknames...
  298. if ( $class == $_behavior )
  299. return true;
  300. }
  301. // Nope?
  302. return false;
  303. }
  304. /**
  305. * Outputs a debug string if in debug mode.
  306. * @param <type> $message The message
  307. * @param <type> $category The category/method of the output
  308. * @param <type> $route The destination of output. Can be 'echo', 'trace|info|error|debug|etc...', 'http', 'firephp'
  309. */
  310. public function _debug( $message, $category = null, $route = null )
  311. {
  312. if ( $this->_debugMode )
  313. echo $message . '<BR />';
  314. }
  315. //********************************************************************************
  316. //* Private Methods
  317. //********************************************************************************
  318. /**
  319. * Loads an array into properties if they exist.
  320. * @param array $optionList
  321. */
  322. protected function _loadConfiguration( $optionList = array(), $overwriteExisting = true )
  323. {
  324. // Make a copy for posterity
  325. if ( property_exists( $this, '_optionList' ) )
  326. {
  327. if ( $overwriteExisting || empty( $this->_optionList ) )
  328. $this->_optionList = $optionList;
  329. else
  330. $this->_optionList = array_merge( $this->_optionList, $optionList );
  331. }
  332. try
  333. {
  334. foreach ( $optionList as $_option => $_value )
  335. {
  336. try
  337. {
  338. // See if __set has a better time with this...
  339. $this->{$_option} = $_value;
  340. }
  341. catch ( Exception $_ex )
  342. {
  343. // Completely ignore errors...
  344. }
  345. }
  346. }
  347. catch ( Exception $_ex )
  348. {
  349. CPSLog::error( __METHOD__, 'Error while loading configuration options: ' . $_ex->getMessage() );
  350. }
  351. }
  352. }