PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/ajaxplorer/server/classes/class.AJXP_PluginsService.php

https://github.com/umbecr/camilaframework
PHP | 375 lines | 295 code | 23 blank | 57 comment | 68 complexity | 54f423430dfdd158fc50200992e076ec MD5 | raw file
  1. <?php
  2. /**
  3. * @package info.ajaxplorer
  4. *
  5. * Copyright 2007-2009 Charles du Jeu
  6. * This file is part of AjaXplorer.
  7. * The latest code can be found at http://www.ajaxplorer.info/
  8. *
  9. * This program is published under the LGPL Gnu Lesser General Public License.
  10. * You should have received a copy of the license along with AjaXplorer.
  11. *
  12. * The main conditions are as follow :
  13. * You must conspicuously and appropriately publish on each copy distributed
  14. * an appropriate copyright notice and disclaimer of warranty and keep intact
  15. * all the notices that refer to this License and to the absence of any warranty;
  16. * and give any other recipients of the Program a copy of the GNU Lesser General
  17. * Public License along with the Program.
  18. *
  19. * If you modify your copy or copies of the library or any portion of it, you may
  20. * distribute the resulting library provided you do so under the GNU Lesser
  21. * General Public License. However, programs that link to the library may be
  22. * licensed under terms of your choice, so long as the library itself can be changed.
  23. * Any translation of the GNU Lesser General Public License must be accompanied by the
  24. * GNU Lesser General Public License.
  25. *
  26. * If you copy or distribute the program, you must accompany it with the complete
  27. * corresponding machine-readable source code or with a written offer, valid for at
  28. * least three years, to furnish the complete corresponding machine-readable source code.
  29. *
  30. * Any of the above conditions can be waived if you get permission from the copyright holder.
  31. * AjaXplorer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  32. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  33. *
  34. * Description : Core parser for handling plugins.
  35. */
  36. defined('AJXP_EXEC') or die( 'Access not allowed');
  37. class AJXP_PluginsService{
  38. private static $instance;
  39. private $registry = array();
  40. private $tmpDependencies = array();
  41. private $activePlugins = array();
  42. private $xmlRegistry;
  43. private $pluginFolder;
  44. private $confFolder;
  45. public function loadPluginsRegistry($pluginFolder, $confFolder){
  46. $this->pluginFolder = $pluginFolder;
  47. $this->confFolder = $confFolder;
  48. $handler = opendir($pluginFolder);
  49. $beforeSort = array();
  50. if($handler){
  51. while ( ($item = readdir($handler)) !==false) {
  52. if($item == "." || $item == ".." || !is_dir($pluginFolder."/".$item) || strstr($item,".")===false) continue ;
  53. $plugin = new AJXP_Plugin($item, $pluginFolder."/".$item);
  54. $plugin->loadManifest();
  55. if($plugin->manifestLoaded()){
  56. $beforeSort[$plugin->getId()] = $plugin;
  57. }
  58. }
  59. closedir($handler);
  60. }
  61. if(count($beforeSort)){
  62. $this->checkDependencies($beforeSort);
  63. $this->usort($beforeSort);
  64. foreach ($beforeSort as $plugin){
  65. $plugType = $plugin->getType();
  66. if(!isSet($this->registry[$plugType])){
  67. $this->registry[$plugType] = array();
  68. }
  69. $plugin = $this->instanciatePluginClass($plugin);
  70. if(is_file($this->confFolder."/conf.".$plugin->getId().".inc")){
  71. $plugin->loadConfig($this->confFolder."/conf.".$plugin->getId().".inc", "inc");
  72. }
  73. $this->registry[$plugType][$plugin->getName()] = $plugin;
  74. }
  75. }
  76. }
  77. /**
  78. * Find a PHP class and instanciate it to replace the empty AJXP_Plugin
  79. *
  80. * @param AJXP_Plugin $plugin
  81. * @return AJXP_Plugin
  82. */
  83. private function instanciatePluginClass($plugin){
  84. $definition = $plugin->getClassFile();
  85. if(!$definition) return $plugin;
  86. $filename = INSTALL_PATH."/".$definition["filename"];
  87. $className = $definition["classname"];
  88. if(is_file($filename)){
  89. require_once($filename);
  90. $newPlugin = new $className($plugin->getId(), $plugin->getBaseDir());
  91. $newPlugin->loadManifest();
  92. return $newPlugin;
  93. }else{
  94. return $plugin;
  95. }
  96. }
  97. private function checkDependencies(&$arrayToSort){
  98. // First make sure that the given dependencies are present
  99. foreach ($arrayToSort as $plugId => $plugObject){
  100. foreach ($plugObject->getDependencies() as $requiredPlugId){
  101. if(strstr($requiredPlugId, "|")!==false){
  102. $orParts = explode("|", $requiredPlugId);
  103. $found = false;
  104. foreach ($orParts as $part){
  105. if(isSet($arrayToSort[$part])){
  106. $found=true;break;
  107. }
  108. }
  109. if(!$found){
  110. unset($arrayToSort[$plugId]);
  111. break;
  112. }
  113. }else if(!isSet($arrayToSort[$requiredPlugId])){
  114. unset($arrayToSort[$plugId]);
  115. break;
  116. }
  117. }
  118. }
  119. }
  120. /**
  121. * User function for sorting
  122. *
  123. * @param AJXP_Plugin $pluginA
  124. * @param AJXP_Plugin $pluginB
  125. */
  126. private function sortByDependency($pluginA, $pluginB){
  127. if($pluginA->dependsOn($pluginB->getId())) {
  128. return 1;
  129. }
  130. if($pluginB->dependsOn($pluginA->getId())) {
  131. return -1;
  132. }
  133. return 0;
  134. }
  135. private function usort(&$tableau){
  136. while(count($tableau)>0){
  137. reset($tableau);
  138. $pluspetit = key($tableau);
  139. foreach($tableau as $c=>$v){
  140. if($this->sortByDependency($tableau[$pluspetit], $v) > 0){
  141. $pluspetit = $c;
  142. }
  143. }
  144. $result[]=$tableau[$pluspetit];
  145. unset($tableau[$pluspetit]);
  146. }
  147. $tableau = $result;
  148. }
  149. public function getPluginsByType($type){
  150. if(isSet($this->registry[$type])) return $this->registry[$type];
  151. else return array();
  152. }
  153. public function getPluginById($pluginId){
  154. $split = explode(".", $pluginId);
  155. return $this->getPluginByTypeName($split[0], $split[1]);
  156. }
  157. public function removePluginById($pluginId){
  158. $split = explode(".", $pluginId);
  159. if(isSet($this->registry[$split[0]]) && isSet($this->registry[$split[0]][$split[1]])){
  160. unset($this->registry[$split[0]][$split[1]]);
  161. }
  162. }
  163. public static function setPluginActive($type, $name, $active=true){
  164. self::getInstance()->setPluginActiveInst($type, $name, $active);
  165. }
  166. public function setPluginActiveInst($type, $name, $active=true){
  167. if($active){
  168. // Check active plugin dependencies
  169. $plug = $this->getPluginById($type.".".$name);
  170. $deps = $plug->getActiveDependencies();
  171. foreach ($deps as $dep){
  172. if(strstr($dep, "|")!==false){
  173. $orParts = explode("|", $dep);
  174. $found = false;
  175. foreach ($orParts as $part){
  176. if(isSet($this->activePlugins[$part]) && $this->activePlugins[$part] === true) {
  177. $found=true;break;
  178. }
  179. }
  180. if(!$found){
  181. $this->activePlugins[$type.".".$name] = false;
  182. return ;
  183. }
  184. }else if(!isSet($this->activePlugins[$dep]) || $this->activePlugins[$dep] === false){
  185. $this->activePlugins[$type.".".$name] = false;
  186. return ;
  187. }
  188. }
  189. }
  190. $this->activePlugins[$type.".".$name] = $active;
  191. if(isSet($this->xmlRegistry)){
  192. $this->buildXmlRegistry();
  193. }
  194. }
  195. public function setPluginUniqueActiveForType($type, $name){
  196. $typePlugs = $this->getPluginsByType($type);
  197. foreach($typePlugs as $plugName => $plugObject){
  198. $this->setPluginActiveInst($type, $plugName, false);
  199. }
  200. $this->setPluginActiveInst($type, $name, true);
  201. }
  202. public function getActivePlugins(){
  203. return $this->activePlugins;
  204. }
  205. public function buildXmlRegistry(){
  206. $actives = $this->getActivePlugins();
  207. $reg = DOMDocument::loadXML("<ajxp_registry></ajxp_registry>");
  208. foreach($actives as $activeName=>$status){
  209. if($status === false) continue;
  210. $plug = $this->getPluginById($activeName);
  211. $contribs = $plug->getRegistryContributions();
  212. foreach($contribs as $contrib){
  213. $parent = $contrib->nodeName;
  214. $nodes = $contrib->childNodes;
  215. if(!$nodes->length) continue;
  216. $uuidAttr = $contrib->getAttribute("uuidAttr") OR "name";
  217. $uuidAttr = "name";
  218. $this->mergeNodes($reg, $parent, $uuidAttr, $nodes);
  219. }
  220. }
  221. $this->xmlRegistry = $reg;
  222. }
  223. public static function getXmlRegistry(){
  224. $self = self::getInstance();
  225. if(!isSet($self->xmlRegistry)){
  226. $self->buildXmlRegistry();
  227. }
  228. return $self->xmlRegistry;
  229. }
  230. public static function searchAllManifests($query, $stringOrNodeFormat = "string"){
  231. $buffer = "";
  232. $nodes = array();
  233. $self = self::getInstance();
  234. foreach ($self->registry as $plugType){
  235. foreach ($plugType as $plugName => $plugObject){
  236. $res = $plugObject->getManifestRawContent($query, $stringOrNodeFormat);
  237. if($stringOrNodeFormat == "string"){
  238. $buffer .= $res;
  239. }else{
  240. foreach ($res as $node){
  241. $nodes[] = $node;
  242. }
  243. }
  244. }
  245. }
  246. if($stringOrNodeFormat == "string") return $buffer;
  247. else return $nodes;
  248. }
  249. protected function mergeNodes(&$original, $parentName, $uuidAttr, $childrenNodes){
  250. // find or create parent
  251. $parentSelection = $original->getElementsByTagName($parentName);
  252. if($parentSelection->length){
  253. $parentNode = $parentSelection->item(0);
  254. $xPath = new DOMXPath($original);
  255. foreach($childrenNodes as $child){
  256. if($child->nodeType != XML_ELEMENT_NODE) continue;
  257. if($child->getAttribute($uuidAttr) == "*"){
  258. $query = $parentName.'/'.$child->nodeName;
  259. }else{
  260. $query = $parentName.'/'.$child->nodeName.'[@'.$uuidAttr.' = "'.$child->getAttribute($uuidAttr).'"]';
  261. }
  262. $childrenSel = $xPath->query($query);
  263. if($childrenSel->length){
  264. foreach ($childrenSel as $existingNode){
  265. // Clone as many as needed
  266. $clone = $original->importNode($child, true);
  267. $this->mergeChildByTagName($clone, $existingNode);
  268. }
  269. }else{
  270. $clone = $original->importNode($child, true);
  271. $parentNode->appendChild($clone);
  272. }
  273. }
  274. }else{
  275. //create parentNode and append children
  276. if($childrenNodes->length){
  277. $parentNode = $original->importNode($childrenNodes->item(0)->parentNode, true);
  278. $original->documentElement->appendChild($parentNode);
  279. }else{
  280. $parentNode = $original->createElement($parentName);
  281. $original->documentElement->appendChild($parentNode);
  282. }
  283. }
  284. }
  285. protected function mergeChildByTagName($new, &$old){
  286. if(!$this->hasElementChild($new) || !$this->hasElementChild($old)){
  287. $old->parentNode->replaceChild($new, $old);
  288. return;
  289. }
  290. foreach($new->childNodes as $newChild){
  291. if($newChild->nodeType != XML_ELEMENT_NODE) continue;
  292. $found = null;
  293. foreach($old->childNodes as $oldChild){
  294. if($oldChild->nodeType != XML_ELEMENT_NODE) continue;
  295. if($oldChild->nodeName == $newChild->nodeName){
  296. $found = $oldChild;
  297. }
  298. }
  299. if($found != null){
  300. if($newChild->nodeName == "post_processing" || $newChild->nodeName == "pre_processing"){
  301. $old->appendChild($newChild->cloneNode(true));
  302. }else{
  303. $this->mergeChildByTagName($newChild, $found);
  304. }
  305. }else{
  306. // CloneNode or it's messing with the current foreach loop.
  307. $old->appendChild($newChild->cloneNode(true));
  308. }
  309. }
  310. }
  311. private function hasElementChild($node){
  312. if(!$node->hasChildNodes()) return false;
  313. foreach($node->childNodes as $child){
  314. if($child->nodeType == XML_ELEMENT_NODE) return true;
  315. }
  316. return false;
  317. }
  318. public function getPluginByTypeName($plugType, $plugName){
  319. if(isSet($this->registry[$plugType]) && isSet($this->registry[$plugType][$plugName])){
  320. return $this->registry[$plugType][$plugName];
  321. }else{
  322. return false;
  323. }
  324. }
  325. public static function findPlugin($type, $name){
  326. $instance = self::getInstance();
  327. return $instance->getPluginByTypeName($type, $name);
  328. }
  329. public static function findPluginById($id){
  330. return self::getInstance()->getPluginById($id);
  331. }
  332. private function __construct(){
  333. }
  334. /**
  335. * Singleton method
  336. *
  337. * @return AJXP_PluginsService the service instance
  338. */
  339. public static function getInstance()
  340. {
  341. if(!isSet(self::$instance)){
  342. $c = __CLASS__;
  343. self::$instance = new $c;
  344. }
  345. return self::$instance;
  346. }
  347. public function __clone()
  348. {
  349. trigger_error("Cannot clone me, i'm a singleton!", E_USER_ERROR);
  350. }
  351. }
  352. ?>