PageRenderTime 56ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/atk4/lib/PathFinder.php

https://github.com/intuititve/lostandfound
PHP | 375 lines | 296 code | 23 blank | 56 comment | 11 complexity | f074de6490b530e9949a9019c8abf6fc MD5 | raw file
Possible License(s): AGPL-3.0
  1. <?php
  2. /***********************************************************
  3. ..
  4. Reference:
  5. http://agiletoolkit.org/doc/ref
  6. **ATK4*****************************************************
  7. This file is part of Agile Toolkit 4
  8. http://agiletoolkit.org
  9. (c) 2008-2011 Agile Technologies Ireland Limited
  10. Distributed under Affero General Public License v3
  11. If you are using this file in YOUR web software, you
  12. must make your make source code for YOUR web software
  13. public.
  14. See LICENSE.txt for more information
  15. You can obtain non-public copy of Agile Toolkit 4 at
  16. http://agiletoolkit.org/commercial
  17. *****************************************************ATK4**/
  18. class PathFinder extends AbstractController {
  19. /*
  20. PathFinder will help you to maintain consistent structure of files. This
  21. controller is used by many other parts of Agile Toolkit
  22. PathFinder concerns itself only with relative paths. It relies on PageManager
  23. ($api->pm) to convert relative paths into absolute.
  24. */
  25. public $base_location=null;
  26. // Object referencing base location. You might want to add more content here
  27. public $atk_location=null;
  28. // Referencing to location of a shared library
  29. function init(){
  30. parent::init();
  31. $this->api->pathfinder=$this;
  32. $GLOBALS['atk_pathfinder']=$this; // used by autoload
  33. $this->addDefaultLocations();
  34. }
  35. function addDefaultLocations(){
  36. // Typically base directory is good for includes,
  37. // but atk4/ can also contain some data
  38. // Primary search point is the webroot directory. We are defining
  39. // those so you don't have to
  40. $base_directory=dirname(@$_SERVER['SCRIPT_FILENAME']);
  41. // Compatibility with command-line
  42. if(!$base_directory)$base_directory=realpath($GLOBALS['argv'][0]);
  43. if(method_exists($this->api,'addDefaultLocations'))$this->api->addDefaultLocations($this,$base_directory);
  44. $this->base_location=$this->addLocation('/',array(
  45. 'php'=>'lib',
  46. 'page'=>'page',
  47. 'addons'=>'atk4-addons',
  48. 'template'=>'templates/'.$this->api->skin,
  49. 'xslt'=>'templates/xslt',
  50. 'mail'=>'templates/mail',
  51. 'js'=>'templates/js',
  52. 'banners'=>'banners',
  53. 'logs'=>'logs',
  54. 'dbupdates'=>'docs/dbupdates',
  55. ))->setBasePath($base_directory)
  56. ;
  57. // Files not found in webroot - will be looked for in library dir
  58. // We are assuming that we are located as atk4/lib/PathFinder.php
  59. $atk_directory=dirname(dirname(__FILE__));
  60. $atk_url=basename($atk_directory);
  61. $this->atk_location=$this->addLocation('atk4',array(
  62. 'php'=>'lib',
  63. // page: for security reasons no pages are allowed
  64. 'docs'=>'', // files like README, COPYING etc
  65. 'template'=>array('templates/'.$this->api->skin,'templates'=>'templates/shared'),
  66. 'xslt'=>'templates/xslt',
  67. 'mail'=>'templates/mail',
  68. 'js'=>'templates/js',
  69. // TODO: check that the folowing two are actually being used
  70. 'images'=>'img',
  71. 'css'=>array('templates/js','templates/'.$this->api->skin.'/css','templates/shared/css'),
  72. ))
  73. ->setBasePath(dirname(dirname(__FILE__)))
  74. ->setBaseURL($this->api->getConfig('atk/base_path','./atk4/'))
  75. ;
  76. }
  77. function addLocation($path,$contents=array()){
  78. $location=$this
  79. ->add('PathFinder_Location',$path)
  80. ->defineContents($contents)
  81. ;
  82. return $location;
  83. }
  84. function locate($type,$filename='',$return='relative'){
  85. /*
  86. Search for filename inside multiple locations, which contain
  87. resources of $type
  88. if filename is not defined, the location of the first available resource is defined
  89. */
  90. $attempted_locations=array();
  91. foreach($this->elements as $location){
  92. if(!($location instanceof PathFinder_Location))continue;
  93. $path=$location->locate($type,$filename,$return);
  94. if(is_string($path) || is_object($path)){
  95. // file found!
  96. return $path;
  97. }elseif(is_array($path)){
  98. $attempted_locations=array_merge($attempted_locations,$path);
  99. }
  100. }
  101. throw new PathFinder_Exception($type,$filename,$attempted_locations);
  102. }
  103. function search($type,$filename='',$return='relative'){
  104. /*
  105. Similar to locate but returns array with all matches for the specified file
  106. in array
  107. */
  108. $matches=array();
  109. foreach($this->elements as $location){
  110. if(!($location instanceof PathFinder_Location))continue;
  111. $path=$location->locate($type,$filename,$return);
  112. if(is_string($path)){
  113. // file found!
  114. $matches[]=$path;
  115. }
  116. }
  117. return $matches;
  118. }
  119. function _searchDirFiles($dir,&$files,$prefix=''){
  120. $d=dir($dir);
  121. while(false !== ($file=$d->read())){
  122. if($file[0]=='.')continue;
  123. if(is_dir($dir.'/'.$file)){
  124. $this->_searchDirFiles($dir.'/'.$file,$files,$prefix.$file.'/');
  125. }else{
  126. $files[]=$prefix.$file;
  127. }
  128. }
  129. $d->close();
  130. }
  131. function searchDir($type,$directory=''){
  132. /*
  133. List all files inside particular directory
  134. */
  135. $dirs=$this->search($type,$directory,'path');
  136. $files=array();
  137. foreach($dirs as $dir){
  138. $this->_searchDirFiles($dir,$files);
  139. }
  140. return $files;
  141. }
  142. function loadClass($class_name){
  143. /**/$this->api->pr->start('pathfinder/loadClass '.$class_name);
  144. list($namespace,$file)=explode('\\',$class_name);
  145. if (!$file && $namespace){
  146. $file = $namespace;
  147. $namespace=null;
  148. }
  149. /**/$this->api->pr->next('pathfinder/loadClass/convertpath '.$class_name);
  150. // Include class file directly, do not rely on auto-load functionality
  151. if(!class_exists($class_name,false) && isset($this->api->pathfinder) && $this->api->pathfinder){
  152. $file = str_replace('_',DIRECTORY_SEPARATOR,$file).'.php';
  153. if($namespace){
  154. $path=$this->api->locatePath('addons',$namespace.DIRECTORY_SEPARATOR.'lib'.DIRECTORY_SEPARATOR.$file);
  155. if(!is_readable($path)){
  156. throw new PathFinder_Exception('addon',$path,$prefix);
  157. }
  158. }else{
  159. /**/$this->api->pr->next('pathfinder/loadClass/locate '.$class_name);
  160. if(substr($class_name,0,5)=='page_'){
  161. $path=$this->api->pathfinder->locate('page',substr($file,5),'path');
  162. }else $path=$this->api->pathfinder->locate('php',$file,'path');
  163. }
  164. /**/$this->api->pr->next('pathfinder/loadClass/include '.$class_name);
  165. /**/$this->api->pr->start('php parsing');
  166. include_once($path);
  167. /**/$this->api->pr->stop();
  168. if(!class_exists($class_name))throw $this->exception('Class is not defined in file')
  169. ->addMoreInfo('file',$path)
  170. ->addMoreInfo('class',$class_name);
  171. }
  172. /**/$this->api->pr->stop();
  173. }
  174. }
  175. class PathFinder_Exception extends BaseException {
  176. function __construct($type,$filename,$attempted_locations,$message=null){
  177. parent::__construct("Unable to include $filename".($message?':'.$message:''));
  178. $this->addMoreInfo('type',$type);
  179. $this->addMoreInfo('attempted_locations',$attempted_locations);
  180. }
  181. }
  182. class PathFinder_Location extends AbstractModel {
  183. /*
  184. Represents a location, which contains number of sub-locations. Each
  185. of which may contain certain type of data
  186. */
  187. public $parent_location=null;
  188. public $contents=array();
  189. // contains list of 'type'=>'subdir' which lists all the
  190. // resources which can be found in this directory
  191. public $relative_path=null;
  192. // Path to relative file within this resource
  193. public $base_url=null;
  194. public $base_path=null;
  195. public $auto_track_element=true;
  196. function init(){
  197. parent::init();
  198. $this->relative_path=$this->short_name;
  199. if($this->short_name[0]=='/' || (strlen($this->short_name)>1 && $this->short_name[1]==':')){
  200. // Absolute path. Independent from base_location
  201. }else{
  202. $this->setParent($this->owner->base_location);
  203. }
  204. }
  205. function setParent($parent){
  206. $this->parent_location=$parent;
  207. return $this;
  208. }
  209. function __toString(){
  210. // this is our path
  211. $s=(isset($this->parent_location)?
  212. ((string)$this->parent_location):'');
  213. if($s && substr($s,-1)!='/' && $this->relative_path)$s.='/';
  214. $s.=$this->relative_path;
  215. return $s;
  216. }
  217. function getURL($file_path=null){
  218. // Returns how this location or file can be accessed through web
  219. // base url + relative path + file_path
  220. $url='';
  221. if($this->base_url)$url=$this->base_url;else
  222. if($this->parent_location){
  223. $url=$this->parent_location->getURL();
  224. if(substr($url,-1)!='/')$url.='/';
  225. $url.=$this->relative_path;
  226. }else
  227. throw new BaseException('Unable to determine URL');
  228. if($file_path){
  229. if(substr($url,-1)!='/')$url.='/';
  230. $url.=$file_path;
  231. }
  232. return $url;
  233. }
  234. function getPath($file_path=null){
  235. // Returns how this location or file can be accessed through filesystem
  236. $path='';
  237. if($this->base_path)$path=$this->base_path;else
  238. if($this->parent_location){
  239. $path=$this->parent_location->getPath();
  240. if(substr($path,-1)!='/')$path.='/';
  241. $path.=$this->relative_path;
  242. }else
  243. throw new BaseException('Unable to determine Path for '.$this.', parent='.$this->parent_location);
  244. if($file_path){
  245. if(substr($path,-1)!='/')$path.='/';
  246. $path.=$file_path;
  247. }
  248. return $path;
  249. }
  250. function setBaseURL($url){
  251. /*
  252. something like /my/app
  253. */
  254. $this->base_url=$url;
  255. return $this;
  256. }
  257. function setBasePath($path){
  258. /*
  259. something like /home/web/public_html
  260. */
  261. $this->base_path=$path;
  262. return $this;
  263. }
  264. function defineContents($contents){
  265. if($contents==='all'){
  266. $contents=array('all'=>'all');
  267. }
  268. if(is_string($contents)){
  269. $contents=array($contents=>'.');
  270. }
  271. $this->contents=array_merge_recursive($this->contents,$contents);
  272. return $this;
  273. }
  274. function locate($type,$filename,$return='relative'){
  275. // Locates the file and if found - returns location,
  276. // otherwise returns array of attempted locations
  277. // specify empty filename to find location
  278. $attempted_locations=array();
  279. $locations=array();
  280. $location=null;
  281. // first - look if type is explicitly defined in
  282. if(isset($this->contents[$type])){
  283. if(is_array($this->contents[$type])){
  284. $locations=$this->contents[$type];
  285. }else{
  286. $locations=array($this->contents[$type]);
  287. }
  288. // next - look if locations claims to have all resource types
  289. }elseif(isset($this->contents['all'])){
  290. $locations=array($type);
  291. echo (string)$this;
  292. }
  293. foreach($locations as $path){
  294. $f=$this->getPath($pathfile=$path.'/'.$filename);
  295. if(file_exists($f)){
  296. if(!is_readable($f)){
  297. throw new PathFinder_Exception($type,$filename,$f,'File found but it is not readable');
  298. }
  299. if($return=='location')return $this;
  300. if($return=='relative')return $pathfile;
  301. if($return=='url')return $this->getURL($pathfile);
  302. if($return=='path')return $f;
  303. throw new BaseException('Wrong return type for locate()');
  304. }else $attempted_locations[]=$f;
  305. }
  306. return $attempted_locations;
  307. }
  308. }