2 /* vim: set expandtab shiftwidth=4 softtabstop=4 tabstop=4 foldmethod=marker: */
5 * TIP_Type definition file
7 * LICENSE: This source file is subject to the New BSD license that is
8 * available through the world-wide-web at the following URI:
9 * http://www.opensource.org/licenses/bsd-license.php
10 * If you did not receive a copy of the New BSD License and are unable to
11 * obtain it through the web, please send a note to license@php.net so we
12 * can mail you a copy immediately.
14 * @author Nicola Fontana <ntd@entidi.it>
15 * @copyright Copyright © 2006-2008 Nicola Fontana
16 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License
24 * Manages all the instantiable TIP objects (types).
25 * Inheriting a class from TIP_Type gives the ability to instantiate this
26 * class only when requested (usually throught a call to getInstance()).
27 * Multiple requests to getInstance() will references the same - unique -
28 * instantiated object.
30 * Also, the PHP file declaring the new type will be included only
31 * when required, enabling a real modular environement.
35 abstract class TIP_Type
46 * An array of parent classes (without TIP_PREFIX)
49 protected $type = null;
52 //{{{ Constructor/destructor
57 * Overridable static method that checks $options for missing or invalid
58 * values and eventually corrects its content.
60 * @param array &$options Property values
61 * @return bool true on success or false on error
63 static protected function checkOptions(&$options)
65 if (!isset($options['type'])) {
69 isset($options['id']) ||
$options['id'] = end($options['type']);
76 * Initializes a TIP_Type instance.
78 * Basically, this class set the properties values by parsing the $options
81 * @param array $options Properties values
83 protected function __construct($options)
85 // Properties initialization
86 foreach ($options as $property => &$value) {
87 $this->$property =& $value;
92 * Overridable post construction method
94 * Called after the construction happened. This can be overriden to do some
95 * other post costruction operation.
97 * The TIP_Type::postConstructor() method does nothing.
99 protected function postConstructor()
109 * Manages the singletons. Given a hierarchy of parent types and a string
110 * identifier, this method returns a singleton of the instantiated object.
111 * If the object is not found, it is dinamically defined and instantiated.
113 * The singletons are stored in a static tree, called register, containing
114 * all the hierarchy of the instantiated types.
116 * If $options is not specified, the whole register is returned.
118 * If $options is a string, it must specify a valid type: a partial
119 * register content of this type is returned.
121 * In the other cases, $options must be an array of options, and a
122 * singleton for the specified object is returned. In this situation,
123 * $options must have at least the following items:
124 * - $options['id']: the instance identifier
125 * - $options['type']: an array containing the parent types of the instance.
126 * These types must be lowercase strings specifying the
127 * parent classes of the instance (TIP_Type excluded)
128 * without TIP_PREFIX. Using array('module', 'content'),
129 * for instance, will instantiate a TIP_Content object.
131 * Some type automatically fills $options['id'] after the checkOptions()
132 * call: check the documentation for each class for further information.
134 * @param array|string|null $options Constructor options
135 * @param bool $dont_store Don't store the instance
137 * @return array|object|null The register content, a reference
138 * to the requested instance or null
139 * on instantiation errors
141 static protected function &singleton($options = null, $dont_store = false)
143 static $register = array();
144 static $flat_register = array();
146 if (empty($options)) {
147 // Return the whole register content
149 } elseif (is_string($options)) {
150 // Return a partial register content
151 return $flat_register[$options];
154 $type = end($options['type']);
155 if (array_key_exists($type, $flat_register)) {
156 // Hierarchy yet defined
157 $list =& $flat_register[$type];
158 } elseif (array_key_exists('include', $options)) {
159 // Explicit include file: suppose the parents are yet defined
160 if (include_once $options['include']) {
161 $list[$type] = array();
162 $flat_register[$type] =& $list[$type];
164 // Definition impossible: this avoid next attempts
166 $list[$type] = $flat_register[$type] = null;
169 $list =& $list[$type];
171 // Hierarchy to be defined
172 $path = TIP
::buildLogicPath('Type');
175 foreach ($options['type'] as $type) {
176 $path .= DIRECTORY_SEPARATOR
. $type;
177 if (!array_key_exists($type, $list)) {
178 // Dynamic type definition
179 $file = $path . '.php';
180 if (include_once $file) {
181 $list[$type] = array();
182 $flat_register[$type] =& $list[$type];
184 // Definition impossible: this avoid next attempts
185 $list[$type] = $flat_register[$type] = null;
189 $list =& $list[$type];
193 $class = TIP_PREFIX
. $type;
194 if (!call_user_func_array(array($class, 'checkOptions'), array(&$options))) {
195 // Invalid options, maybe a requested option is not specified
201 $instance = new $class($options);
202 $instance->postConstructor();
204 $id = $options['id'];
205 if (!array_key_exists($id, $list)) {
206 // Object instantiation
207 $instance = new $class($options);
210 $list[$id] =& $instance;
212 // postConstructor() call: must be done after the registration
213 // to avoid circular dependency
214 $instance->postConstructor();
216 $instance =& $list[$id];
226 * Gets the singleton of a configured object. $id could be any identifier
227 * defined in $GLOBALS['cfg'].
229 * An internal register is mantained to avoid singleton() calls with the
232 * @param mixed $id Instance identifier
233 * @param bool $required true if errors must be fatals
234 * @return TIP_Type The reference to the requested instance or
237 static public function &getInstance($id, $required = true)
239 static $register = array();
242 $id = strtolower($id);
243 if (class_exists('TIP_Application')) {
244 $namespace = TIP_Application
::getGlobal('namespace');
245 if (!empty($namespace) && isset($cfg[$namespace . '_' . $id])) {
246 $id = $namespace . '_' . $id;
250 if (array_key_exists($id, $register)) {
251 return $register[$id];
254 if (isset($cfg[$id])) {
255 $options = $cfg[$id];
256 isset($options['id']) ||
$options['id'] = $id;
257 $instance =& TIP_Type
::singleton($options);
262 if (is_null($instance) && $required) {
263 TIP
::fatal("unable to instantiate the requested object ($id)");
267 $register[$id] =& $instance;
272 * Return the id of a TIP instance
273 * @return string The instance identifier
275 public function __toString()
281 * Get the type of a TIP instance
283 * Returns the type of the current - instantiated - TIP object. This
284 * function simply gets the class name (in lowercase) and strips the
285 * TIP_PREFIX from the string.
287 * The result is converted to lowecase to avoid discrepancies between
288 * different PHP versions.
290 * @return string The type name
292 public function getType()
294 return end($this->type
);
298 * Get a property of this instance
300 * @param string $property The property name
301 * @return mixed|null The property value or null on errors
303 public function &getProperty($property)
305 return $this->$property;
309 * Get a global option for the current instance
311 * Wrappers the more general TIP::getOption() function without the need to
314 * @param string $option The option to retrieve
315 * @return mixed|null The value of the requested option or null on errors
317 public function getOption($option)
319 return @$GLOBALS['cfg'][$this->id
][$option];