Skip to content

Commit

Permalink
added fix command from the oxid console project
Browse files Browse the repository at this point in the history
https://github.com/OXIDprojects/oxid-console

added requirements to composer.json to be able to develop that module with ide support
  • Loading branch information
keywan-ghadami-oxid committed Nov 23, 2018
1 parent 2de57ca commit 711344d
Show file tree
Hide file tree
Showing 5 changed files with 843 additions and 3 deletions.
4 changes: 3 additions & 1 deletion .gitignore
@@ -1 +1,3 @@
.idea
/.idea
/composer.phar
/vendor
177 changes: 177 additions & 0 deletions Command/ModuleFixCommand.php
@@ -0,0 +1,177 @@
<?php

namespace OxidCommunity\ModuleInternals\Command;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Output\NullOutput;
use OxidEsales\Eshop\Core\Registry;
use OxidEsales\Eshop\Core\Module\Module;
use OxidEsales\Eshop\Core\Module\ModuleList;
use OxidEsales\Eshop\Core\Exception\InputException;
use OxidCommunity\ModuleInternals\Core\ModuleStateFixer;
use OxidProfessionalServices\OxidConsole\Core\ShopConfig;

/**
* Fix States command
*/
class ModuleFixCommand extends Command
{

/**
* @var array|null Available module ids
*/
protected $_aAvailableModuleIds = null;

/** @var InputInterface */
private $input;

/**
* {@inheritdoc}
*/
public function configure()
{
$this
->setName('module:fix')
->setAliases(['fix:states'])
->setDescription('Fixes modules metadata states')
->addOption('all', 'a', InputOption::VALUE_NONE, 'Includes all modules')
->addOption('base-shop', 'b', InputOption::VALUE_NONE, 'Apply changes to base shop only')
->addOption('shop', 's', InputOption::VALUE_REQUIRED, 'Apply changes to given shop only')
->addArgument('module-id', InputArgument::IS_ARRAY, 'Module id/ids to use');
}

/**
* {@inheritdoc}
*/
public function execute(InputInterface $input, OutputInterface $output)
{
$this->input = $input;

$verboseOutput = $output->getVerbosity() >= OutputInterface::VERBOSITY_VERBOSE
? $output
: new NullOutput();

try {
$aModuleIds = $this->_parseModuleIds();
$aShopConfigs = $this->_parseShopConfigs();
} catch (InputException $oEx) {
$output->writeLn($oEx->getMessage());
exit(1);
}

/** @var ModuleStateFixer $oModuleStateFixer */
$oModuleStateFixer = Registry::get(ModuleStateFixer::class);
$oModuleStateFixer->setOutput($output);
$oModuleStateFixer->setDebugOutput($verboseOutput);

/** @var Module $oModule */
$oModule = oxNew(Module::class);

foreach ($aShopConfigs as $oConfig) {
$moduleCount = count($aModuleIds);
$verboseOutput->writeLn('[DEBUG] Working on shop id ' . $oConfig->getShopId() . " fixing $moduleCount modules");

foreach ($aModuleIds as $sModuleId) {
$oModule->setMetaDataVersion(null);
if (!$oModule->load($sModuleId)) {
$verboseOutput->writeLn("[DEBUG] {$sModuleId} does not exist - skipping");
continue;
}

$verboseOutput->writeLn("[DEBUG] Fixing {$sModuleId} module");
$oModuleStateFixer->fix($oModule, $oConfig);
}

$verboseOutput->writeLn('');
}

$output->writeLn('Fixed module states successfully');
}

/**
* Parse and return module ids from input
*
* @return array
*
* @throws InputException
*/
protected function _parseModuleIds()
{
if ($this->input->getOption('all')) {
return $this->_getAvailableModuleIds();
}

if (count($this->input->getArguments()['module-id']) === 0) {
throw oxNew(
InputException::class,
'Please specify at least one module if as argument or use --all (-a) option'
);
}

$requestedModuleIds = $this->input->getArguments()['module-id'];
$availableModuleIds = $this->_getAvailableModuleIds();

// Checking if all provided module ids exist
foreach ($requestedModuleIds as $moduleId) {
if (!in_array($moduleId, $availableModuleIds)) {
throw oxNew(
InputException::class,
"{$moduleId} module does not exist"
);
}
}

return $requestedModuleIds;
}

/**
* Parse and return shop config objects from input
*
* @return ShopConfig[]
*
* @throws InputException
*/
protected function _parseShopConfigs()
{
if ($this->input->getOption('base-shop')) {
return array(Registry::getConfig());
}

if ($shopId = $this->input->getOption('shop')) {
if ($oConfig = ShopConfig::get($shopId)) {
return array($oConfig);
}

throw oxNew(
InputException::class,
'Shop id does not exist'
);
}

return ShopConfig::getAll();
}

/**
* Get all available module ids
*
* @return array
*/
protected function _getAvailableModuleIds()
{
if ($this->_aAvailableModuleIds === null) {
$oConfig = Registry::getConfig();

// We are calling getModulesFromDir() because we want to refresh
// the list of available modules. This is a workaround for OXID
// bug.
oxNew(ModuleList::class)->getModulesFromDir($oConfig->getModulesDir());
$this->_aAvailableModuleIds = array_keys($oConfig->getConfigParam('aModulePaths'));
}

return $this->_aAvailableModuleIds;
}
}
132 changes: 132 additions & 0 deletions Core/ModuleExtensionCleanerDebug.php
@@ -0,0 +1,132 @@
<?php
/**
* Created by PhpStorm.
* User: keywan
* Date: 23.11.18
* Time: 11:37
*/

