/** * This test creates an extension based on a JSON file, generated * with version 1.0 of the ExtensionBuilder and compares all * generated files with the originally created ones * This test should help, to find compatibility breaking changes * * @test */ function generateExtensionFromVersion3Configuration() { $this->configurationManager = $this->getMock($this->buildAccessibleProxy('EBT\\ExtensionBuilder\\Configuration\\ConfigurationManager'), array('dummy')); $this->extensionSchemaBuilder = $this->objectManager->get('EBT\\ExtensionBuilder\\Service\\ExtensionSchemaBuilder'); $testExtensionDir = $this->fixturesPath . 'TestExtensions/test_extension_v3/'; $jsonFile = $testExtensionDir . \EBT\ExtensionBuilder\Configuration\ConfigurationManager::EXTENSION_BUILDER_SETTINGS_FILE; if (file_exists($jsonFile)) { // compatibility adaptions for configurations from older versions $extensionConfigurationJSON = json_decode(file_get_contents($jsonFile), TRUE); $extensionConfigurationJSON = $this->configurationManager->fixExtensionBuilderJSON($extensionConfigurationJSON, FALSE); } else { $extensionConfigurationJSON = array(); $this->fail('JSON file not found'); } $this->extension = $this->extensionSchemaBuilder->build($extensionConfigurationJSON); $this->fileGenerator->setSettings(array('codeTemplateRootPath' => PATH_typo3conf . 'ext/extension_builder/Resources/Private/CodeTemplates/Extbase/', 'extConf' => array('enableRoundtrip' => '0'))); $newExtensionDir = vfsStream::url('testDir') . '/'; $this->extension->setExtensionDir($newExtensionDir . 'test_extension/'); $this->fileGenerator->build($this->extension); $referenceFiles = \TYPO3\CMS\Core\Utility\GeneralUtility::getAllFilesAndFoldersInPath(array(), $testExtensionDir); foreach ($referenceFiles as $referenceFile) { $createdFile = str_replace($testExtensionDir, $this->extension->getExtensionDir(), $referenceFile); if (!in_array(basename($createdFile), array('ExtensionBuilder.json'))) { $referenceFileContent = str_replace(array('2011-08-11T06:49:00Z', '2011-08-11', '###YEAR###', '2014'), array(date('Y-m-d\\TH:i:00\\Z'), date('Y-m-d'), date('Y'), date('Y')), file_get_contents($referenceFile)); $this->assertFileExists($createdFile, 'File ' . $createdFile . ' was not created!'); // do not compare files that contain a formatted DateTime, as it might have changed between file creation and this comparison if (strpos($referenceFile, 'xlf') === FALSE && strpos($referenceFile, 'yaml') === FALSE) { $originalLines = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(LF, $referenceFileContent, TRUE); $generatedLines = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(LF, file_get_contents($createdFile), TRUE); $this->assertEquals($originalLines, $generatedLines, 'File ' . $createdFile . ' was not equal to original file.'); } } } }
/** * Helper function to find the parents class recordType * @param \EBT\ExtensionBuilder\Domain\Model\DomainObject $domainObject * @return string */ public function render(\EBT\ExtensionBuilder\Domain\Model\DomainObject $domainObject) { $classSettings = $this->configurationManager->getExtbaseClassConfiguration($domainObject->getParentClass()); if (isset($classSettings['recordType'])) { $parentRecordType = \EBT\ExtensionBuilder\Utility\Tools::convertClassNameToRecordType($classSettings['recordType']); } else { $parentRecordType = \EBT\ExtensionBuilder\Utility\Tools::convertClassNameToRecordType($domainObject->getParentClass()); $existingTypes = $GLOBALS['TCA'][$domainObject->getDatabaseTableName()]['types']; \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('Parent Record type: ' . $parentRecordType, 'extension_builder', 2, $existingTypes); if (is_array($existingTypes) && !isset($existingTypes[$parentRecordType])) { // no types field for parent record type configured, use the default type 1 if (isset($existingTypes['1'])) { $parentRecordType = 1; } else { //if it not exists get first existing key $parentRecordType = reset(array_keys($existingTypes)); } } } $this->templateVariableContainer->add('parentModelName', end(explode('\\', $domainObject->getParentClass()))); $this->templateVariableContainer->add('parentRecordType', $parentRecordType); $content = $this->renderChildren(); $this->templateVariableContainer->remove('parentRecordType'); $this->templateVariableContainer->remove('parentModelName'); return $content; }
/** * @param \EBT\ExtensionBuilder\Domain\Model\Extension $extension */ public function saveExtensionConfiguration(\EBT\ExtensionBuilder\Domain\Model\Extension $extension) { $extensionBuildConfiguration = $this->configurationManager->getConfigurationFromModeler(); $extensionBuildConfiguration['log'] = array('last_modified' => date('Y-m-d h:i'), 'extension_builder_version' => \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::getExtensionVersion('extension_builder'), 'be_user' => $GLOBALS['BE_USER']->user['realName'] . ' (' . $GLOBALS['BE_USER']->user['uid'] . ')'); $encodeOptions = 0; // option JSON_PRETTY_PRINT is available since PHP 5.4.0 if (defined('JSON_PRETTY_PRINT')) { $encodeOptions |= JSON_PRETTY_PRINT; } \TYPO3\CMS\Core\Utility\GeneralUtility::writeFile($extension->getExtensionDir() . \EBT\ExtensionBuilder\Configuration\ConfigurationManager::EXTENSION_BUILDER_SETTINGS_FILE, json_encode($extensionBuildConfiguration, $encodeOptions)); }
/** * * @param array $relationJsonConfiguration * @param \EBT\ExtensionBuilder\Domain\Model\DomainObject $domainObject * @throws \Exception * @return \EBT\ExtensionBuilder\Domain\Model\DomainObject\Relation\AbstractRelation */ public function buildRelation($relationJsonConfiguration, $domainObject) { $relationSchemaClassName = 'EBT\\ExtensionBuilder\\Domain\\Model\\DomainObject\\Relation\\'; $relationSchemaClassName .= ucfirst($relationJsonConfiguration['relationType']) . 'Relation'; if (!class_exists($relationSchemaClassName)) { throw new \Exception('Relation of type ' . $relationSchemaClassName . ' not found (configured in "' . $relationJsonConfiguration['relationName'] . '")'); } /** * @var $relation \EBT\ExtensionBuilder\Domain\Model\DomainObject\Relation\AbstractRelation */ $relation = new $relationSchemaClassName(); $relation->setName($relationJsonConfiguration['relationName']); $relation->setLazyLoading((bool) $relationJsonConfiguration['lazyLoading']); $relation->setExcludeField($relationJsonConfiguration['propertyIsExcludeField']); $relation->setDescription($relationJsonConfiguration['relationDescription']); $relation->setUniqueIdentifier($relationJsonConfiguration['uid']); $relation->setType($relationJsonConfiguration['type']); if (!empty($relationJsonConfiguration['foreignRelationClass'])) { // relations without wires if (strpos($relationJsonConfiguration['foreignRelationClass'], '\\') > 0) { // add trailing slash if not set $relationJsonConfiguration['foreignRelationClass'] = '\\' . $relationJsonConfiguration['foreignRelationClass']; } $relation->setForeignClassName($relationJsonConfiguration['foreignRelationClass']); $relation->setRelatedToExternalModel(true); $extbaseClassConfiguration = $this->configurationManager->getExtbaseClassConfiguration($relationJsonConfiguration['foreignRelationClass']); if (isset($extbaseClassConfiguration['tableName'])) { $foreignDatabaseTableName = $extbaseClassConfiguration['tableName']; $this->relatedForeignTables[$foreignDatabaseTableName] = 1; } else { $foreignDatabaseTableName = Tools::parseTableNameFromClassName($relationJsonConfiguration['foreignRelationClass']); } $relation->setForeignDatabaseTableName($foreignDatabaseTableName); if ($relation instanceof \EBT\ExtensionBuilder\Domain\Model\DomainObject\Relation\ZeroToManyRelation) { $foreignKeyName = strtolower($domainObject->getName()); if (\EBT\ExtensionBuilder\Service\ValidationService::isReservedMYSQLWord($foreignKeyName)) { $foreignKeyName = 'tx_' . $foreignKeyName; } if (isset($this->relatedForeignTables[$foreignDatabaseTableName])) { $foreignKeyName .= $this->relatedForeignTables[$foreignDatabaseTableName]; $this->relatedForeignTables[$foreignDatabaseTableName] += 1; } else { $foreignDatabaseTableName = Tools::parseTableNameFromClassName($relationJsonConfiguration['foreignRelationClass']); } $relation->setForeignDatabaseTableName($foreignDatabaseTableName); } if ($relation->isFileReference() && !empty($relationJsonConfiguration['maxItems'])) { /** @var $relation \EBT\ExtensionBuilder\Domain\Model\DomainObject\FileProperty */ $relation->setMaxItems($relationJsonConfiguration['maxItems']); if (!empty($relationJsonConfiguration['allowedFileTypes'])) { $relation->setAllowedFileTypes($relationJsonConfiguration['allowedFileTypes']); } } } return $relation; }
/** * Find the mapped table for a foreign related class * @test */ public function anyToManyRelationToForeignClassBuildsCorrectRelationTableName() { $domainObjectName1 = 'DomainObject1'; $description = 'My long domain object description'; $relationName = 'Relation1'; $className = '\\TYPO3\\CMS\\Extbase\\Domain\\Model\\FrontendUser'; $input = array('name' => $domainObjectName1, 'objectsettings' => array('description' => $description, 'aggregateRoot' => TRUE, 'type' => 'Entity'), 'relationGroup' => array('relations' => array(0 => array('relationName' => $relationName, 'relationType' => 'zeroToMany', 'propertyIsExcludeField' => FALSE, 'foreignRelationClass' => $className)))); $extbaseConfiguration = array('tableName' => 'fe_users'); $this->configurationManager->expects($this->atLeastOnce())->method('getExtbaseClassConfiguration')->with($className)->will($this->returnValue($extbaseConfiguration)); $domainObject1 = $this->objectSchemaBuilder->build($input); $relation = $domainObject1->getPropertyByName($relationName); $this->assertFalse($relation->getUseMMTable(), 'ZeroToMany Relation->getUseMMTable() returned TRUE.'); $this->assertEquals('fe_users', $relation->getForeignDatabaseTableName()); }
/** * * create a new class object based on the template and the related domain object * * @param \EBT\ExtensionBuilder\Domain\Model\DomainObject $domainObject * * @return void */ protected function createNewModelClassObject($domainObject) { $this->classFileObject = clone $this->templateFileObject; $this->classObject = clone $this->templateFileObject->getFirstClass(); $this->classObject->resetAll(); // start with plain class $this->classObject->setName($domainObject->getName()); if ($domainObject->isEntity()) { $parentClass = $domainObject->getParentClass(); if (empty($parentClass)) { $parentClass = $this->configurationManager->getParentClassForEntityObject($this->extension->getExtensionKey()); } } else { $parentClass = $this->configurationManager->getParentClassForValueObject($this->extension->getExtensionKey()); } $this->classObject->setParentClassName($parentClass); $this->classObject->setDescription($domainObject->getDescription()); }
/** * @test */ public function getExtbaseClassConfigurationReturnsCorrectValue() { $classConfiguration = $this->configurationManager->getExtbaseClassConfiguration('TYPO3\\CMS\\Extbase\\Domain\\Model\\FrontendUser'); self::assertSame($classConfiguration['tableName'], 'fe_users'); }
/** * @param \EBT\ExtensionBuilder\Domain\Model\Extension $extension * @param array $propertyConfiguration * @return void */ protected function setExtensionProperties(&$extension, $propertyConfiguration) { // name $extension->setName(trim($propertyConfiguration['name'])); // description $extension->setDescription($propertyConfiguration['description']); // extensionKey $extension->setExtensionKey(trim($propertyConfiguration['extensionKey'])); // vendorName $extension->setVendorName(trim($propertyConfiguration['vendorName'])); if (!empty($propertyConfiguration['emConf']['sourceLanguage'])) { $extension->setSourceLanguage($propertyConfiguration['emConf']['sourceLanguage']); } if ($propertyConfiguration['emConf']['disableVersioning']) { $extension->setSupportVersioning(false); } if ($propertyConfiguration['emConf']['disableLocalization']) { $extension->setSupportLocalization(false); } if (!empty($propertyConfiguration['emConf']['skipGenerateDocumentationTemplate'])) { $extension->setGenerateDocumentationTemplate(false); } // various extension properties $extension->setVersion($propertyConfiguration['emConf']['version']); if (!empty($propertyConfiguration['emConf']['dependsOn'])) { $dependencies = array(); $lines = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode(LF, $propertyConfiguration['emConf']['dependsOn']); foreach ($lines as $line) { if (strpos($line, '=>')) { list($extensionKey, $version) = \TYPO3\CMS\Core\Utility\GeneralUtility::trimExplode('=>', $line); $dependencies[$extensionKey] = $version; } } $extension->setDependencies($dependencies); } if (!empty($propertyConfiguration['emConf']['targetVersion'])) { $extension->setTargetVersion(floatval($propertyConfiguration['emConf']['targetVersion'])); } if (!empty($propertyConfiguration['emConf']['custom_category'])) { $category = $propertyConfiguration['emConf']['custom_category']; } else { $category = $propertyConfiguration['emConf']['category']; } $extension->setCategory($category); // state $state = 0; switch ($propertyConfiguration['emConf']['state']) { case 'alpha': $state = \EBT\ExtensionBuilder\Domain\Model\Extension::STATE_ALPHA; break; case 'beta': $state = \EBT\ExtensionBuilder\Domain\Model\Extension::STATE_BETA; break; case 'stable': $state = \EBT\ExtensionBuilder\Domain\Model\Extension::STATE_STABLE; break; case 'experimental': $state = \EBT\ExtensionBuilder\Domain\Model\Extension::STATE_EXPERIMENTAL; break; case 'test': $state = \EBT\ExtensionBuilder\Domain\Model\Extension::STATE_TEST; break; } $extension->setState($state); if (!empty($propertyConfiguration['originalExtensionKey'])) { // handle renaming of extensions // original extensionKey $extension->setOriginalExtensionKey($propertyConfiguration['originalExtensionKey']); \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('Extension setOriginalExtensionKey:' . $extension->getOriginalExtensionKey(), 'extbase', 0, $propertyConfiguration); } if (!empty($propertyConfiguration['originalExtensionKey']) && $extension->getOriginalExtensionKey() != $extension->getExtensionKey()) { $settings = $this->configurationManager->getExtensionSettings($extension->getOriginalExtensionKey()); // if an extension was renamed, a new extension dir is created and we // have to copy the old settings file to the new extension dir copy($this->configurationManager->getSettingsFile($extension->getOriginalExtensionKey()), $this->configurationManager->getSettingsFile($extension->getExtensionKey())); } else { $settings = $this->configurationManager->getExtensionSettings($extension->getExtensionKey()); } if (!empty($settings)) { $extension->setSettings($settings); \TYPO3\CMS\Core\Utility\GeneralUtility::devLog('Extension settings:' . $extension->getExtensionKey(), 'extbase', 0, $extension->getSettings()); } }
/** * cover all cases: * 1. extend TYPO3 class like fe_users (no mapping table needed) * * @param \EBT\ExtensionBuilder\Domain\Model\DomainObject $domainObject */ private function validateMapping(\EBT\ExtensionBuilder\Domain\Model\DomainObject $domainObject) { $parentClass = $domainObject->getParentClass(); $tableName = $domainObject->getMapToTable(); $extensionPrefix = 'Tx_' . GeneralUtility::underscoredToUpperCamelCase($domainObject->getExtension()->getExtensionKey()) . '_Domain_Model_'; if (!empty($parentClass)) { $classConfiguration = $this->configurationManager->getExtbaseClassConfiguration($parentClass); GeneralUtility::devlog('class settings ' . $parentClass, 'extension_builder', 0, $classConfiguration); if (!isset($classConfiguration['tableName'])) { if (!$tableName) { $this->validationResult['errors'][] = new ExtensionException('Mapping configuration error in domain object ' . $domainObject->getName() . ': ' . LF . 'The mapping table could not be detected from Extbase Configuration. Please enter a table name', self::ERROR_MAPPING_NO_TABLE); } } else { // get the table name from the parent class configuration $tableName = $classConfiguration['tableName']; } if (!class_exists($parentClass, TRUE)) { $this->validationResult['errors'][] = new ExtensionException('Mapping configuration error in domain object ' . $domainObject->getName() . ': the parent class ' . LF . $parentClass . 'seems not to exist ', self::ERROR_MAPPING_NO_PARENTCLASS); } } if ($tableName) { if (in_array($tableName, array('tt_content', 'pages')) || preg_match("/^(pages_|be_|sys_|static_|cf_)/", $tableName)) { $this->validationResult['warnings'][] = new ExtensionException('The configuration for table "' . $tableName . '" is not compatible' . LF . ' with extbase. You have to configure it yourself if you want to map' . LF . ' to this table', self::ERROR_MAPPING_TO_INCOMPATIBLE_TABLE); } if (strpos($extensionPrefix, $tableName) !== FALSE) { // the domainObject extends a class of the same extension if (!$parentClass) { $this->validationResult['errors'][] = new ExtensionException('Mapping configuration error in domain object ' . $domainObject->getName() . ': you have to define' . LF . 'a parent class if you map to a table of another domain object of the same extension ', self::ERROR_MAPPING_NO_PARENTCLASS); } } if (!isset($GLOBALS['TCA'][$tableName])) { $this->validationResult['errors'][] = new ExtensionException('There is no entry for table "' . $tableName . '" of ' . $domainObject->getName() . ' in TCA. ' . LF . 'For technical reasons you can only extend tables with TCA configuration.', self::ERROR_MAPPING_NO_TCA); } } if (isset($GLOBALS['TCA'][$tableName]['ctrl']['type'])) { $dataTypeRes = $this->getDatabaseConnection()->sql_query('DESCRIBE ' . $tableName); while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($dataTypeRes)) { if ($row['Field'] == $GLOBALS['TCA'][$tableName]['ctrl']['type']) { if (strpos($row['Type'], 'int') !== FALSE) { $this->validationResult['warnings'][] = new ExtensionException('The configured type field for table "' . $tableName . '" is of type ' . $row['Type'] . '' . LF . 'This means the type field can not be used for defining the record type. ' . LF . 'You have to configure the mappings yourself if you want to map to this' . LF . 'table or extend the correlated class', self::ERROR_MAPPING_WRONG_TYPEFIELD_CONFIGURATION); } } } } }
/** * parse existing tca and set appropriate properties * * @param \EBT\ExtensionBuilder\Domain\Model\Extension $extension * @return void */ public static function prepareExtensionForRoundtrip(&$extension) { foreach ($extension->getDomainObjects() as $domainObject) { $existingTca = self::getTcaForDomainObject($domainObject, $extension); if ($existingTca) { foreach ($domainObject->getAnyToManyRelationProperties() as $relationProperty) { if (isset($existingTca['columns'][$relationProperty->getName()]['config']['MM'])) { self::log('Relation table for Model ' . $domainObject->getName() . ' relation ' . $relationProperty->getName(), 0, $existingTca['columns'][$relationProperty->getName()]['config']); $relationProperty->setRelationTableName($existingTca['columns'][$relationProperty->getName()]['config']['MM']); } } } if (file_exists($extension->getExtensionDir() . 'Configuration/TCA/' . $domainObject->getName() . '.php')) { $extensionConfigurationJson = \EBT\ExtensionBuilder\Configuration\ConfigurationManager::getExtensionBuilderJson($extension->getExtensionKey()); if (floatval($extensionConfigurationJson['log']['extension_builder_version']) <= 6.2) { self::moveAdditionalTcaToOverrideFile($domainObject); } } } }
/** * This method is the main part of the roundtrip functionality * It looks for a previous version of the current domain object and * parses the existing class file for that domain model * compares all properties and methods with the previous version. * * Methods are either removed/added or updated according to * the new property names * * @param \EBT\ExtensionBuilder\Domain\Model\DomainObject $domainObject The new domain object * * @return \EBT\ExtensionBuilder\Domain\Model\ClassObject\ClassObject OR NULL */ public function getDomainModelClassFile(Model\DomainObject $currentDomainObject) { if (isset($this->previousDomainObjects[$currentDomainObject->getUniqueIdentifier()])) { $this->log('domainObject identified:' . $currentDomainObject->getName()); $oldDomainObject = $this->previousDomainObjects[$currentDomainObject->getUniqueIdentifier()]; /** @var \EBT\ExtensionBuilder\Domain\Model\DomainObject $oldDomainObject */ $extensionDir = $this->previousExtensionDirectory; $fileName = FileGenerator::getFolderForClassFile($extensionDir, 'Model', FALSE) . $oldDomainObject->getName() . '.php'; if (file_exists($fileName)) { // import the classObject from the existing file $this->classFileObject = $this->parserService->parseFile($fileName); $this->classObject = $this->classFileObject->getFirstClass(); if ($oldDomainObject->getName() != $currentDomainObject->getName() || $this->extensionRenamed) { if (!$this->extensionRenamed) { $this->log('domainObject renamed. old: ' . $oldDomainObject->getName() . ' new: ' . $currentDomainObject->getName(), 'extension_builder'); } $newClassName = $currentDomainObject->getName(); $this->classObject->setName($newClassName); $this->classObject->setFileName($currentDomainObject->getName() . '.php'); $this->cleanUp(FileGenerator::getFolderForClassFile($extensionDir, 'Model'), $oldDomainObject->getName() . '.php'); $this->cleanUp($extensionDir . 'Configuration/TCA/', $oldDomainObject->getName() . '.php'); } else { $this->classObject->setName($currentDomainObject->getName()); } $this->updateModelClassProperties($oldDomainObject, $currentDomainObject); $newActions = array(); foreach ($currentDomainObject->getActions() as $newAction) { $newActions[$newAction->getName()] = $newAction; } $oldActions = $oldDomainObject->getActions(); if (empty($newActions) && !$currentDomainObject->isAggregateRoot() && (!empty($oldActions) || $oldDomainObject->isAggregateRoot())) { // remove the controller $this->cleanUp(FileGenerator::getFolderForClassFile($extensionDir, 'Controller'), $oldDomainObject->getName() . 'Controller.php'); } // the parent class settings configuration $parentClass = $currentDomainObject->getParentClass(); $oldParentClass = $oldDomainObject->getParentClass(); if (!empty($parentClass)) { if ($oldParentClass != $parentClass) { // the parent class was just new added $this->classObject->setParentClassName($parentClass); } } elseif (!empty($oldParentClass)) { // the old object had a parent class setting, but it's removed now if ($currentDomainObject->isEntity()) { $parentClass = $this->configurationManager->getParentClassForEntityObject($this->extension->getExtensionKey()); } else { $parentClass = $this->configurationManager->getParentClassForValueObject($this->extension->getExtensionKey()); } $this->classObject->setParentClassName($parentClass); } if ($currentDomainObject->isEntity() && !$oldDomainObject->isEntity()) { // the object type was changed in the modeler $this->classObject->setParentClassName($this->configurationManager->getParentClassForEntityObject($this->extension->getExtensionKey())); } elseif (!$currentDomainObject->isEntity() && $oldDomainObject->isEntity()) { // the object type was changed in the modeler $this->classObject->setParentClassName($this->configurationManager->getParentClassForValueObject($this->extension->getExtensionKey())); } $this->classFileObject->setClasses(array($this->classObject)); return $this->classFileObject; } else { GeneralUtility::devLog('class file didn\'t exist:' . $fileName, 'extension_builder', 0); } } else { $this->log('domainObject not identified:' . $currentDomainObject->getName(), 0, $this->previousDomainObjects); $fileName = FileGenerator::getFolderForClassFile($this->extensionDirectory, 'Model', FALSE); $fileName .= $currentDomainObject->getName() . '.php'; if (file_exists($fileName)) { // import the classObject from the existing file $this->classFileObject = $this->parserService->parseFile($fileName); $this->classObject = $this->classFileObject->getFirstClass(); $this->classObject->setFileName($fileName); $this->classObject->setName($currentDomainObject->getName()); $this->log('class file found:' . $currentDomainObject->getName() . '.php', 0, $this->classObject->getNamespaceName()); $this->classFileObject->setClasses(array($this->classObject)); return $this->classFileObject; } } return NULL; }
/** * @return array */ protected function rpcActionPerformDbUpdate() { $params = $this->configurationManager->getParamsFromRequest(); return $this->extensionInstallationStatus->performDbUpdates($params); }