| <?php | 
 | /* | 
 |  * Licensed to the Apache Software Foundation (ASF) under one | 
 |  * or more contributor license agreements. See the NOTICE file | 
 |  * distributed with this work for additional information | 
 |  * regarding copyright ownership. The ASF licenses this file | 
 |  * to you under the Apache License, Version 2.0 (the | 
 |  * "License"); you may not use this file except in compliance | 
 |  * with the License. You may obtain a copy of the License at | 
 |  * | 
 |  *   http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, | 
 |  * software distributed under the License is distributed on an | 
 |  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
 |  * KIND, either express or implied. See the License for the | 
 |  * specific language governing permissions and limitations | 
 |  * under the License. | 
 |  * | 
 |  * ClassLoader to load Thrift library and definitions | 
 |  * Inspired from UniversalClassLoader from Symfony 2 | 
 |  * | 
 |  * @package thrift.classloader | 
 |  */ | 
 |  | 
 | namespace Thrift\ClassLoader; | 
 |  | 
 | class ThriftClassLoader | 
 | { | 
 |     /** | 
 |      * Namespaces path | 
 |      * @var array | 
 |      */ | 
 |     protected $namespaces = array(); | 
 |  | 
 |     /** | 
 |      * Thrift definition paths | 
 |      * @var type | 
 |      */ | 
 |     protected $definitions = array(); | 
 |  | 
 |     /** | 
 |      * Do we use APCu cache ? | 
 |      * @var boolean | 
 |      */ | 
 |     protected $apcu = false; | 
 |  | 
 |     /** | 
 |      * APCu Cache prefix | 
 |      * @var string | 
 |      */ | 
 |     protected $apcu_prefix; | 
 |  | 
 |     /** | 
 |      * Set autoloader to use APCu cache | 
 |      * @param boolean $apc | 
 |      * @param string $apcu_prefix | 
 |      */ | 
 |     public function __construct($apc = false, $apcu_prefix = null) | 
 |     { | 
 |         $this->apcu = $apc; | 
 |         $this->apcu_prefix = $apcu_prefix; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Registers a namespace. | 
 |      * | 
 |      * @param string $namespace The namespace | 
 |      * @param array|string $paths The location(s) of the namespace | 
 |      */ | 
 |     public function registerNamespace($namespace, $paths) | 
 |     { | 
 |         $this->namespaces[$namespace] = (array)$paths; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Registers a Thrift definition namespace. | 
 |      * | 
 |      * @param string $namespace The definition namespace | 
 |      * @param array|string $paths The location(s) of the definition namespace | 
 |      */ | 
 |     public function registerDefinition($namespace, $paths) | 
 |     { | 
 |         $this->definitions[$namespace] = (array)$paths; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Registers this instance as an autoloader. | 
 |      * | 
 |      * @param Boolean $prepend Whether to prepend the autoloader or not | 
 |      */ | 
 |     public function register($prepend = false) | 
 |     { | 
 |         spl_autoload_register(array($this, 'loadClass'), true, $prepend); | 
 |     } | 
 |  | 
 |     /** | 
 |      * Loads the given class, definition or interface. | 
 |      * | 
 |      * @param string $class The name of the class | 
 |      */ | 
 |     public function loadClass($class) | 
 |     { | 
 |         if ((true === $this->apcu && ($file = $this->findFileInApcu($class))) or | 
 |             ($file = $this->findFile($class)) | 
 |         ) { | 
 |             require_once $file; | 
 |         } | 
 |     } | 
 |  | 
 |     /** | 
 |      * Loads the given class or interface in APCu. | 
 |      * @param  string $class The name of the class | 
 |      * @return string | 
 |      */ | 
 |     protected function findFileInApcu($class) | 
 |     { | 
 |         if (false === $file = apcu_fetch($this->apcu_prefix . $class)) { | 
 |             apcu_store($this->apcu_prefix . $class, $file = $this->findFile($class)); | 
 |         } | 
 |  | 
 |         return $file; | 
 |     } | 
 |  | 
 |     /** | 
 |      * Find class in namespaces or definitions directories | 
 |      * @param  string $class | 
 |      * @return string | 
 |      */ | 
 |     public function findFile($class) | 
 |     { | 
 |         // Remove first backslash | 
 |         if ('\\' == $class[0]) { | 
 |             $class = substr($class, 1); | 
 |         } | 
 |  | 
 |         if (false !== $pos = strrpos($class, '\\')) { | 
 |             // Namespaced class name | 
 |             $namespace = substr($class, 0, $pos); | 
 |  | 
 |             // Iterate in normal namespaces | 
 |             foreach ($this->namespaces as $ns => $dirs) { | 
 |                 //Don't interfere with other autoloaders | 
 |                 if (0 !== strpos($namespace, $ns)) { | 
 |                     continue; | 
 |                 } | 
 |  | 
 |                 foreach ($dirs as $dir) { | 
 |                     $className = substr($class, $pos + 1); | 
 |  | 
 |                     $file = $dir . DIRECTORY_SEPARATOR . | 
 |                         str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . | 
 |                         DIRECTORY_SEPARATOR . | 
 |                         $className . '.php'; | 
 |  | 
 |                     if (file_exists($file)) { | 
 |                         return $file; | 
 |                     } | 
 |                 } | 
 |             } | 
 |  | 
 |             // Iterate in Thrift namespaces | 
 |  | 
 |             // Remove first part of namespace | 
 |             $m = explode('\\', $class); | 
 |  | 
 |             // Ignore wrong call | 
 |             if (count($m) <= 1) { | 
 |                 return; | 
 |             } | 
 |  | 
 |             $class = array_pop($m); | 
 |             $namespace = implode('\\', $m); | 
 |  | 
 |             foreach ($this->definitions as $ns => $dirs) { | 
 |                 //Don't interfere with other autoloaders | 
 |                 if (0 !== strpos($namespace, $ns)) { | 
 |                     continue; | 
 |                 } | 
 |  | 
 |                 foreach ($dirs as $dir) { | 
 |                     /** | 
 |                      * Available in service: Interface, Client, Processor, Rest | 
 |                      * And every service methods (_.+) | 
 |                      */ | 
 |                     if (0 === preg_match('#(.+)(if|client|processor|rest)$#i', $class, $n) and | 
 |                         0 === preg_match('#(.+)_[a-z0-9]+_(args|result)$#i', $class, $n) | 
 |                     ) { | 
 |                         $className = 'Types'; | 
 |                     } else { | 
 |                         $className = $n[1]; | 
 |                     } | 
 |  | 
 |                     $file = $dir . DIRECTORY_SEPARATOR . | 
 |                         str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . | 
 |                         DIRECTORY_SEPARATOR . | 
 |                         $className . '.php'; | 
 |  | 
 |                     if (file_exists($file)) { | 
 |                         return $file; | 
 |                     } | 
 |                 } | 
 |             } | 
 |         } | 
 |     } | 
 | } |