namespace OxidCommunity\ModuleInternals\Core;


use OxidEsales\Eshop\Core\Module\ModuleExtensionsCleaner;
use OxidEsales\Eshop\Core\Registry;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;

class ModuleExtensionCleanerDebug extends ModuleExtensionsCleaner
{
protected $_debugOutput;

public function __construct()
{
$this->_debugOutput= new NullOutput();
}

public function setOutput(OutputInterface $out){

$this->_debugOutput = $out;
}

/**
* Removes garbage ( module not used extensions ) from all installed extensions list.
* For example: some classes were renamed, so these should be removed.
*
* @param array $installedExtensions
* @param \OxidEsales\Eshop\Core\Module\Module $module
*
* @return array
*/
public function cleanExtensions($installedExtensions, \OxidEsales\Eshop\Core\Module\Module $module)
{
$installedExtensions = parent::cleanExtensions($installedExtensions, $module);

$oModules = oxNew( \OxidEsales\EshopCommunity\Core\Module\ModuleList::class );
//ids will include garbage in case there are files that not registered by any module
$ids = $oModules->getModuleIds();

$config = Registry::getConfig();
$knownIds = array_keys($config->getConfigParam('aModulePaths'));
$diff = array_diff($ids,$knownIds);
if ($diff) {
foreach ($diff as $item) {
foreach ($installedExtensions as &$coreClassExtension) {
foreach ($coreClassExtension as $i => $ext) {
if ($ext === $item) {
$this->_debugOutput->writeln("$item will be removed");
unset($coreClassExtension[$i]);
}
}
}
}
}

return $installedExtensions;
}

protected function removeGarbage($aInstalledExtensions, $aarGarbage)
{
foreach ($aarGarbage as $moduleId => $aExt) {
$this->_debugOutput->writeLn("[INFO] removing garbage for module $moduleId: " . join(',', $aExt));
}
return parent::removeGarbage($aInstalledExtensions, $aarGarbage);
}

/**
* Returns extension which is no longer in metadata - garbage
*
* @param array $moduleMetaDataExtensions extensions defined in metadata.
* @param array $moduleInstalledExtensions extensions which are installed
*
* @return array
*/
protected function getModuleExtensionsGarbage($moduleMetaDataExtensions, $moduleInstalledExtensions)
{

$garbage = parent::getModuleExtensionsGarbage($moduleMetaDataExtensions, $moduleInstalledExtensions);

foreach ($moduleInstalledExtensions as $coreClassName => $listOfExtensions) {
foreach ($listOfExtensions as $extensions) {
if (! (isset($moduleMetaDataExtensions[$coreClassName]) && $moduleMetaDataExtensions[$coreClassName] == $extensions)) {
$garbage[$coreClassName][] = $extensions;
}
}
}

return $garbage;
}

/**
* Returns extensions list by module id.
*
* @param array $modules Module array (nested format)
* @param string $moduleId Module id/folder name
*
* @return array
*/
protected function filterExtensionsByModuleId($modules, $moduleId)
{
$modulePaths = \OxidEsales\Eshop\Core\Registry::getConfig()->getConfigParam('aModulePaths');

$path = '';
if (isset($modulePaths[$moduleId])) {
$path = $modulePaths[$moduleId] . '/';
}

// TODO: This condition should be removed. Need to check integration tests.
if (!$path) {
$path = $moduleId . "/";
}

$filteredModules = [];
foreach ($modules as $class => $extend) {
foreach ($extend as $extendPath) {
if (strpos($extendPath, $path) === 0) {
$filteredModules[$class][] = $extendPath;
}
}
}

return $filteredModules;
}
}

0 comments on commit 711344d

Please sign in to comment.