/** * Reads and caches a single manifest from a given plugin directory. * * @static * @private * @param string $dir * @return DevblocksPluginManifest */ protected static function _readPluginManifest($rel_dir, $persist = true) { $manifest_file = APP_PATH . '/' . $rel_dir . '/plugin.xml'; if (!file_exists($manifest_file)) { return NULL; } $plugin = simplexml_load_file($manifest_file); $prefix = APP_DB_PREFIX != '' ? APP_DB_PREFIX . '_' : ''; // [TODO] Cleanup $manifest = new DevblocksPluginManifest(); $manifest->id = (string) $plugin->id; $manifest->dir = $rel_dir; $manifest->description = (string) $plugin->description; $manifest->author = (string) $plugin->author; $manifest->revision = (int) $plugin->revision; $manifest->link = (string) $plugin->link; $manifest->name = (string) $plugin->name; // Dependencies if (isset($plugin->dependencies)) { if (isset($plugin->dependencies->require)) { foreach ($plugin->dependencies->require as $eDependency) { $depends_on = (string) $eDependency['plugin_id']; $manifest->manifest_cache['dependencies'][] = $depends_on; } } } // Patches if (isset($plugin->patches)) { if (isset($plugin->patches->patch)) { foreach ($plugin->patches->patch as $ePatch) { $patch_version = (string) $ePatch['version']; $patch_revision = (string) $ePatch['revision']; $patch_file = (string) $ePatch['file']; $manifest->manifest_cache['patches'][] = array('version' => $patch_version, 'revision' => $patch_revision, 'file' => $patch_file); } } } // Templates if (isset($plugin->templates)) { foreach ($plugin->templates as $eTemplates) { $template_set = (string) $eTemplates['set']; if (isset($eTemplates->template)) { foreach ($eTemplates->template as $eTemplate) { $manifest->manifest_cache['templates'][] = array('plugin_id' => $manifest->id, 'set' => $template_set, 'path' => (string) $eTemplate['path']); } } } } // Image if (isset($plugin->image)) { $manifest->manifest_cache['plugin_image'] = (string) $plugin->image; } if (!$persist) { return $manifest; } $db = DevblocksPlatform::getDatabaseService(); if (is_null($db)) { return; } // Persist manifest if ($db->GetOne(sprintf("SELECT id FROM {$prefix}plugin WHERE id = %s", $db->qstr($manifest->id)))) { // update $db->Execute(sprintf("UPDATE {$prefix}plugin " . "SET name=%s,description=%s,author=%s,revision=%s,link=%s,dir=%s,manifest_cache_json=%s " . "WHERE id=%s", $db->qstr($manifest->name), $db->qstr($manifest->description), $db->qstr($manifest->author), $db->qstr($manifest->revision), $db->qstr($manifest->link), $db->qstr($manifest->dir), $db->qstr(json_encode($manifest->manifest_cache)), $db->qstr($manifest->id))); } else { // insert $enabled = 'devblocks.core' == $manifest->id ? 1 : 0; $db->Execute(sprintf("INSERT INTO {$prefix}plugin (id,enabled,name,description,author,revision,link,dir,manifest_cache_json) " . "VALUES (%s,%d,%s,%s,%s,%s,%s,%s,%s)", $db->qstr($manifest->id), $enabled, $db->qstr($manifest->name), $db->qstr($manifest->description), $db->qstr($manifest->author), $db->qstr($manifest->revision), $db->qstr($manifest->link), $db->qstr($manifest->dir), $db->qstr(json_encode($manifest->manifest_cache)))); } // Class Loader if (isset($plugin->class_loader->file)) { foreach ($plugin->class_loader->file as $eFile) { @($sFilePath = (string) $eFile['path']); $manifest->class_loader[$sFilePath] = array(); if (isset($eFile->class)) { foreach ($eFile->class as $eClass) { @($sClassName = (string) $eClass['name']); $manifest->class_loader[$sFilePath][] = $sClassName; } } } } // Routing if (isset($plugin->uri_routing->uri)) { foreach ($plugin->uri_routing->uri as $eUri) { @($sUriName = (string) $eUri['name']); @($sController = (string) $eUri['controller']); $manifest->uri_routing[$sUriName] = $sController; } } // ACL if (isset($plugin->acl->priv)) { foreach ($plugin->acl->priv as $ePriv) { @($sId = (string) $ePriv['id']); @($sLabel = (string) $ePriv['label']); if (empty($sId) || empty($sLabel)) { continue; } $priv = new DevblocksAclPrivilege(); $priv->id = $sId; $priv->plugin_id = $manifest->id; $priv->label = $sLabel; $manifest->acl_privs[$priv->id] = $priv; } asort($manifest->acl_privs); } // Event points if (isset($plugin->event_points->event)) { foreach ($plugin->event_points->event as $eEvent) { $sId = (string) $eEvent['id']; $sName = (string) $eEvent->name; if (empty($sId) || empty($sName)) { continue; } $point = new DevblocksEventPoint(); $point->id = $sId; $point->plugin_id = $plugin->id; $point->name = $sName; $point->params = array(); if (isset($eEvent->param)) { foreach ($eEvent->param as $eParam) { $key = (string) $eParam['key']; $val = (string) $eParam['value']; $point->param[$key] = $val; } } $manifest->event_points[] = $point; } } // Extensions if (isset($plugin->extensions->extension)) { foreach ($plugin->extensions->extension as $eExtension) { $sId = (string) $eExtension->id; $sName = (string) $eExtension->name; if (empty($sId) || empty($sName)) { continue; } $extension = new DevblocksExtensionManifest(); $extension->id = $sId; $extension->plugin_id = $manifest->id; $extension->point = (string) $eExtension['point']; $extension->name = $sName; $extension->file = (string) $eExtension->class->file; $extension->class = (string) $eExtension->class->name; if (isset($eExtension->params->param)) { foreach ($eExtension->params->param as $eParam) { $key = (string) $eParam['key']; if (isset($eParam->value)) { // [JSJ]: If there is a child of the param tag named value, then this // param has multiple values and thus we need to grab them all. foreach ($eParam->value as $eValue) { // [JSJ]: If there is a child named data, then this is a complex structure if (isset($eValue->data)) { $value = array(); foreach ($eValue->data as $eData) { $key2 = (string) $eData['key']; if (isset($eData['value'])) { $value[$key2] = (string) $eData['value']; } else { $value[$key2] = (string) $eData; } } } else { // [JSJ]: Else, just grab the value and use it $value = (string) $eValue; } $extension->params[$key][] = $value; unset($value); // Just to be extra safe } } else { // [JSJ]: Otherwise, we grab the single value from the params value attribute. $extension->params[$key] = (string) $eParam['value']; } } } $manifest->extensions[] = $extension; } } // [JAS]: Extension caching $new_extensions = array(); if (is_array($manifest->extensions)) { foreach ($manifest->extensions as $pos => $extension) { /* @var $extension DevblocksExtensionManifest */ $db->Execute(sprintf("REPLACE INTO {$prefix}extension (id,plugin_id,point,pos,name,file,class,params) " . "VALUES (%s,%s,%s,%d,%s,%s,%s,%s)", $db->qstr($extension->id), $db->qstr($extension->plugin_id), $db->qstr($extension->point), $pos, $db->qstr($extension->name), $db->qstr($extension->file), $db->qstr($extension->class), $db->qstr(serialize($extension->params)))); $new_extensions[$extension->id] = true; } } /* * Compare our loaded XML manifest to the DB manifest cache and invalidate * the cache for extensions that are no longer in the XML. */ $sql = sprintf("SELECT id FROM %sextension WHERE plugin_id = %s", $prefix, $db->qstr($plugin->id)); $results = $db->GetArray($sql); foreach ($results as $row) { $plugin_ext_id = $row['id']; if (!isset($new_extensions[$plugin_ext_id])) { DAO_Platform::deleteExtension($plugin_ext_id); } } // Class loader cache $db->Execute(sprintf("DELETE FROM %sclass_loader WHERE plugin_id = %s", $prefix, $db->qstr($plugin->id))); if (is_array($manifest->class_loader)) { foreach ($manifest->class_loader as $file_path => $classes) { if (is_array($classes) && !empty($classes)) { foreach ($classes as $class) { $db->Execute(sprintf("REPLACE INTO {$prefix}class_loader (class,plugin_id,rel_path) " . "VALUES (%s,%s,%s)", $db->qstr($class), $db->qstr($manifest->id), $db->qstr($file_path))); } } } } // URI routing cache $db->Execute(sprintf("DELETE FROM %suri_routing WHERE plugin_id = %s", $prefix, $db->qstr($plugin->id))); if (is_array($manifest->uri_routing)) { foreach ($manifest->uri_routing as $uri => $controller_id) { $db->Execute(sprintf("REPLACE INTO {$prefix}uri_routing (uri,plugin_id,controller_id) " . "VALUES (%s,%s,%s)", $db->qstr($uri), $db->qstr($manifest->id), $db->qstr($controller_id))); } } // ACL caching $db->Execute(sprintf("DELETE FROM %sacl WHERE plugin_id = %s", $prefix, $db->qstr($plugin->id))); if (is_array($manifest->acl_privs)) { foreach ($manifest->acl_privs as $priv) { /* @var $priv DevblocksAclPrivilege */ $db->Execute(sprintf("REPLACE INTO {$prefix}acl (id,plugin_id,label) " . "VALUES (%s,%s,%s)", $db->qstr($priv->id), $db->qstr($priv->plugin_id), $db->qstr($priv->label))); } } // [JAS]: Event point caching if (is_array($manifest->event_points)) { foreach ($manifest->event_points as $event) { /* @var $event DevblocksEventPoint */ $db->Execute(sprintf("REPLACE INTO {$prefix}event_point (id,plugin_id,name,params) " . "VALUES (%s,%s,%s,%s)", $db->qstr($event->id), $db->qstr($event->plugin_id), $db->qstr($event->name), $db->qstr(serialize($event->params)))); } } return $manifest; }
/** * Reads and caches a single manifest from a given plugin directory. * * @static * @private * @param string $dir * @return DevblocksPluginManifest */ protected static function _readPluginManifest($rel_dir) { $manifest_file = APP_PATH . '/' . $rel_dir . '/plugin.xml'; if (!file_exists($manifest_file)) { return NULL; } $plugin = simplexml_load_file($manifest_file); $prefix = APP_DB_PREFIX != '' ? APP_DB_PREFIX . '_' : ''; // [TODO] Cleanup $manifest = new DevblocksPluginManifest(); $manifest->id = (string) $plugin->id; $manifest->dir = $rel_dir; $manifest->description = (string) $plugin->description; $manifest->author = (string) $plugin->author; $manifest->revision = (int) $plugin->revision; $manifest->link = (string) $plugin->link; $manifest->name = (string) $plugin->name; // [TODO] Clear out any removed plugins/classes/exts? $db = DevblocksPlatform::getDatabaseService(); if (is_null($db)) { return; } // Templates if (isset($plugin->templates)) { foreach ($plugin->templates as $eTemplates) { $template_set = (string) $eTemplates['set']; if (isset($eTemplates->template)) { foreach ($eTemplates->template as $eTemplate) { $manifest->templates[] = array('plugin_id' => $manifest->id, 'set' => $template_set, 'path' => (string) $eTemplate['path']); } } } } // Manifest $db->Replace($prefix . 'plugin', array('id' => $db->qstr($manifest->id), 'name' => $db->qstr($manifest->name), 'description' => $db->qstr($manifest->description), 'author' => $db->qstr($manifest->author), 'revision' => $manifest->revision, 'link' => $db->qstr($manifest->link), 'dir' => $db->qstr($manifest->dir), 'templates_json' => $db->qstr(json_encode($manifest->templates))), array('id'), false); // Class Loader if (isset($plugin->class_loader->file)) { foreach ($plugin->class_loader->file as $eFile) { @($sFilePath = (string) $eFile['path']); $manifest->class_loader[$sFilePath] = array(); if (isset($eFile->class)) { foreach ($eFile->class as $eClass) { @($sClassName = (string) $eClass['name']); $manifest->class_loader[$sFilePath][] = $sClassName; } } } } // Routing if (isset($plugin->uri_routing->uri)) { foreach ($plugin->uri_routing->uri as $eUri) { @($sUriName = (string) $eUri['name']); @($sController = (string) $eUri['controller']); $manifest->uri_routing[$sUriName] = $sController; } } // ACL if (isset($plugin->acl->priv)) { foreach ($plugin->acl->priv as $ePriv) { @($sId = (string) $ePriv['id']); @($sLabel = (string) $ePriv['label']); if (empty($sId) || empty($sLabel)) { continue; } $priv = new DevblocksAclPrivilege(); $priv->id = $sId; $priv->plugin_id = $manifest->id; $priv->label = $sLabel; $manifest->acl_privs[$priv->id] = $priv; } asort($manifest->acl_privs); } // Event points if (isset($plugin->event_points->event)) { foreach ($plugin->event_points->event as $eEvent) { $sId = (string) $eEvent['id']; $sName = (string) $eEvent->name; if (empty($sId) || empty($sName)) { continue; } $point = new DevblocksEventPoint(); $point->id = $sId; $point->plugin_id = $plugin->id; $point->name = $sName; $point->params = array(); if (isset($eEvent->param)) { foreach ($eEvent->param as $eParam) { $key = (string) $eParam['key']; $val = (string) $eParam['value']; $point->param[$key] = $val; } } $manifest->event_points[] = $point; } } // Extensions if (isset($plugin->extensions->extension)) { foreach ($plugin->extensions->extension as $eExtension) { $sId = (string) $eExtension->id; $sName = (string) $eExtension->name; if (empty($sId) || empty($sName)) { continue; } $extension = new DevblocksExtensionManifest(); $extension->id = $sId; $extension->plugin_id = $manifest->id; $extension->point = (string) $eExtension['point']; $extension->name = $sName; $extension->file = (string) $eExtension->class->file; $extension->class = (string) $eExtension->class->name; if (isset($eExtension->params->param)) { foreach ($eExtension->params->param as $eParam) { $key = (string) $eParam['key']; if (isset($eParam->value)) { // [JSJ]: If there is a child of the param tag named value, then this // param has multiple values and thus we need to grab them all. foreach ($eParam->value as $eValue) { // [JSJ]: If there is a child named data, then this is a complex structure if (isset($eValue->data)) { $value = array(); foreach ($eValue->data as $eData) { $key2 = (string) $eData['key']; if (isset($eData['value'])) { $value[$key2] = (string) $eData['value']; } else { $value[$key2] = (string) $eData; } } } else { // [JSJ]: Else, just grab the value and use it $value = (string) $eValue; } $extension->params[$key][] = $value; unset($value); // Just to be extra safe } } else { // [JSJ]: Otherwise, we grab the single value from the params value attribute. $extension->params[$key] = (string) $eParam['value']; } } } $manifest->extensions[] = $extension; } } // [JAS]: Extension caching $new_extensions = array(); if (is_array($manifest->extensions)) { foreach ($manifest->extensions as $pos => $extension) { /* @var $extension DevblocksExtensionManifest */ // [JAS]: [TODO] Move to platform DAO $db->Replace($prefix . 'extension', array('id' => $db->qstr($extension->id), 'plugin_id' => $db->qstr($extension->plugin_id), 'point' => $db->qstr($extension->point), 'pos' => $pos, 'name' => $db->qstr($extension->name), 'file' => $db->qstr($extension->file), 'class' => $db->qstr($extension->class), 'params' => $db->qstr(serialize($extension->params))), array('id'), false); $new_extensions[$extension->id] = true; } } /* * Compare our loaded XML manifest to the DB manifest cache and invalidate * the cache for extensions that are no longer in the XML. */ $sql = sprintf("SELECT id FROM %sextension WHERE plugin_id = %s", $prefix, $db->qstr($plugin->id)); $rs_plugin_extensions = $db->Execute($sql); while (!$rs_plugin_extensions->EOF) { $plugin_ext_id = $rs_plugin_extensions->fields['id']; if (!isset($new_extensions[$plugin_ext_id])) { DAO_Platform::deleteExtension($plugin_ext_id); } $rs_plugin_extensions->MoveNext(); } // [JAS]: [TODO] Extension point caching // Class loader cache $db->Execute(sprintf("DELETE FROM %sclass_loader WHERE plugin_id = %s", $prefix, $db->qstr($plugin->id))); if (is_array($manifest->class_loader)) { foreach ($manifest->class_loader as $file_path => $classes) { if (is_array($classes) && !empty($classes)) { foreach ($classes as $class) { $db->Replace($prefix . 'class_loader', array('class' => $db->qstr($class), 'plugin_id' => $db->qstr($manifest->id), 'rel_path' => $db->qstr($file_path)), array('class'), false); } } } } // URI routing cache $db->Execute(sprintf("DELETE FROM %suri_routing WHERE plugin_id = %s", $prefix, $db->qstr($plugin->id))); if (is_array($manifest->uri_routing)) { foreach ($manifest->uri_routing as $uri => $controller_id) { $db->Replace($prefix . 'uri_routing', array('uri' => $db->qstr($uri), 'plugin_id' => $db->qstr($manifest->id), 'controller_id' => $db->qstr($controller_id)), array('uri'), false); } } // ACL caching $db->Execute(sprintf("DELETE FROM %sacl WHERE plugin_id = %s", $prefix, $db->qstr($plugin->id))); if (is_array($manifest->acl_privs)) { foreach ($manifest->acl_privs as $priv) { /* @var $priv DevblocksAclPrivilege */ $db->Replace($prefix . 'acl', array('id' => $db->qstr($priv->id), 'plugin_id' => $db->qstr($priv->plugin_id), 'label' => $db->qstr($priv->label)), array('id'), false); } } // [JAS]: Event point caching if (is_array($manifest->event_points)) { foreach ($manifest->event_points as $event) { /* @var $event DevblocksEventPoint */ $db->Replace($prefix . 'event_point', array('id' => $db->qstr($event->id), 'plugin_id' => $db->qstr($event->plugin_id), 'name' => $db->qstr($event->name), 'params' => $db->qstr(serialize($event->params))), array('id'), false); } } return $manifest; }