/** * @return void */ public function indexAction() { $packageGroups = array(); foreach ($this->packageManager->getAvailablePackages() as $package) { /** @var \TYPO3\Flow\Package $package */ $packagePath = substr($package->getPackagepath(), strlen(FLOW_PATH_PACKAGES)); $packageGroup = substr($packagePath, 0, strpos($packagePath, '/')); $packageGroups[$packageGroup][$package->getPackageKey()] = array('sanitizedPackageKey' => str_replace('.', '', $package->getPackageKey()), 'version' => $package->getPackageMetaData()->getVersion(), 'name' => $package->getComposerManifest('name'), 'type' => $package->getComposerManifest('type'), 'description' => $package->getPackageMetaData()->getDescription(), 'metaData' => $package->getPackageMetaData(), 'isActive' => $this->packageManager->isPackageActive($package->getPackageKey()), 'isFrozen' => $this->packageManager->isPackageFrozen($package->getPackageKey()), 'isProtected' => $package->isProtected()); } ksort($packageGroups); foreach (array_keys($packageGroups) as $packageGroup) { ksort($packageGroups[$packageGroup]); } $this->view->assignMultiple(array('packageGroups' => $packageGroups, 'isDevelopmentContext' => $this->objectManager->getContext()->isDevelopment())); }
/** * @param string $packageKey * @return bool */ public function getMissingPackageRequirements($packageKey) { if (property_exists($this->packageManager->getAvailablePackages()[$packageKey]->getComposerManifest(), 'require') == true) { $requiredPackages = $this->packageManager->getAvailablePackages()[$packageKey]->getComposerManifest()->require; foreach (array_keys((array) $requiredPackages) as $requiredPackageName) { // Simple check if requirement is a package if (strpos($requiredPackageName, '/') === false) { continue; } if ($this->isPackageActiveByName($requiredPackageName) === false) { return $requiredPackageName; } } return false; } }
/** * Generate a new migration * * If $diffAgainstCurrent is TRUE (the default), it generates a migration file * with the diff between current DB structure and the found mapping metadata. * * Otherwise an empty migration skeleton is generated. * * Only includes tables/sequences matching the $filterExpression regexp when * diffing models and existing schema. Include delimiters in the expression! * The use of * * --filter-expression '/^acme_com/' * * would only create a migration touching tables starting with "acme_com". * * Note: A filter-expression will overrule any filter configured through the * TYPO3.Flow.persistence.doctrine.migrations.ignoredTables setting * * @param boolean $diffAgainstCurrent Whether to base the migration on the current schema structure * @param string $filterExpression Only include tables/sequences matching the filter expression regexp * @return void * @see typo3.flow:doctrine:migrate * @see typo3.flow:doctrine:migrationstatus * @see typo3.flow:doctrine:migrationexecute * @see typo3.flow:doctrine:migrationversion */ public function migrationGenerateCommand($diffAgainstCurrent = true, $filterExpression = null) { // "driver" is used only for Doctrine, thus we (mis-)use it here // additionally, when no host is set, skip this step, assuming no DB is needed if (!$this->isDatabaseConfigured()) { $this->outputLine('Doctrine migration generation has been SKIPPED, the driver and host backend options are not set in /Configuration/Settings.yaml.'); $this->quit(1); } // use default filter expression from settings if ($filterExpression === null) { $ignoredTables = array_keys(array_filter($this->settings['doctrine']['migrations']['ignoredTables'])); if ($ignoredTables !== array()) { $filterExpression = sprintf('/^(?!%s$).*$/xs', implode('$|', $ignoredTables)); } } list($status, $migrationClassPathAndFilename) = $this->doctrineService->generateMigration($diffAgainstCurrent, $filterExpression); $this->outputLine('<info>%s</info>', [$status]); $this->outputLine(); if ($migrationClassPathAndFilename) { $choices = ['Don\'t Move']; $packages = [null]; /** @var Package $package */ foreach ($this->packageManager->getAvailablePackages() as $package) { $type = $package->getComposerManifest('type'); if ($type === null || strpos($type, 'typo3-') !== 0 && strpos($type, 'neos-') !== 0) { continue; } $choices[] = $package->getPackageKey(); $packages[] = $package; } $selectedPackageIndex = (int) $this->output->select('Do you want to move the migration to one of these packages?', $choices, 0); $this->outputLine(); if ($selectedPackageIndex !== 0) { /** @var Package $selectedPackage */ $selectedPackage = $packages[$selectedPackageIndex]; $targetPathAndFilename = Files::concatenatePaths([$selectedPackage->getPackagePath(), 'Migrations', $this->doctrineService->getDatabasePlatformName(), basename($migrationClassPathAndFilename)]); Files::createDirectoryRecursively(dirname($targetPathAndFilename)); rename($migrationClassPathAndFilename, $targetPathAndFilename); $this->outputLine('The migration was moved to: <comment>%s</comment>', [substr($targetPathAndFilename, strlen(FLOW_PATH_PACKAGES))]); $this->outputLine(); $this->outputLine('Next Steps:'); } else { $this->outputLine('Next Steps:'); $this->outputLine(sprintf('- Move <comment>%s</comment> to YourPackage/<comment>Migrations/%s/</comment>', $migrationClassPathAndFilename, $this->doctrineService->getDatabasePlatformName())); } $this->outputLine('- Review and adjust the generated migration.'); $this->outputLine('- (optional) execute the migration using <comment>%s doctrine:migrate</comment>', [$this->getFlowInvocationString()]); } }
/** * Tries to find out a package key which the Version belongs to. If no * package could be found, an empty string is returned. * * @param Version $version * @return string */ protected function getPackageKeyFromMigrationVersion(Version $version) { $sortedAvailablePackages = $this->packageManager->getAvailablePackages(); usort($sortedAvailablePackages, function (PackageInterface $packageOne, PackageInterface $packageTwo) { return strlen($packageTwo->getPackagePath()) - strlen($packageOne->getPackagePath()); }); $reflectedClass = new \ReflectionClass($version->getMigration()); $classPathAndFilename = Files::getUnixStylePath($reflectedClass->getFileName()); /** @var $package PackageInterface */ foreach ($sortedAvailablePackages as $package) { $packagePath = Files::getUnixStylePath($package->getPackagePath()); if (strpos($classPathAndFilename, $packagePath) === 0) { return $package->getPackageKey(); } } return ''; }
/** * Refreeze a package * * Refreezes a currently frozen package: all precompiled information is removed * and file monitoring will consider the package exactly once, on the next * request. After that request, the package remains frozen again, just with the * updated data. * * By specifying <b>all</b> as a package key, all currently frozen packages are * refrozen (the default). * * @param string $packageKey Key of the package to refreeze, or 'all' * @return void * @see typo3.flow:package:freeze * @see typo3.flow:cache:flush */ public function refreezeCommand($packageKey = 'all') { if (!$this->bootstrap->getContext()->isDevelopment()) { $this->outputLine('Package freezing is only supported in Development context.'); $this->quit(3); } $packagesToRefreeze = []; if ($packageKey === 'all') { foreach (array_keys($this->packageManager->getAvailablePackages()) as $packageKey) { if ($this->packageManager->isPackageFrozen($packageKey)) { $packagesToRefreeze[] = $packageKey; } } if ($packagesToRefreeze === []) { $this->outputLine('Nothing to do, no packages were frozen.'); $this->quit(0); } } else { if ($packageKey === null) { $this->outputLine('You must specify a package to refreeze.'); $this->quit(1); } if (!$this->packageManager->isPackageAvailable($packageKey)) { $this->outputLine('Package "%s" is not available.', [$packageKey]); $this->quit(2); } if (!$this->packageManager->isPackageFrozen($packageKey)) { $this->outputLine('Package "%s" was not frozen.', [$packageKey]); $this->quit(0); } $packagesToRefreeze = [$packageKey]; } foreach ($packagesToRefreeze as $packageKey) { $this->packageManager->refreezePackage($packageKey); $this->outputLine('Refroze package "%s".', [$packageKey]); } Scripts::executeCommand('typo3.flow:cache:flush', $this->settings, false); $this->sendAndExit(0); }
/** * Generate a new migration * * If $diffAgainstCurrent is TRUE (the default), it generates a migration file * with the diff between current DB structure and the found mapping metadata. * * Otherwise an empty migration skeleton is generated. * * @param boolean $diffAgainstCurrent Whether to base the migration on the current schema structure * @return void * @see typo3.flow:doctrine:migrate * @see typo3.flow:doctrine:migrationstatus * @see typo3.flow:doctrine:migrationexecute * @see typo3.flow:doctrine:migrationversion */ public function migrationGenerateCommand($diffAgainstCurrent = TRUE) { // "driver" is used only for Doctrine, thus we (mis-)use it here // additionally, when no path is set, skip this step, assuming no DB is needed if ($this->settings['backendOptions']['driver'] === NULL || $this->settings['backendOptions']['host'] === NULL) { $this->outputLine('Doctrine migration generation has been SKIPPED, the driver and host backend options are not set in /Configuration/Settings.yaml.'); $this->quit(1); } $migrationClassPathAndFilename = $this->doctrineService->generateMigration($diffAgainstCurrent); $choices = array('Don\'t Move'); $packages = array(NULL); /** @var Package $package */ foreach ($this->packageManager->getAvailablePackages() as $package) { $manifest = $package->getComposerManifest(); if (!isset($manifest->type) || strpos($manifest->type, 'typo3-') !== 0) { continue; } $choices[] = $package->getPackageKey(); $packages[] = $package; } $selectedPackageIndex = (int) $this->output->select('Do you want to move the migration to one of these Packages?', $choices, 0); $this->outputLine('<info>Generated new migration class!</info>'); $this->outputLine(''); if ($selectedPackageIndex !== 0) { /** @var Package $selectedPackage */ $selectedPackage = $packages[$selectedPackageIndex]; $targetPathAndFilename = Files::concatenatePaths(array($selectedPackage->getPackagePath(), 'Migrations', $this->doctrineService->getDatabasePlatformName(), basename($migrationClassPathAndFilename))); Files::createDirectoryRecursively(dirname($targetPathAndFilename)); rename($migrationClassPathAndFilename, $targetPathAndFilename); $this->outputLine('The migration was moved to %s.', array(substr($targetPathAndFilename, strlen(FLOW_PATH_PACKAGES)))); $this->outputLine('Next Steps:'); } else { $this->outputLine('Next Steps:'); $this->outputLine(sprintf('- Move <comment>%s</comment> to YourPackage/<comment>Migrations/%s/</comment>', $migrationClassPathAndFilename, $this->doctrineService->getDatabasePlatformName())); } $this->outputLine('- Review and adjust the generated migration.'); $this->outputLine('- (optional) execute the migration using <comment>%s doctrine:migrate</comment>', array($this->getFlowInvocationString())); }
/** * Checks which classes lack a cache entry and removes their reflection data * accordingly. * * @return void */ protected function forgetChangedClasses() { $frozenNamespaces = []; /** @var $package Package */ foreach ($this->packageManager->getAvailablePackages() as $packageKey => $package) { if ($this->packageManager->isPackageFrozen($packageKey)) { $frozenNamespaces[] = $package->getNamespace(); } } $classNames = array_keys($this->classReflectionData); foreach ($frozenNamespaces as $namespace) { $namespace .= '\\'; foreach ($classNames as $index => $className) { if (strpos($className, $namespace) === 0) { unset($classNames[$index]); } } } foreach ($classNames as $className) { if (!$this->statusCache->has($this->produceCacheIdentifierFromClassName($className))) { $this->forgetClass($className); } } }
/** * Checks which classes lack a cache entry and removes their reflection data * accordingly. * * @return void */ protected function forgetChangedClasses() { $frozenNamespaces = array(); /** @var $package \TYPO3\Flow\Package */ foreach ($this->packageManager->getAvailablePackages() as $packageKey => $package) { if ($this->packageManager->isPackageFrozen($packageKey)) { $frozenNamespaces[] = $package->getNamespace(); } } $classNames = array_keys($this->classReflectionData); foreach ($frozenNamespaces as $namespace) { $namespace .= '\\'; $namespaceLength = strlen($namespace); foreach ($classNames as $index => $className) { if (substr($className, 0, $namespaceLength) === $namespace) { unset($classNames[$index]); } } } foreach ($classNames as $className) { if (!$this->statusCache->has(str_replace('\\', '_', $className))) { $this->forgetClass($className); } } }
/** * Initialize action */ public function initializeAction() { $this->availablePackages = $this->packageManager->getAvailablePackages(); $this->activePackages = $this->packageManager->getActivePackages(); }