1: <?php
2: /**
3: * Wei Framework
4: *
5: * @copyright Copyright (c) 2008-2013 Twin Huang
6: * @license http://opensource.org/licenses/mit-license.php MIT License
7: */
8:
9: namespace Wei
10: {
11: /**
12: * @see Wei\Base
13: */
14: require_once 'Base.php';
15:
16: /**
17: * The service container
18: *
19: * @author Twin Huang <twinhuang@qq.com>
20: *
21: * Cache
22: * @property Cache $cache A cache service proxy
23: * @method mixed cache($key, $value = null, $expire = 0) Retrieve or store an item by cache
24: * @property ArrayCache $arrayCache A cache service that stored data in PHP array
25: * @method mixed arrayCache($key, $value = null, $expire = 0) Retrieve or store an item by array cache
26: * @property Apc $apc A cache service that stored data in PHP APC
27: * @method mixed apc($key, $value = null, $expire = 0) Retrieve or store an item
28: * @property DbCache $dbCache A cache service that stored data in databases
29: * @method mixed dbCache($key, $value = null, $expire = 0) Retrieve or store an item by database cache
30: * @property FileCache $fileCache A cache service that stored data in files
31: * @method mixed fileCache($key, $value = null, $expire = 0) Retrieve or store an item by file
32: * @property Memcache $memcache A cache service that stored data in Memcache
33: * @method mixed memcache($key, $value = null, $expire = 0) Retrieve or store an item by Memcache
34: * @property Memcached $memcached A cache service that stored data in Memcached
35: * @method mixed memcached($key, $value = null, $expire = 0) Retrieve or store an item by Memcached
36: * @property MongoCache $mongoCache A cache service that stores data in MongoDB
37: * @method mixed mongoCache($key, $value = null, $expire = 0) Retrieve or store an item by MongoDB
38: * @property Couchbase $couchbase A cache service base on Couchbase
39: * @method mixed couchbase($key, $value = null, $expire = 0) Retrieve or store an item by Couchbase
40: * @property Redis $redis A cache service that stores data in Redis
41: * @method mixed redis($key = null, $value = null, $expire = 0) Retrieve or store an item by Redis
42: * @property Bicache $bicache A two-level cache service
43: * @method mixed bicache($key, $value = null, $expire = 0) Retrieve or store an item by two-level cache
44: *
45: * Database
46: * @property Db $db A database service inspired by Doctrine DBAL
47: * @method \Wei\Record db($table = null) Create a new record object
48: *
49: * HTTP Client
50: * @property Http $http An alias of call service
51: * @method \Wei\Http http(array $options) Create a new HTTP service and execute
52: *
53: * HTTP Request
54: * @property Request $request A service that handles the HTTP request data
55: * @method mixed request($name, $default = null) Returns a stringify request parameter value
56: * @property Cookie $cookie A object that handles the HTTP request and response cookies
57: * @method mixed cookie($key, $value = null, $options = array()) Get or set cookie
58: * @property Session $session A object that session parameters ($_SESSION)
59: * @method mixed session($name, $default = null) Returns a stringify session parameter value
60: * @property Ua $ua A object to detect user OS, device and browser name and version
61: * @method bool ua() Check if in the specified browser, OS or device
62: * @property Upload $upload A object that handles the uploaded files
63: * @method bool upload(array $options = array()) Upload a file
64: *
65: * HTTP Response
66: * @property Response $response A object that handles the HTTP response data
67: * @method \Wei\Response response($content = null, $status = null) Send response header and content
68: *
69: * View
70: * @property View $view A object that use to render PHP template
71: * @method string view($name = null, $vars = array()) Returns view object or render a PHP template
72: * @property Asset $asset A service to generate assets' URL
73: * @method string asset($file) Returns the asset URL by specified file
74: * @property E $e A object to escape HTML, javascript, CSS, HTML Attribute and URL for secure output
75: * @method string e($string, $type = 'html') Escapes a string by specified type for secure output
76: *
77: * Application
78: * @property App $app An MVC application service
79: * @method \Wei\App app(array $options = array()) Startup an MVC application
80: * @property WeChatApp $weChatApp A object handles WeChat(WeiXin) callback message
81: * @method \Wei\WeChatApp weChatApp() Start up WeChat application and output the matched rule message
82: * @property Router $router A object that build a simple REST application
83: * @method \Wei\Router router($pathInfo = null, $method = null) Run the application
84: * @property Url $url A util object to build URL
85: * @method string url($uri) Build URL by specified uri and parameters
86: *
87: * Other
88: * @property Config $config A object to manage object configurations
89: * @property Counter $counter A counter service
90: * @property Env $env A object to detect the environment name and load configuration by environment name
91: * @method string env() Returns the environment name
92: * @property Error $error A object that handles exception and display pretty exception message
93: * @method \Wei\Error error($fn) Attach a handler to exception error
94: * @property Gravatar $gravatar A object that generates a Gravatar URL for a specified email address
95: * @method string gravatar($email, $size = null, $default = null, $rating = null) Generates a Gravatar URL for a specified email address
96: * @property Lock $lock A service that provide the functionality of exclusive Lock
97: * @method bool lock($key) Acquire a lock key
98: * @property Logger $logger A logger service, which is inspired by Monolog
99: * @method bool logger($level, $message) Logs with an arbitrary level
100: * @property Password $password A wrapper class for password hashing functions
101: * @property Pinyin $pinyin An util object that converts Chinese words to phonetic alphabets
102: * @method string pinyin($word) Converts Chinese words to phonetic alphabets
103: * @property SafeUrl $safeUrl Generate a URL with signature
104: * @property Uuid $uuid A util object that generates a RANDOM UUID(universally unique identifier)
105: * @method string uuid() generates a RANDOM UUID(universally unique identifier)
106: * @property T $t A translator object
107: * @method string t($message, array $parameters = array()) Translate the message
108: *
109: * Validation
110: * @method \Wei\Validate validate(array $option) Create a new validator and validate by specified options
111: *
112: * Data type and composition
113: * @property Validator\Alnum $isAlnum
114: * @method bool isAlnum($input) Check if the input contains letters (a-z) and digits (0-9)
115: * @property Validator\Alpha $isAlpha
116: * @method bool isAlpha($input) Check if the input contains only letters (a-z)
117: * @property Validator\Blank $isBlank
118: * @method bool isBlank($input) Check if the input is blank
119: * @property Validator\Contains $isContains
120: * @method bool isContains($input, $search, $regex = false) Check if the input is contains the specified string or pattern
121: * @property Validator\Decimal $isDecimal
122: * @method bool isDecimal($input) Check if the input is decimal
123: * @property Validator\Digit $isDigit
124: * @method bool isDigit($input) Check if the input contains only digits (0-9)
125: * @property Validator\DivisibleBy $isDivisibleBy
126: * @method bool isDivisibleBy($input, $divisor) Check if the input could be divisible by specified divisor
127: * @property Validator\DoubleByte $isDoubleByte
128: * @method bool isDoubleByte($input) Check if the input contains only double characters
129: * @property Validator\Present $isPresent
130: * @method bool isPresent($input) Check if the input is empty
131: * @property Validator\EndsWith $isEndsWith
132: * @method bool isEndsWith($input, $findMe, $case = false) Check if the input is ends with specified string
133: * @property Validator\In $isIn
134: * @method bool isIn($input, array $array, $strict = false) Check if the input is in specified array
135: * @property Validator\Lowercase $isLowercase
136: * @method bool isLowercase($input) Check if the input is lowercase
137: * @property Validator\Luhn $isLuhn
138: * @method bool isLuhn($input) Check if the input is valid by the Luhn algorithm
139: * @property Validator\NaturalNumber $isNaturalNumber
140: * @method bool isNaturalNumber($input) Check if the input is a natural number (integer that greater than or equals 0)
141: * @property Validator\Null $isNull
142: * @method bool isNull($input) Check if the input is null
143: * @property Validator\Number $isNumber
144: * @method bool isNumber($input) Check if the input is number
145: * @property Validator\PositiveInteger $isPositiveInteger
146: * @method bool isPositiveInteger($input) Check if the input is a positive integer (integer that greater than 0)
147: * @property Validator\Regex $isRegex
148: * @method bool isRegex($input, $pattern) Check if the input is valid by specified regular expression
149: * @property Validator\StartsWith $isStartsWith
150: * @method bool isStartsWith($input, $findMe, $case = false) Check if the input is starts with specified string
151: * @property Validator\Type $isType
152: * @method bool isType($input, $type) Check if the type of input is equals specified type name
153: * @property Validator\Uppercase $isUppercase
154: * @method bool isUppercase($input) Check if the input is uppercase
155: *
156: * Length
157: * @property Validator\Length $isLength
158: * @method bool isLength($input, $length, $max = null) Check if the length (or size) of input is equals specified length or in specified length range
159: * @property Validator\CharLength $isCharLength
160: * @method bool isCharLength($input, $length) Check if the characters length of input is equals specified length
161: * @property Validator\MinLength $isMinLength
162: * @method bool isMinLength($input, $min) Check if the length (or size) of input is greater than specified length
163: * @property Validator\MaxLength $isMaxLength
164: * @method bool isMaxLength($input, $max) Check if the length (or size) of input is lower than specified length
165: *
166: * Comparison
167: * @property Validator\EqualTo $isEqualTo
168: * @method bool isEqualTo($input, $value) Check if the input is equals to (==) the specified value
169: * @property Validator\IdenticalTo $identicalTo
170: * @method bool isIdenticalTo($input, $value) Check if the input is equals to (==) the specified value
171: * @property Validator\GreaterThan $isGreaterThan
172: * @method bool isGreaterThan($input, $value) Check if the input is greater than (>=) the specified value
173: * @property Validator\GreaterThanOrEqual $isGreaterThanOrEqual
174: * @method bool isGreaterThanOrEqual($input, $value) Check if the input is greater than or equal to (>=) the specified value
175: * @property Validator\LessThan $isLessThan
176: * @method bool isLessThan($input, $value) Check if the input is less than (<) the specified value
177: * @property Validator\LessThanOrEqual $isLessThanOrEqual
178: * @method bool isLessThanOrEqual($input, $value) Check if the input is less than or equal to (<=) the specified value
179: * @property Validator\Between $isBetween
180: * @method bool isBetween($input, $min, $max) Check if the input is between the specified minimum and maximum value
181: *
182: * Date and time
183: * @property Validator\Date $isDate
184: * @method bool isDate($input, $format = 'Y-m-d') Check if the input is a valid date
185: * @property Validator\DateTime $isDateTime
186: * @method bool isDateTime($input, $format = null) Check if the input is a valid datetime
187: * @property Validator\Time $isTime
188: * @method bool isTime($input, $format = 'H:i:s') Check if the input is a valid time
189: *
190: * File and directory
191: * @property Validator\Dir $isDir
192: * @method bool isDir($input) Check if the input is existing directory
193: * @property Validator\Exists $isExists
194: * @method bool isExists($input) Check if the input is existing file or directory
195: * @property Validator\File $isFile
196: * @method bool isFile($input, array $options) Check if the input is valid file
197: * @property Validator\Image $isImage
198: * @method bool isImage($input, array $options) Check if the input is valid image
199: *
200: * Network
201: * @property Validator\Email $isEmail
202: * @method bool isEmail($input) Check if the input is valid email address
203: * @property Validator\Ip $isIp
204: * @method bool isIp($input, array $options = array()) Check if the input is valid IP address
205: * @property Validator\Tld $isTld
206: * @method bool isTld($input) Check if the input is a valid top-level domain
207: * @property Validator\Url $isUrl
208: * @method bool isUrl($input, array $options = array()) Check if the input is valid URL address
209: * @property Validator\Uuid $isUuid
210: * @method bool isUuid($input) Check if the input is valid UUID(v4)
211: *
212: * Region
213: * @property Validator\CreditCard $isCreditCard
214: * @method bool isCreditCard($input, $type = null) Check if the input is valid credit card number
215: * @property Validator\Phone $isPhone
216: * @method bool isPhone($input) Check if the input is valid phone number, contains only digit, +, - and spaces
217: * @property Validator\Chinese $isChinese
218: * @method bool isChinese($input) Check if the input contains only Chinese characters
219: * @property Validator\IdCardCn $isIdCardCn
220: * @method bool isIdCardCn($input) Check if the input is valid Chinese identity card
221: * @property Validator\IdCardHk $isIdCardHk
222: * @method bool isIdCardHk($input) Check if the input is valid Hong Kong identity card
223: * @property Validator\IdCardMo $isIdCardMo
224: * @method bool isIdCardMo($input) Check if the input is valid Macau identity card
225: * @property Validator\IdCardTw $isIdCardTw
226: * @method bool isIdCardTw($input) Check if the input is valid Taiwan identity card
227: * @property Validator\PhoneCn $isPhoneCn
228: * @method bool isPhoneCn($input) Check if the input is valid Chinese phone number
229: * @property Validator\PlateNumberCn $isPlateNumberCn
230: * @method bool isPlateNumberCn($input) Check if the input is valid Chinese plate number
231: * @property Validator\PostcodeCn $isPostcodeCn
232: * @method bool isPostcodeCn($input) Check if the input is valid Chinese postcode
233: * @property Validator\QQ $isQQ
234: * @method bool isQQ($input) Check if the input is valid QQ number
235: * @property Validator\MobileCn $isMobileCn
236: * @method bool isMobileCn($input) Check if the input is valid Chinese mobile number
237: *
238: * Group
239: * @property Validator\AllOf $isAllOf
240: * @method bool isAllOf($input, array $rules) Check if the input is valid by all of the rules
241: * @property Validator\NoneOf $isNoneOf
242: * @method bool isNoneOf($input, array $rules) Check if the input is NOT valid by all of specified rules
243: * @property Validator\OneOf $isOneOf
244: * @method bool isOneOf($input, array $rules) Check if the input is valid by any of the rules
245: * @property Validator\SomeOf $isSomeOf
246: * @method bool isSomeOf($input, array $rules, $atLeast) Check if the input is valid by specified number of the rules
247: *
248: * Others
249: * @property Validator\RecordExists $isRecordExists
250: * @method bool isRecordExists($input, $table, $field = 'id') Check if the input is existing table record
251: * @property Validator\All $isAll
252: * @method bool isAll($input, array $rules) Check if all of the element in the input is valid by all specified rules
253: * @property Validator\Callback $isCallback
254: * @method bool isCallback($input, \Closure $fn, $message = null) Check if the input is valid by specified callback
255: * @property Validator\Color $isColor
256: * @method bool isColor($input) Check if the input is valid Hex color
257: * @property Validator\Password $isPassword
258: * @method bool isPassword($input, array $options = array()) Check if the input password is secure enough
259: */
260: class Wei extends Base
261: {
262: /**
263: * Version
264: */
265: const VERSION = '0.9.14';
266:
267: /**
268: * The configurations for all objects
269: *
270: * @var array
271: */
272: protected $configs = array();
273:
274: /**
275: * The name of current application
276: *
277: * @var string
278: */
279: protected $name;
280:
281: /**
282: * Whether in debug mode or not
283: *
284: * @var bool
285: */
286: protected $debug = true;
287:
288: /**
289: * The PHP configuration options that will be set when the service container constructing
290: *
291: * @var array
292: * @see http://www.php.net/manual/en/ini.php
293: * @see http://www.php.net/manual/en/function.ini-set.php
294: */
295: protected $inis = array();
296:
297: /**
298: * Whether enable class autoload or not
299: *
300: * @var bool
301: */
302: protected $autoload = true;
303:
304: /**
305: * The directories for autoload
306: *
307: * @var array
308: */
309: protected $autoloadMap = array();
310:
311: /**
312: * The service name to class name map
313: *
314: * @var array
315: */
316: protected $aliases = array();
317:
318: /**
319: * The service provider map
320: *
321: * @var array
322: */
323: protected $providers = array();
324:
325: /**
326: * The import configuration
327: *
328: * Format:
329: * array(
330: * array(
331: * 'dir' => 'lib/Wei/Validator',
332: * 'namespace' => 'Wei\Validator',
333: * 'format' => 'is%s',
334: * 'autoload' => false
335: * ),
336: * array(
337: * 'dir' => 'src/MyProject/Wei',
338: * 'namespace' => 'MyProject\Wei',
339: * 'format' => '%s',
340: * 'autoload' => true
341: * )
342: * );
343: * @var array
344: */
345: protected $import = array();
346:
347: /**
348: * The callback executes *before* service constructed
349: *
350: * @var callable
351: */
352: protected $beforeConstruct;
353:
354: /**
355: * The callback executes *after* service constructed
356: *
357: * @var callable
358: */
359: protected $afterConstruct;
360:
361: /**
362: * The services that will be instanced after service container constructed
363: *
364: * @var array
365: */
366: protected $preload = array();
367:
368: /**
369: * An array contains the instanced services
370: *
371: * @var Base[]
372: */
373: protected $services = array();
374:
375: /**
376: * The current service container
377: *
378: * @var Wei
379: */
380: protected static $container;
381:
382: /**
383: * Instance service container
384: *
385: * @param array $config
386: */
387: public function __construct(array $config = array())
388: {
389: // Set configurations for all services
390: $this->setConfig($config);
391:
392: $this->set('wei', $this);
393: $this->wei = $this;
394:
395: // Set all options
396: $options = get_object_vars($this);
397: if (isset($this->configs['wei'])) {
398: $options = array_merge($options, $this->configs['wei']);
399: }
400: $this->setOption($options);
401: }
402:
403: /**
404: * Get the service container instance
405: *
406: * @param array $config The array or file configuration
407: * @return $this
408: * @throws \InvalidArgumentException When the configuration parameter is not array or file
409: */
410: public static function getContainer($config = array())
411: {
412: // Most of time, it's called after instanced and without any arguments
413: if (!$config && static::$container) {
414: return static::$container;
415: }
416:
417: switch (true) {
418: case is_array($config):
419: break;
420:
421: case is_string($config) && file_exists($config):
422: $config = (array) require $config;
423: break;
424:
425: default:
426: throw new \InvalidArgumentException('Configuration should be array or file', 1010);
427: }
428:
429: if (!isset(static::$container)) {
430: static::$container = new static($config);
431: } else {
432: static::$container->setConfig($config);
433: }
434: return static::$container;
435: }
436:
437: /**
438: * Set the service container
439: *
440: * @param Wei $container
441: */
442: public static function setContainer(Wei $container = null)
443: {
444: static::$container = $container;
445: }
446:
447: /**
448: * Autoload the PSR-0 class
449: *
450: * @param string $class the name of the class
451: * @return bool
452: */
453: public function autoload($class)
454: {
455: $class = strtr($class, array('_' => DIRECTORY_SEPARATOR, '\\' => DIRECTORY_SEPARATOR)) . '.php';
456:
457: foreach ($this->autoloadMap as $prefix => $dir) {
458: // Autoload class from relative path like PSR-4 when prefix starts with "\"
459: if (isset($prefix[0]) && $prefix[0] == '\\' && 0 === strpos($class, ltrim($prefix, '\\'))) {
460: $file = $dir . DIRECTORY_SEPARATOR . substr($class, strlen($prefix));
461: if (file_exists($file)) {
462: require_once $file;
463: return true;
464: }
465: }
466:
467: // Allow empty class prefix
468: if (!$prefix || 0 === strpos($class, $prefix)) {
469: if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $class)) {
470: require_once $file;
471: return true;
472: }
473: }
474: }
475:
476: return false;
477: }
478:
479: /**
480: * Set service's configuration
481: *
482: * @param string|array $name
483: * @param mixed $value
484: * @return $this
485: */
486: public function setConfig($name, $value = null)
487: {
488: // Set array configurations
489: if (is_array($name)) {
490: foreach ($name as $key => $value) {
491: $this->setConfig($key, $value);
492: }
493: return $this;
494: }
495:
496: // Set one configuration
497: $names = explode(':', $name);
498: $first = $names[0];
499: $configs = &$this->configs;
500:
501: foreach ($names as $name) {
502: if (!is_array($configs)) {
503: $configs = array();
504: }
505: if (!isset($configs[$name])) {
506: $configs[$name] = array();
507: }
508: $configs = &$configs[$name];
509: }
510:
511: // Merge only first child node
512: if (is_array($configs) && is_array($value)) {
513: $configs = $value + $configs;
514: } else {
515: $configs = $value;
516: }
517:
518: /**
519: * Automatically create dependence map when configuration key contains "."
520: *
521: * $this->configs = array(
522: * 'mysql.db' => array(),
523: * );
524: * =>
525: * $this->providers['mysqlDb'] = 'mysql.db';
526: */
527: if (false !== strpos($first, '.')) {
528: $parts = explode('.', $first, 2);
529: $serviceName = $parts[0] . ucfirst($parts[1]);
530: if (!isset($this->providers[$serviceName])) {
531: $this->providers[$serviceName] = $first;
532: }
533: }
534:
535: // Set options for existing service
536: if (isset($this->services[$first])) {
537: $this->services[$first]->setOption($value);
538: }
539:
540: return $this;
541: }
542:
543: /**
544: * Get services' configuration
545: *
546: * @param string $name The name of configuration
547: * @param mixed $default The default value if configuration not found
548: * @return mixed
549: */
550: public function getConfig($name = null, $default = null)
551: {
552: if (is_null($name)) {
553: return $this->configs;
554: }
555:
556: if (false === strpos($name, ':')) {
557: return isset($this->configs[$name]) ? $this->configs[$name] : $default;
558: }
559:
560: $configs = &$this->configs;
561: foreach (explode(':', $name) as $key) {
562: if (is_array($configs) && isset($configs[$key])) {
563: $configs = &$configs[$key];
564: } else {
565: return $default;
566: }
567: }
568: return $configs;
569: }
570:
571: /**
572: * Get a service and call its "__invoke" method
573: *
574: * @param string $name The name of the service
575: * @param array $args The arguments for "__invoke" method
576: * @param array $providers The service providers map
577: * @return mixed
578: */
579: public function invoke($name, array $args = array(), $providers = array())
580: {
581: $service = $this->get($name, $providers);
582: return call_user_func_array(array($service, '__invoke'), $args);
583: }
584:
585: /**
586: * Get a service
587: *
588: * @param string $name The name of the service, without class prefix "Wei\"
589: * @param array $options The option properties for service
590: * @param array $providers The dependent configuration
591: * @throws \BadMethodCallException
592: * @return Base
593: */
594: public function get($name, array $options = array(), array $providers = array())
595: {
596: // Resolve the service name in dependent configuration
597: if (isset($providers[$name])) {
598: $name = $providers[$name];
599: }
600:
601: if (isset($this->providers[$name])) {
602: $name = $this->providers[$name];
603: }
604:
605: if (isset($this->services[$name])) {
606: return $this->services[$name];
607: }
608:
609: // Resolve the real service name and the config name($full)
610: $full = $name;
611: if (false !== ($pos = strpos($name, '.'))) {
612: $name = substr($name, $pos + 1);
613: }
614:
615: // Get the service class and instance
616: $class = $this->getClass($name);
617: if (class_exists($class)) {
618: // Trigger the before construct callback
619: $this->beforeConstruct && call_user_func($this->beforeConstruct, $this, $full, $name);
620:
621: // Load the service configuration and make sure "wei" option at first
622: $options = array('wei' => $this) + $options + (array)$this->getConfig($full);
623:
624: $this->services[$full] = new $class($options);
625:
626: // Trigger the after construct callback
627: $this->afterConstruct && call_user_func($this->afterConstruct, $this, $full, $name, $this->services[$full]);
628:
629: return $this->services[$full];
630: }
631:
632: // Build the error message
633: $traces = debug_backtrace();
634:
635: // $wei->notFound()
636: if (isset($traces[3]) && $name == $traces[3]['function']) {
637: // For call_user_func/call_user_func_array
638: $file = isset($traces[3]['file']) ? $traces[3]['file'] : $traces[4]['file'];
639: $line = isset($traces[3]['line']) ? $traces[3]['line'] : $traces[4]['line'];
640: throw new \BadMethodCallException(sprintf('Method "%s->%2$s" or object "%s" (class "%s") not found, called in file "%s" at line %s', $traces[3]['class'], $traces[3]['function'], $class, $file, $line), 1011);
641: // $wei->notFound
642: } elseif (isset($traces[1]) && '__get' == $traces[1]['function'] && $name == $traces[1]['args'][0]) {
643: throw new \BadMethodCallException(sprintf('Property or object "%s" (class "%s") not found, called in file "%s" at line %s', $traces[1]['args'][0], $class, $traces[1]['file'], $traces[1]['line']), 1012);
644: // $wei->get('notFound');
645: } else {
646: throw new \BadMethodCallException(sprintf('Property or method "%s" not found', $name), 1013);
647: }
648: }
649:
650: /**
651: * Returns all instanced services
652: *
653: * @return Base[]
654: */
655: public function getServices()
656: {
657: return $this->services;
658: }
659:
660: /**
661: * Check if the service is instanced
662: *
663: * @param string $name The name of service
664: * @return bool
665: */
666: public function isInstanced($name)
667: {
668: return isset($this->services[$name]);
669: }
670:
671: /**
672: * Initialize a new instance of service, with the specified name
673: *
674: * @param string $name The name of the service
675: * @param array $options The option properties for service
676: * @param array $providers The dependent configuration
677: * @return Base The instanced service
678: */
679: public function newInstance($name, array $options = array(), array $providers = array())
680: {
681: $name .= uniqid() . '.' . $name;
682: return $this->wei->get($name, $options, $providers);
683: }
684:
685: /**
686: * Add a service to the service container
687: *
688: * @param string $name The name of service
689: * @param Base $service The object of service
690: * @return $this
691: */
692: public function set($name, Base $service)
693: {
694: $this->services[$name] = $service;
695: return $this;
696: }
697:
698: /**
699: * Remove the service by the specified name
700: *
701: * @param string $name The name of service
702: * @return bool
703: */
704: public function remove($name)
705: {
706: if (isset($this->services[$name])) {
707: unset($this->services[$name]);
708: return true;
709: }
710: return false;
711: }
712:
713: /**
714: * Get the service class by the given name
715: *
716: * @param string $name The name of service
717: * @return string
718: */
719: public function getClass($name)
720: {
721: if (isset($this->aliases[$name])) {
722: $class = $this->aliases[$name];
723: } elseif ('is' == substr($name, 0, 2) && strlen($name) > 2) {
724: $class = 'Wei\Validator\\' . ucfirst(substr($name, 2));
725: } else {
726: $class = 'Wei\\' . ucfirst($name);
727: }
728: return $class;
729: }
730:
731: /**
732: * Check if the service exists by the specified name, if the service exists,
733: * returns the full class name, else return false
734: *
735: * @param string $name The name of service
736: * @return string|false
737: */
738: public function has($name)
739: {
740: $class = $this->getClass($name);
741: return class_exists($class) ? $class : false;
742: }
743:
744: /**
745: * Set debug flag
746: *
747: * @param $bool
748: * @return $this
749: */
750: public function setDebug($bool)
751: {
752: $this->debug = (bool) $bool;
753: return $this;
754: }
755:
756: /**
757: * Whether in debug mode or not
758: *
759: * @return bool
760: */
761: public function isDebug()
762: {
763: return $this->debug;
764: }
765:
766: /**
767: * Whether enable autoload or not
768: *
769: * @param bool $enable
770: * @return $this
771: */
772: public function setAutoload($enable)
773: {
774: $this->autoload = (bool) $enable;
775: call_user_func(
776: $enable ? 'spl_autoload_register' : 'spl_autoload_unregister',
777: array($this, 'autoload')
778: );
779: return $this;
780: }
781:
782: /**
783: * Set autoload directories for autoload method
784: *
785: * @param array $map
786: * @throws \InvalidArgumentException
787: * @return $this
788: */
789: public function setAutoloadMap(array $map)
790: {
791: foreach ($map as &$dir) {
792: if (!is_dir($dir)) {
793: throw new \InvalidArgumentException(sprintf('Directory "%s" for autoloading is not found', $dir));
794: }
795: $dir = realpath($dir);
796: }
797:
798: // Automatic add PSR-4 autoloading for "\Wei" namespace
799: $map['\Wei'] = __DIR__;
800:
801: $this->autoloadMap = $map;
802: return $this;
803: }
804:
805: /**
806: * Sets the value of PHP configuration options
807: *
808: * @param array $inis
809: * @return $this
810: */
811: public function setInis(array $inis)
812: {
813: $this->inis = $inis + $this->inis;
814: foreach ($inis as $key => $value) {
815: ini_set($key, $value);
816: }
817: return $this;
818: }
819:
820: /**
821: * Merge service aliases
822: *
823: * @param array $aliases
824: * @return $this
825: */
826: public function setAliases(array $aliases)
827: {
828: $this->aliases = $aliases + $this->aliases;
829: return $this;
830: }
831:
832: /**
833: * Set service alias
834: *
835: * @param string $name The name of service
836: * @param string $class The class that the service reference to
837: * @return $this
838: */
839: public function setAlias($name, $class)
840: {
841: $this->aliases[$name] = $class;
842: return $this;
843: }
844:
845: /**
846: * Add a service to the service container
847: *
848: * @param string $name The name of service
849: * @param Base $service The service service
850: * @return $this
851: */
852: public function __set($name, Base $service)
853: {
854: return $this->set($name, $service);
855: }
856:
857: /**
858: * Import classes in the specified directory as services
859: *
860: * @param string $dir The directory to search class
861: * @param string $namespace The prefix namespace of the class
862: * @param null $format The service name format, eg 'is%s'
863: * @param bool $autoload Whether add namespace and directory to `autoloadMap` or nor
864: * @throws \InvalidArgumentException When the first parameter is not a directory
865: * @return $this
866: */
867: public function import($dir, $namespace, $format = null, $autoload = false)
868: {
869: if (!is_dir($dir)) {
870: throw new \InvalidArgumentException(sprintf('Fail to import classes from non-exists directory "%s"', $dir), 1014);
871: }
872:
873: if ($autoload) {
874: $this->autoloadMap[$namespace] = dirname($dir);
875: }
876:
877: $files = glob($dir . '/*.php') ?: array();
878: foreach ($files as $file) {
879: $class = substr(basename($file), 0, -4);
880: $name = $format ? sprintf($format, $class) : $class;
881: $this->aliases[lcfirst($name)] = $namespace . '\\' . $class;
882: }
883:
884: return $this;
885: }
886:
887: /**
888: * Set the name of current application
889: *
890: * @param string $name
891: * @return $this
892: */
893: public function setName($name)
894: {
895: $this->name = $name;
896: return $this;
897: }
898:
899: /**
900: * Returns the name of current application
901: *
902: * @return string
903: */
904: public function getName()
905: {
906: return $this->name;
907: }
908:
909: /**
910: * Set import services
911: *
912: * @param array $import
913: * @return $this
914: */
915: protected function setImport(array $import = array())
916: {
917: $this->import = $import + $this->import;
918: foreach ($import as $option) {
919: $option += array(
920: 'dir' => null,
921: 'namespace' => null,
922: 'format' => null,
923: 'autoload' => false,
924: );
925: $this->import($option['dir'], $option['namespace'], $option['format'], $option['autoload']);
926: }
927: }
928:
929: /**
930: * Merge the dependence map
931: *
932: * @param array $providers
933: */
934: protected function setProviders(array $providers)
935: {
936: $this->providers = $providers + $this->providers;
937: }
938:
939: /**
940: * Instance preload services
941: *
942: * @param array $preload
943: */
944: protected function setPreload(array $preload)
945: {
946: $this->preload = array_merge($this->preload, $preload);
947: foreach ($preload as $service) {
948: $this->set($service, $this->get($service));
949: }
950: }
951:
952: /**
953: * Merge service objects
954: *
955: * @param array $services
956: */
957: protected function setServices(array $services)
958: {
959: $this->services = $services + $this->services;
960: }
961: }
962: }
963:
964: /**
965: * Define function in global namespace
966: */
967: namespace
968: {
969: /**
970: * Get the service container instance
971: *
972: * @return Wei\Wei
973: */
974: function wei()
975: {
976: return call_user_func_array(array('Wei\Wei', 'getContainer'), func_get_args());
977: }
978:
979: /**
980: * Get the service container instance
981: *
982: * @return Wei\Wei
983: * @deprecated Remove in 0.9.9
984: */
985: function widget()
986: {
987: return call_user_func_array(array('Wei\Wei', 'getContainer'), func_get_args());
988: }
989: }
990: