/** * method: getCallback * * Use the callback data to generate a callback usable in call_user_func* function. This * function can be provided with a fallback plugin or api object in case the detected plugin * doesn't exist. This is especially useful when the plugins are being loaded, it's not fully * installed in the system, but it's required to generate a callback * * params: * $callback - An array of data for the callback, or a string of comma separated parts * $fallback - Either null, a Plugin or API object * * returns: * - A callback in any case, if there is a problem with the data, it passed an exception * callback which will fail on execution * * variatons: * - array(plugin,object,method) * - array(plugin,method) * - "plugin,object,method => explode(,) => array(plugin,object,method) <-- array * - "plugin,method" => explode(,) => array(plugin,method) <-- array * - array(Object,method) <-- not static / array * - array(Class,method) <-- static / string * - "Class::method" <-- string * - "straightFunction" <-- string */ public static function getCallback($callback, $fallback = null) { $method = __METHOD__; // set output/invalid to be this default callback which throws an exception // this is so we can catch bad callbacks and trace them back to where they // where constructed $output = $invalid = function () use($method, $callback) { $args = func_get_args(); throw new Amslib_Exception("{$method}, callback was not valid", array("callback" => $callback instanceof Closure ? "was closure" : $callback, "arguments" => $args)); }; // supports: "plugin,object,method => array(plugin,object,method) // supports: "plugin,method" => array(plugin,method) if (is_string($callback) && strpos($callback, ",") !== false) { $callback = explode(",", $callback); } // supports: array(Object,method) // supports: array(plugin,object,method) // supports: array(plugin,method) if (is_array($callback) && in_array(count($callback), [2, 3])) { // The first element has to be an object or a plugin $plugin = array_shift($callback); // The last element in the array is always the method, if there is a third element // it will sit inside the middle, [plugin, >>>HERE<<<, method] and will be the object // But the third parameter is not necessary, if it's missing, the plugins API object is used $method = array_pop($callback); if (is_string($plugin) && !empty($plugin)) { // supports: array(plugin,object,method) // supports: array(plugin,method) $plugin = Amslib_Plugin_Manager::getAPI($plugin); } else { if (is_object($plugin)) { // supports: array(Object,method) $output = array($plugin, $method); } } if (!$plugin) { // supports: array(Class,method) if (class_exists($plugin)) { // The plugin was not found, therefore this must be a array(Class,Method) type call $output = array($plugin, $method); } else { if ($fallback instanceof Amslib_Plugin) { // If plugin is invalid and you were passed a plugin object $plugin = $fallback->getAPI(); } else { if ($fallback instanceof Amslib_MVC) { // If plugin is invalid and the method was passed an API object $plugin = $fallback; } } } } if ($plugin) { // Get the object to use in the callback $object = !empty($callback) ? array_shift($callback) : false; $object = !empty($object) && is_string($object) ? $plugin->getObject($object) : $plugin; // From the information, generate a new callback $output = array($object, $method); } } else { // supports: "Class::method" // supports: "theFunctionCall" // note: we don't need to do anything to support this, just fall into the else statement } // Return the callback, or a not_found default callback which throws an exception when called return is_callable($output) ? $output : $invalid; }
/** * method: getAPI * * todo: write documentation */ public function getAPI($name = NULL) { return $name ? Amslib_Plugin_Manager::getAPI($name) : $this; }
public function initialise() { // Quickly insert this plugin object before we load anything else // We do this so other plugins that might call the application can access this plugins // configuration before the entire tree is loaded, because in a tree algorithm, all the // other plugins are loaded into the system before this one, which causes a problem because // of course if you need to talk to or through the application object, if you have not fully // explored the tree, it won't exist, this obviously causes a lot of problems, so we need to // "insert" a incomplete plugin here, so at least the plugin configurtion is available even // if the actual API is not, when configuring the plugin tree, we 100% of the time always deal // with the plugin object, not the API which is created after the plugin is fully loaded Amslib_Plugin_Manager::insert($this->getName(), $this); // Set the base locations to load plugins from // NOTE: this obviously means it's not configurable, since I'm hardcoding the path for this here Amslib_Plugin_Manager::addLocation($this->getLocation()); Amslib_Plugin_Manager::addLocation($this->getLocation() . "/plugins"); // We can't use Amslib_Plugin_Manager for this, because it's an application plugin $this->config($this->getName()); // Process all the imports and exports so all the plugins contain the correct data Amslib_Plugin_Manager::processImport(); Amslib_Plugin_Manager::processExport(); // Now we have to load all the plugins into the system $this->load(); // NOTE: perhaps we can add a default callback for running the method Amslib_Plugin_Manager::processTransfers // NOTE: after all the plugins are loaded, do we need ot keep the plugin objects in memory, perhaps we should // dump them all once all the API objects are created // NOTE: perhaps we register a completion callback to manually take care of this, it sounds like a useful way // to save some memory, all those xml objects must take up space and especially the bulky confguration arrays // NOTE: we currently are deleting it inside the plugin code, perhaps this is not elegant $this->runCompletionCallbacks(); }
public static function processExport() { foreach (self::$export as $key => $list) { foreach ($list as $name => $value) { $src = is_string($value["src"]) ? self::getPlugin($value["src"]) : $value["src"]; $dst = is_string($value["dst"]) ? self::getPlugin($value["dst"]) : $value["dst"]; $data = false; if (!$src || !$dst) { $sname = is_object($src) ? $src->getName() : "searched: {$value["src"]}"; $dname = is_object($dst) ? $dst->getName() : "searched: {$value["dst"]}"; Amslib_Debug::log("plugin list", Amslib_Plugin_Manager::listPlugin()); Amslib_Debug::log("plugin invalid", intval(is_object($src)) . ", " . intval(is_object($dst)), $sname, $dname, Amslib_Router::getPath()); continue; } switch ($value["key"]) { case "stylesheet": case "javascript": case "font": die("[DIE]EXPORT[{$key}] => " . Amslib_Debug::pdump(true, array($src->getName(), $dst->getName(), $value["key"], $value["val"]))); break; case "view": case "value": // NOTE: if I could change getValue to this, I could refactor all of these branches // together maybe into something very generic // NOTE: the new import/export system works slightly differently from the old one, // we push directly into the import/export queues the information that we // want to pass and it doesn't enter the host plugin, this way, we can skip // a lot of bullshit with regard to internal data and data which is destined // for other plugins, the getValue method should in this case, circumstantially // create objects or just parse the data out of the structure, but it's not // about "getting" the value from the pluing, the $value variable already has // it and in many cases we don't need to do anything except return a particular // key depending on the stucture or type of that data, but in the case of // translators, objects or models, we need to ask the host plugin to create // the object on our behalf and then return and use it, because it might be // that the host plugin is the only plugin which has the correct functionality // necessary to create that object, in these cases getValue will do more than // just return a particular key, but will actually process the input data into // an "output data" to use //$data = $src->getValue($value); $dst->setValue($value["key"], $value["val"]); break; case "service": //Amslib_FirePHP::output("export",$item); // Hmmm, I need a test case cause otherwise I won't know if this works break; case "image": $dst->setValue($value["key"], $value["val"]); break; // We do nothing special with these entries, we simply pass them // We do nothing special with these entries, we simply pass them case "model": case "translator": default: // NOTE: I should change $value["key"] here to $value and make "key" something getValue uses internally $data = $src->getValue($value["key"]); $dst->setValue($value["key"], $data); break; } } } self::$export = NULL; }