/** * Create the default data for the Extensions module. * * @return void */ public function defaultdata() { $version = new ExtensionsModuleVersion(new ZikulaExtensionsModule()); $meta = $version->toArray(); $meta['state'] = \ModUtil::STATE_ACTIVE; unset($meta['dependencies']); unset($meta['oldnames']); $item = new ExtensionEntity(); $item->merge($meta); $this->entityManager->persist($item); $this->entityManager->flush(); }
/** * Regenerate modules list. * * @param array[] $args { * @type array $filemodules An array of modules in the filesystem, as would be returned by * {@link getfilemodules()}; optional, defaults to the results of $this->getfilemodules() * } * * @return boolean True on success, false on failure * * @throws \InvalidArgumentException Thrown if the filemodules parameter is either not set or not an array * @throws AccessDeniedException Thrown if the user doesn't have admin permissions over the module * @throws \RuntimeException Thrown if module information cannot be obtained from the database */ public function regenerate($args) { // Security check if (!System::isInstalling()) { if (!SecurityUtil::checkPermission('ZikulaExtensionsModule::', '::', ACCESS_ADMIN)) { throw new AccessDeniedException(); } } $boot = new Bootstrap(); $helper = new BootstrapHelper($boot->getConnection($this->getContainer()->get('kernel'))); // sync the filesystem and the bundles table $helper->load(); // Argument check if (!isset($args['filemodules']) || !is_array($args['filemodules'])) { throw new \InvalidArgumentException(__('Invalid arguments array received')); } // default action $filemodules = $args['filemodules']; $defaults = isset($args['defaults']) ? $args['defaults'] : false; // Get all modules in DB $allmodules = $this->entityManager->getRepository(self::EXTENSION_ENTITY)->findAll(); if (!$allmodules) { throw new \RuntimeException($this->__('Error! Could not load data.')); } // index modules by name $dbmodules = array(); /* @var ExtensionEntity $module */ foreach ($allmodules as $module) { $dbmodules[$module['name']] = $module->toArray(); } // build a list of found modules and dependencies $fileModuleNames = array(); $moddependencies = array(); foreach ($filemodules as $modinfo) { $fileModuleNames[] = $modinfo['name']; if (isset($modinfo['dependencies']) && !empty($modinfo['dependencies'])) { $moddependencies[$modinfo['name']] = unserialize($modinfo['dependencies']); } } // see if any modules have changed name since last regeneration foreach ($filemodules as $name => $modinfo) { if (isset($modinfo['oldnames']) && !empty($modinfo['oldnames'])) { foreach ($dbmodules as $dbname => $dbmodinfo) { if (isset($dbmodinfo['name']) && in_array($dbmodinfo['name'], (array) $modinfo['oldnames'])) { // migrate its modvars $query = $this->entityManager->createQueryBuilder()->update('Zikula\\ExtensionsModule\\Entity\\ExtensionVarEntity', 'v')->set('v.modname', ':modname')->setParameter('modname', $modinfo['name'])->where('v.modname = :dbname')->setParameter('dbname', $dbname)->getQuery(); $query->execute(); // rename the module register $query = $this->entityManager->createQueryBuilder()->update(self::EXTENSION_ENTITY, 'e')->set('e.name', ':modname')->setParameter('modname', $modinfo['name'])->where('e.id = :dbname')->setParameter('dbname', $dbmodules[$dbname]['id'])->getQuery(); $query->execute(); // replace the old module with the new one in the dbmodules array $newmodule = $dbmodules[$dbname]; $newmodule['name'] = $modinfo['name']; unset($dbmodules[$dbname]); $dbname = $modinfo['name']; $dbmodules[$dbname] = $newmodule; } } } // If module was previously determined to be incompatible with the core. return to original state if (isset($dbmodules[$name]) && $dbmodules[$name]['state'] > 10) { $dbmodules[$name]['state'] = $dbmodules[$name]['state'] - ModUtil::INCOMPATIBLE_CORE_SHIFT; $this->setState(array('id' => $dbmodules[$name]['id'], 'state' => $dbmodules[$name]['state'])); } // update the DB information for this module to reflect user settings (e.g. url) if (isset($dbmodules[$name]['id'])) { $modinfo['id'] = $dbmodules[$name]['id']; if ($dbmodules[$name]['state'] != ModUtil::STATE_UNINITIALISED && $dbmodules[$name]['state'] != ModUtil::STATE_INVALID) { unset($modinfo['version']); } if (!$defaults) { unset($modinfo['displayname']); unset($modinfo['description']); unset($modinfo['url']); } unset($modinfo['oldnames']); unset($modinfo['dependencies']); $modinfo['capabilities'] = unserialize($modinfo['capabilities']); $modinfo['securityschema'] = unserialize($modinfo['securityschema']); $module = $this->entityManager->getRepository(self::EXTENSION_ENTITY)->find($modinfo['id']); $module->merge($modinfo); $this->entityManager->flush(); } // check core version is compatible with current $coreCompatibility = isset($filemodules[$name]['corecompatibility']) ? $filemodules[$name]['corecompatibility'] : $this->formatCoreCompatibilityString($filemodules[$name]['core_min'], $filemodules[$name]['core_max']); $isCompatible = $this->isCoreCompatible($coreCompatibility); if (isset($dbmodules[$name])) { if (!$isCompatible) { // module is incompatible with current core $dbmodules[$name]['state'] = $dbmodules[$name]['state'] + ModUtil::INCOMPATIBLE_CORE_SHIFT; $this->setState(array('id' => $dbmodules[$name]['id'], 'state' => $dbmodules[$name]['state'])); } if (isset($dbmodules[$name]['state'])) { $filemodules[$name]['state'] = $dbmodules[$name]['state']; } } } // See if we have lost any modules since last regeneration foreach ($dbmodules as $name => $modinfo) { if (!in_array($name, $fileModuleNames)) { $lostModule = $this->entityManager->getRepository(self::EXTENSION_ENTITY)->findOneBy(array('name' => $name)); if (!$lostModule) { throw new \RuntimeException($this->__f('Error! Could not load data for module %s.', array($name))); } $lostModuleState = $lostModule->getState(); if ($lostModuleState == ModUtil::STATE_INVALID || $lostModuleState == ModUtil::STATE_INVALID + ModUtil::INCOMPATIBLE_CORE_SHIFT) { // module was invalid and subsequently removed from file system, // or module was incompatible with core and subsequently removed, delete it $this->entityManager->remove($lostModule); $this->entityManager->flush(); } elseif ($lostModuleState == ModUtil::STATE_UNINITIALISED || $lostModuleState == ModUtil::STATE_UNINITIALISED + ModUtil::INCOMPATIBLE_CORE_SHIFT) { // module was uninitialised and subsequently removed from file system, delete it $this->entityManager->remove($lostModule); $this->entityManager->flush(); } else { // Set state of module to 'missing' $this->setState(array('id' => $lostModule->getId(), 'state' => ModUtil::STATE_MISSING)); } unset($dbmodules[$name]); } } // See if we have gained any modules since last generation, // or if any current modules have been upgraded foreach ($filemodules as $name => $modinfo) { if (empty($dbmodules[$name])) { // set state to invalid if we can't determine an ID $modinfo['state'] = ModUtil::STATE_UNINITIALISED; if (!$modinfo['version']) { $modinfo['state'] = ModUtil::STATE_INVALID; } else { $coreCompatibility = isset($filemodules[$name]['corecompatibility']) ? $filemodules[$name]['corecompatibility'] : $this->formatCoreCompatibilityString($filemodules[$name]['core_min'], $filemodules[$name]['core_max']); // shift state if module is incompatible with core version $modinfo['state'] = $this->isCoreCompatible($coreCompatibility) ? $modinfo['state'] : $modinfo['state'] + ModUtil::INCOMPATIBLE_CORE_SHIFT; } // unset some vars unset($modinfo['oldnames']); unset($modinfo['dependencies']); // unserialze some vars $modinfo['capabilities'] = unserialize($modinfo['capabilities']); $modinfo['securityschema'] = unserialize($modinfo['securityschema']); // insert new module to db if ($this->serviceManager['multisites.enabled'] == 1) { // only the main site can regenerate the modules list if ($this->serviceManager['multisites.mainsiteurl'] == $this->request->query->get('sitedns', null) && $this->serviceManager['multisites.based_on_domains'] == 0 || $this->serviceManager['multisites.mainsiteurl'] == $_SERVER['HTTP_HOST'] && $this->serviceManager['multisites.based_on_domains'] == 1) { $item = new ExtensionEntity(); $item->merge($modinfo); $this->entityManager->persist($item); } } else { $item = new ExtensionEntity(); $item->merge($modinfo); $this->entityManager->persist($item); } $this->entityManager->flush(); } else { // module is in the db already if ($dbmodules[$name]['state'] == ModUtil::STATE_MISSING || $dbmodules[$name]['state'] == ModUtil::STATE_MISSING + ModUtil::INCOMPATIBLE_CORE_SHIFT) { // module was lost, now it is here again $this->setState(array('id' => $dbmodules[$name]['id'], 'state' => ModUtil::STATE_INACTIVE)); } elseif (($dbmodules[$name]['state'] == ModUtil::STATE_INVALID || $dbmodules[$name]['state'] == ModUtil::STATE_INVALID + ModUtil::INCOMPATIBLE_CORE_SHIFT) && $modinfo['version']) { $coreCompatibility = isset($filemodules[$name]['corecompatibility']) ? $filemodules[$name]['corecompatibility'] : $this->formatCoreCompatibilityString($filemodules[$name]['core_min'], $filemodules[$name]['core_max']); $isCompatible = $this->isCoreCompatible($coreCompatibility); if ($isCompatible) { // module was invalid, now it is valid $item = $this->entityManager->getRepository(self::EXTENSION_ENTITY)->find($dbmodules[$name]['id']); $item->setState(ModUtil::STATE_UNINITIALISED); $this->entityManager->flush(); } } if ($dbmodules[$name]['version'] != $modinfo['version']) { if ($dbmodules[$name]['state'] != ModUtil::STATE_UNINITIALISED && $dbmodules[$name]['state'] != ModUtil::STATE_INVALID) { $this->setState(array('id' => $dbmodules[$name]['id'], 'state' => ModUtil::STATE_UPGRADED)); } } } } // now clear re-load the dependencies table with all current dependencies $connection = $this->entityManager->getConnection(); $platform = $connection->getDatabasePlatform(); $connection->executeUpdate($platform->getTruncateTableSQL('module_deps', true)); // loop round dependencies adding the module id - we do this now rather than // earlier since we won't have the id's for new modules at that stage ModUtil::flushCache(); foreach ($moddependencies as $modname => $moddependency) { $modid = ModUtil::getIdFromName($modname); // each module may have multiple dependencies foreach ($moddependency as $dependency) { $dependency['modid'] = $modid; $item = new ExtensionDependencyEntity(); $item->merge($dependency); $this->entityManager->persist($item); } } $this->entityManager->flush(); return true; }
/** * Get an array of Blocks that are available by scanning the filesystem. * Optionally only retrieve the blocks of one module. * * @param ExtensionEntity|null $module * @return array [[ModuleName:FqBlockClassName => ModuleDisplayName/BlockDisplayName]] */ public function getAvailableBlockTypes(ExtensionEntity $module = null) { $foundBlocks = []; $modules = isset($module) ? [$module] : $this->extensionApi->getModulesBy(['state' => ExtensionApi::STATE_ACTIVE]); /** @var \Zikula\ExtensionsModule\Entity\ExtensionEntity $module */ foreach ($modules as $module) { $moduleInstance = $this->extensionApi->getModuleInstanceOrNull($module->getName()); list($nameSpace, $path) = $this->getModuleBlockPath($moduleInstance, $module->getName()); if (!isset($path)) { continue; } $finder = new Finder(); $foundFiles = $finder->files()->name('*.php')->in($path)->depth(0); foreach ($foundFiles as $file) { preg_match("/class (\\w+) (?:extends|implements) \\\\?(\\w+)/", $file->getContents(), $matches); $blockInstance = $this->blockFactory->getInstance($nameSpace . $matches[1], $moduleInstance); $foundBlocks[$module->getName() . ':' . $nameSpace . $matches[1]] = $module->getDisplayname() . '/' . $blockInstance->getType(); } } // Add service defined blocks. foreach ($this->blockCollector->getBlocks() as $id => $blockInstance) { $className = get_class($blockInstance); list($moduleName, $serviceId) = explode(':', $id); if (isset($foundBlocks["{$moduleName}:{$className}"])) { // remove blocks found in file search with same class name unset($foundBlocks["{$moduleName}:{$className}"]); } $moduleEntity = $this->extensionApi->getModule($moduleName); $foundBlocks[$id] = $moduleEntity->getDisplayname() . '/' . $blockInstance->getType(); } return $foundBlocks; }