2 // vim: foldmethod=marker
6 * @author Masaki Fujimoto <fujimoto@php.net>
7 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
12 // {{{ Ethna_ClassFactory
14 * Ethnaフレームワークのオブジェクト生成ゲートウェイ
16 * DIコンテナか、ということも考えましたがEthnaではこの程度の単純なものに
17 * 留めておきます。アプリケーションレベルDIしたい場合はフィルタチェインを
20 * @author Masaki Fujimoto <fujimoto@php.net>
24 class Ethna_ClassFactory
30 /** @var object Ethna_Controller controllerオブジェクト */
33 /** @var object Ethna_Controller controllerオブジェクト(省略形) */
36 /** @var array クラス定義 */
39 /** @var array 生成済みオブジェクトキャッシュ */
40 var $object = array();
42 /** @var array 生成済みアプリケーションマネージャオブジェクトキャッシュ */
43 var $manager = array();
45 /** @var array メソッド一覧キャッシュ */
46 var $method_list = array();
52 * Ethna_ClassFactoryクラスのコンストラクタ
55 * @param object Ethna_Controller &$controller controllerオブジェクト
56 * @param array $class クラス定義
58 public function __construct(&$controller, $class)
60 $this->controller = $controller;
61 $this->ctl = $controller;
62 $this->class = $class;
66 * typeに対応するアプリケーションマネージャオブジェクトを返す
67 * 注意: typeは大文字小文字を区別しない
68 * (PHP自体が、クラス名の大文字小文字を区別しないため)
71 * @param string $type アプリケーションマネージャー名
72 * @param bool $weak オブジェクトが未生成の場合の強制生成フラグ(default: false)
73 * @return object Ethna_AppManager マネージャオブジェクト
75 function getManager($type, $weak = false)
79 // すでにincludeされていなければ、includeを試みる
80 // ここで返されるクラス名は、AppObjectの命名規約によるもの
82 // これは、AppObject のファイル中にAppManagerが含まれる場合が
84 $obj_class_name = $this->controller->getObjectClassName($type);
85 if (class_exists($obj_class_name) === false) {
86 $this->_include($obj_class_name);
89 // すでにincludeされていなければ、includeを試みる
90 // ここで返されるクラス名は、AppManagerの命名規約によるもの
91 $class_name = $this->controller->getManagerClassName($type);
92 if (class_exists($class_name) === false
93 && $this->_include($class_name) === false) {
94 return $obj; // include 失敗。戻り値はNULL。
98 if (isset($this->method_list[$class_name]) == false) {
99 $this->method_list[$class_name] = get_class_methods($class_name);
100 for ($i = 0; $i < count($this->method_list[$class_name]); $i++) {
101 $this->method_list[$class_name][$i] = strtolower($this->method_list[$class_name][$i]);
105 // PHPのクラス名は大文字小文字を区別しないので、
106 // 同じクラス名と見做されるものを指定した場合には
108 $type = strtolower($type);
110 // 以下のルールに従って、キャッシュが利用可能かを判定する
111 // 利用可能と判断した場合、キャッシュされていればそれを返す
113 // 1. メソッドに getInstance があればキャッシュを利用可能と判断する
114 // この場合、シングルトンかどうかは getInstance 次第
115 // 2. weak が true であれば、キャッシュは利用不能と判断してオブジェクトを再生成
116 // 3. weak が false であれば、キャッシュは利用可能と判断する(デフォルト)
117 if ($this->_isCacheAvailable($class_name, $this->method_list[$class_name], $weak)) {
118 if (isset($this->manager[$type]) && is_object($this->manager[$type])) {
119 return $this->manager[$type];
123 // インスタンス化のヘルパ(getInstance)があればそれを使う
124 if (in_array("getinstance", $this->method_list[$class_name])) {
125 $obj = call_user_func(array($class_name, 'getInstance'));
127 $backend = $this->controller->getBackend();
128 $obj = new $class_name($backend);
131 // 生成したオブジェクトはとりあえずキャッシュする
132 if (isset($this->manager[$type]) == false || is_object($this->manager[$type]) == false) {
133 $this->manager[$type] = $obj;
140 * クラスキーに対応するオブジェクトを返す/クラスキーが未定義の場合はAppObjectを探す
141 * クラスキーとは、[Appid]_Controller#class に定められたもの。
144 * @param string $key [Appid]_Controller#class に定められたクラスキー
147 * @param bool $ext オブジェクトが未生成の場合の強制生成フラグ(default: false)
148 * @return object 生成されたオブジェクト(エラーならnull)
150 function getObject($key, $ext = false)
154 $ext = to_array($ext);
155 if (isset($this->class[$key]) == false) {
157 $class_name = $this->controller->getObjectClassName($key);
158 $ext = array_pad($ext, 3, null);
159 list($key_type, $key_value, $prop) = $ext;
162 $class_name = $this->class[$key];
163 $ext = array_pad($ext, 1, null);
167 // すでにincludeされていなければ、includeを試みる
168 if (class_exists($class_name) == false) {
169 if ($this->_include($class_name) == false) {
170 return $object; // include 失敗。返り値はnull
175 // AppObject はキャッシュされないことに注意
176 if (isset($this->class[$key]) == false) {
177 $backend = $this->controller->getBackend();
178 $object = new $class_name($backend, $key_type, $key_value, $prop);
182 // Ethna_Controllerで定義されたクラスキーの場合
184 if (isset($this->method_list[$class_name]) == false) {
185 $this->method_list[$class_name] = get_class_methods($class_name);
186 for ($i = 0; $i < count($this->method_list[$class_name]); $i++) {
187 $this->method_list[$class_name][$i] = strtolower($this->method_list[$class_name][$i]);
191 // 以下のルールに従って、キャッシュが利用可能かを判定する
192 // 利用可能と判断した場合、キャッシュされていればそれを返す
194 // 1. メソッドに getInstance があればキャッシュを利用可能と判断する
195 // この場合、シングルトンかどうかは getInstance 次第
196 // 2. weak が true であれば、キャッシュは利用不能と判断してオブジェクトを再生成
197 // 3. weak が false であれば、キャッシュは利用可能と判断する(デフォルト)
198 if ($this->_isCacheAvailable($class_name, $this->method_list[$class_name], $weak)) {
199 if (isset($this->object[$key]) && is_object($this->object[$key])) {
200 return $this->object[$key];
204 // インスタンス化のヘルパがあればそれを使う
205 $method = sprintf('_getObject_%s', ucfirst($key));
206 if (method_exists($this, $method)) {
207 $object = $this->$method($class_name);
208 } else if (in_array("getinstance", $this->method_list[$class_name])) {
209 $object = call_user_func(array($class_name, 'getInstance'));
211 $object = new $class_name();
214 // クラスキーに定められたクラスのインスタンスは
216 if (isset($this->object[$key]) == false || is_object($this->object[$key]) == false) {
217 $this->object[$key] = $object;
227 * @param string $key クラスキー
228 * @return string クラス名
230 function getObjectName($key)
232 if (isset($this->class[$key]) == false) {
236 return $this->class[$key];
240 * オブジェクト生成メソッド(backend)
243 * @param string $class_name クラス名
244 * @return object 生成されたオブジェクト(エラーならnull)
246 function _getObject_Backend($class_name)
248 $_ret_object = new $class_name($this->ctl);
253 * オブジェクト生成メソッド(config)
256 * @param string $class_name クラス名
257 * @return object 生成されたオブジェクト(エラーならnull)
259 function _getObject_Config($class_name)
261 $_ret_object = new $class_name($this->ctl);
269 * @param string $class_name クラス名
270 * @return object 生成されたオブジェクト(エラーならnull)
272 function _getObject_I18n($class_name)
274 $_ret_object = new $class_name($this->ctl->getDirectory('locale'), $this->ctl->getAppId());
279 * オブジェクト生成メソッド(logger)
282 * @param string $class_name クラス名
283 * @return object 生成されたオブジェクト(エラーならnull)
285 function _getObject_Logger($class_name)
287 $_ret_object = new $class_name($this->ctl);
292 * オブジェクト生成メソッド(plugin)
295 * @param string $class_name クラス名
296 * @return object 生成されたオブジェクト(エラーならnull)
298 function _getObject_Plugin($class_name)
300 $_ret_object = new $class_name($this->ctl);
305 * オブジェクト生成メソッド(renderer)
308 * @param string $class_name クラス名
309 * @return object 生成されたオブジェクト(エラーならnull)
311 function _getObject_Renderer($class_name)
313 $_ret_object = new $class_name($this->ctl);
318 * オブジェクト生成メソッド(session)
321 * @param string $class_name クラス名
322 * @return object 生成されたオブジェクト(エラーならnull)
324 function _getObject_Session($class_name)
326 $_ret_object = new $class_name($this->ctl, $this->ctl->getAppId());
334 * @param string $class_name クラス名
335 * @return object 生成されたオブジェクト(エラーならnull)
337 function _getObject_Sql($class_name)
339 $_ret_object = new $class_name($this->ctl);
344 * 指定されたクラスから想定されるファイルをincludeする
348 function _include($class_name)
350 $file = sprintf("%s.%s", $class_name, $this->controller->getExt('php'));
351 if (file_exists_ex($file)) {
356 if (preg_match('/^(\w+?)_(.*)/', $class_name, $match)) {
357 // try ethna app style
358 // App_Foo_Bar_Baz -> Foo/Bar/App_Foo_Bar_Baz.php
359 $tmp = explode("_", $match[2]);
360 $tmp[count($tmp)-1] = $class_name;
361 $file = sprintf('%s.%s',
362 implode(DIRECTORY_SEPARATOR, $tmp),
363 $this->controller->getExt('php'));
364 if (file_exists_ex($file)) {
369 // try ethna app & pear mixed style
370 // App_Foo_Bar_Baz -> Foo/Bar/Baz.php
371 $file = sprintf('%s.%s',
372 str_replace('_', DIRECTORY_SEPARATOR, $match[2]),
373 $this->controller->getExt('php'));
374 if (file_exists_ex($file)) {
379 // try ethna master style
380 // Ethna_Foo_Bar -> class/Ethna/Foo/Bar.php
381 $tmp = explode('_', $match[2]);
382 array_unshift($tmp, 'Ethna', 'class');
383 $file = sprintf('%s.%s',
384 implode(DIRECTORY_SEPARATOR, $tmp),
385 $this->controller->getExt('php'));
386 if (file_exists_ex($file)) {
392 // Foo_Bar_Baz -> Foo/Bar/Baz.php
393 $file = sprintf('%s.%s',
394 str_replace('_', DIRECTORY_SEPARATOR, $class_name),
395 $this->controller->getExt('php'));
396 if (file_exists_ex($file)) {
405 * 指定されたクラスがキャッシュを利用可能かどうかをチェックする
409 function _isCacheAvailable($class_name, $method_list, $weak)
411 // if we have getInstance(), use this anyway
412 if (in_array('getinstance', $method_list)) {
416 // if not, see if weak or not
417 return $weak ? false : true;