/** * Iterate through the segments of the current request path * find the corresponding module configuration and set controller & action * accordingly * * @param string $value * @return boolean|integer */ protected function matchValue($value) { $format = pathinfo($value, PATHINFO_EXTENSION); if ($format !== '') { $value = substr($value, 0, strlen($value) - strlen($format) - 1); } $segments = Arrays::trimExplode('/', $value); $currentModuleBase = $this->settings['modules']; if ($segments === array() || !isset($currentModuleBase[$segments[0]])) { return self::MATCHRESULT_NOSUCHMODULE; } $modulePath = array(); $level = 0; $moduleConfiguration = null; $moduleController = null; $moduleAction = 'index'; foreach ($segments as $segment) { if (isset($currentModuleBase[$segment])) { $modulePath[] = $segment; $moduleConfiguration = $currentModuleBase[$segment]; if (isset($moduleConfiguration['controller'])) { $moduleController = $moduleConfiguration['controller']; } else { $moduleController = null; } if (isset($moduleConfiguration['submodules'])) { $currentModuleBase = $moduleConfiguration['submodules']; } else { $currentModuleBase = array(); } } else { if ($level === count($segments) - 1) { $moduleMethods = array_change_key_case(array_flip(get_class_methods($moduleController)), CASE_LOWER); if (array_key_exists($segment . 'action', $moduleMethods)) { $moduleAction = $segment; break; } } return self::MATCHRESULT_NOSUCHMODULE; } $level++; } if ($moduleController === null) { return self::MATCHRESULT_NOCONTROLLER; } $this->value = array('module' => implode('/', $modulePath), 'controller' => $moduleController, 'action' => $moduleAction); if ($format !== '') { $this->value['format'] = $format; } return self::MATCHRESULT_FOUND; }
/** * Kickstart a new command controller * * Creates a new command controller with the given name in the specified * package. The generated controller class already contains an example command. * * @param string $packageKey The package key of the package for the new controller * @param string $controllerName The name for the new controller. This may also be a comma separated list of controller names. * @param boolean $force Overwrite any existing controller. * @return string * @see neos.kickstarter:kickstart:actioncontroller */ public function commandControllerCommand($packageKey, $controllerName, $force = false) { $this->validatePackageKey($packageKey); if (!$this->packageManager->isPackageAvailable($packageKey)) { $this->outputLine('Package "%s" is not available.', array($packageKey)); exit(2); } $generatedFiles = array(); $controllerNames = Arrays::trimExplode(',', $controllerName); foreach ($controllerNames as $currentControllerName) { $generatedFiles += $this->generatorService->generateCommandController($packageKey, $currentControllerName, $force); } $this->outputLine(implode(PHP_EOL, $generatedFiles)); }
/** * Create a new user * * This command creates a new user which has access to the backend user interface. * * More specifically, this command will create a new user and a new account at the same time. The created account * is, by default, a Neos backend account using the the "Typo3BackendProvider" for authentication. The given username * will be used as an account identifier for that new account. * * If an authentication provider name is specified, the new account will be created for that provider instead. * * Roles for the new user can optionally be specified as a comma separated list. For all roles provided by * Neos, the role namespace "Neos.Neos:" can be omitted. * * @param string $username The username of the user to be created, used as an account identifier for the newly created account * @param string $password Password of the user to be created * @param string $firstName First name of the user to be created * @param string $lastName Last name of the user to be created * @param string $roles A comma separated list of roles to assign. Examples: "Editor, Acme.Foo:Reviewer" * @param string $authenticationProvider Name of the authentication provider to use for the new account. Example: "Typo3BackendProvider" * @return void */ public function createCommand($username, $password, $firstName, $lastName, $roles = null, $authenticationProvider = null) { $user = $this->userService->getUser($username, $authenticationProvider); if ($user instanceof User) { $this->outputLine('The username "%s" is already in use', array($username)); $this->quit(1); } try { if ($roles === null) { $user = $this->userService->createUser($username, $password, $firstName, $lastName, null, $authenticationProvider); } else { $roleIdentifiers = Arrays::trimExplode(',', $roles); $user = $this->userService->createUser($username, $password, $firstName, $lastName, $roleIdentifiers, $authenticationProvider); } $roleIdentifiers = array(); foreach ($user->getAccounts() as $account) { /** @var Account $account */ foreach ($account->getRoles() as $role) { /** @var Role $role */ $roleIdentifiers[$role->getIdentifier()] = true; } } $roleIdentifiers = array_keys($roleIdentifiers); if (count($roleIdentifiers) === 0) { $this->outputLine('Created user "%s".', array($username)); $this->outputLine('<b>Please note that this user currently does not have any roles assigned.</b>'); } else { $this->outputLine('Created user "%s" and assigned the following role%s: %s.', array($username, count($roleIdentifiers) > 1 ? 's' : '', implode(', ', $roleIdentifiers))); } } catch (\Exception $exception) { $this->outputLine($exception->getMessage()); $this->quit(1); } }
/** * A method which runs the task implemented by the plugin for the given command * * @param string $controllerCommandName Name of the command in question, for example "repair" * @param ConsoleOutput $output An instance of ConsoleOutput which can be used for output or dialogues * @param NodeType $nodeType Only handle this node type (if specified) * @param string $workspaceName Only handle this workspace (if specified) * @param boolean $dryRun If TRUE, don't do any changes, just simulate what you would do * @param boolean $cleanup If FALSE, cleanup tasks are skipped * @param string $skip Skip the given check or checks (comma separated) * @param string $only Only execute the given check or checks (comma separated) * @return void */ public function invokeSubCommand($controllerCommandName, ConsoleOutput $output, NodeType $nodeType = null, $workspaceName = 'live', $dryRun = false, $cleanup = true, $skip = null, $only = null) { $this->output = $output; $commandMethods = ['generateUriPathSegments' => ['cleanup' => false], 'removeContentDimensionsFromRootAndSitesNode' => ['cleanup' => true]]; $skipCommandNames = Arrays::trimExplode(',', $skip === null ? '' : $skip); $onlyCommandNames = Arrays::trimExplode(',', $only === null ? '' : $only); switch ($controllerCommandName) { case 'repair': foreach ($commandMethods as $commandMethodName => $commandMethodConfiguration) { if (in_array($commandMethodName, $skipCommandNames)) { continue; } if ($onlyCommandNames !== [] && !in_array($commandMethodName, $onlyCommandNames)) { continue; } if (!$cleanup && $commandMethodConfiguration['cleanup']) { continue; } $this->{$commandMethodName}($workspaceName, $dryRun, $nodeType); } } }
/** * @Then /^I can (not )?call the method "([^"]*)" of class "([^"]*)"(?: with arguments "([^"]*)")?$/ */ public function iCanCallTheMethodOfClassWithArguments($not, $methodName, $className, $arguments = '') { if ($this->isolated === true) { $this->callStepInSubProcess(__METHOD__, sprintf(' %s %s %s %s %s %s %s %s', 'string', escapeshellarg(trim($not)), 'string', escapeshellarg($methodName), 'string', escapeshellarg($className), 'string', escapeshellarg($arguments))); } else { $this->setupSecurity(); $instance = $this->objectManager->get($className); try { $result = call_user_func_array([$instance, $methodName], Arrays::trimExplode(',', $arguments)); if ($not === 'not') { Assert::fail('Method should not be callable'); } return $result; } catch (AccessDeniedException $exception) { if ($not !== 'not') { throw $exception; } } } }
/** * A method which runs the task implemented by the plugin for the given command * * @param string $controllerCommandName Name of the command in question, for example "repair" * @param ConsoleOutput $output An instance of ConsoleOutput which can be used for output or dialogues * @param NodeType $nodeType Only handle this node type (if specified) * @param string $workspaceName Only handle this workspace (if specified) * @param boolean $dryRun If TRUE, don't do any changes, just simulate what you would do * @param boolean $cleanup If FALSE, cleanup tasks are skipped * @param string $skip Skip the given check or checks (comma separated) * @param string $only Only execute the given check or checks (comma separated) * @return void */ public function invokeSubCommand($controllerCommandName, ConsoleOutput $output, NodeType $nodeType = null, $workspaceName = 'live', $dryRun = false, $cleanup = true, $skip = null, $only = null) { $this->output = $output; $commandMethods = ['removeAbstractAndUndefinedNodes' => ['cleanup' => true], 'removeOrphanNodes' => ['cleanup' => true], 'removeDisallowedChildNodes' => ['cleanup' => true], 'removeUndefinedProperties' => ['cleanup' => true], 'removeBrokenEntityReferences' => ['cleanup' => true], 'removeNodesWithInvalidDimensions' => ['cleanup' => true], 'removeNodesWithInvalidWorkspace' => ['cleanup' => true], 'fixNodesWithInconsistentIdentifier' => ['cleanup' => false], 'createMissingChildNodes' => ['cleanup' => false], 'reorderChildNodes' => ['cleanup' => false], 'addMissingDefaultValues' => ['cleanup' => false], 'repairShadowNodes' => ['cleanup' => false]]; $skipCommandNames = Arrays::trimExplode(',', $skip === null ? '' : $skip); $onlyCommandNames = Arrays::trimExplode(',', $only === null ? '' : $only); switch ($controllerCommandName) { case 'repair': foreach ($commandMethods as $commandMethodName => $commandMethodConfiguration) { if (in_array($commandMethodName, $skipCommandNames)) { continue; } if ($onlyCommandNames !== [] && !in_array($commandMethodName, $onlyCommandNames)) { continue; } if (!$cleanup && $commandMethodConfiguration['cleanup']) { continue; } $this->{$commandMethodName}($workspaceName, $dryRun, $nodeType); } } }
/** * @Given /^the following users exist:$/ */ public function theFollowingUsersExist(TableNode $table) { $rows = $table->getHash(); /** @var UserService $userService */ $userService = $this->objectManager->get(UserService::class); /** @var PartyRepository $partyRepository */ $partyRepository = $this->objectManager->get(PartyRepository::class); /** @var AccountRepository $accountRepository */ $accountRepository = $this->objectManager->get(AccountRepository::class); foreach ($rows as $row) { $roleIdentifiers = array_map(function ($role) { return 'Neos.Neos:' . $role; }, Arrays::trimExplode(',', $row['roles'])); $userService->createUser($row['username'], $row['password'], $row['firstname'], $row['lastname'], $roleIdentifiers); } $this->getSubcontext('flow')->persistAll(); }
/** * Import redirects from CSV file * * This command is used to (re)import CSV files containing redirects. * The argument ``filename`` is the name of the file you uploaded to the root folder. * This operation requires the package ``league/csv``. Install it by running ``composer require league/csv``. * Structure per line is: * ``sourcePath``,``targetPath``,``statusCode``,``host`` (optional) * After a successful import a report will be shown. While `++` marks newly created redirects, `~~` marks already * existing redirect source paths along with the used status code and ``source``. * ``redirect:import`` will not delete pre-existing redirects. To do this run ``redirect:removeall`` before * the import. Be aware that this will also delete all automatically generated redirects. * * @param string $filename CSV file path * @return void */ public function importCommand($filename) { $hasErrors = false; $this->outputLine(); if (!class_exists(Reader::class)) { $this->outputWarningForLeagueCsvPackage(); } if (!is_readable($filename)) { $this->outputLine('<error>Sorry, but the file "%s" is not readable or does not exist...</error>', [$filename]); $this->outputLine(); $this->sendAndExit(1); } $this->outputLine('<b>Import redirects from "%s"</b>', [$filename]); $this->outputLine(); $reader = Reader::createFromPath($filename); $counter = 0; foreach ($reader as $index => $row) { $skipped = false; list($sourceUriPath, $targetUriPath, $statusCode, $hosts) = $row; $hosts = Arrays::trimExplode('|', $hosts); if ($hosts === []) { $hosts = [null]; } $forcePersist = false; foreach ($hosts as $key => $host) { $host = trim($host); $host = $host === '' ? null : $host; $redirect = $this->redirectStorage->getOneBySourceUriPathAndHost($sourceUriPath, $host); $isSame = $this->isSame($sourceUriPath, $targetUriPath, $host, $statusCode, $redirect); if ($redirect !== null && $isSame === false) { $this->outputRedirectLine('<info>--</info>', $redirect); $this->redirectStorage->removeOneBySourceUriPathAndHost($sourceUriPath, $host); $forcePersist = true; } elseif ($isSame === true) { $this->outputRedirectLine('<comment>~~</comment>', $redirect); unset($hosts[$key]); $skipped = true; } } if ($skipped === true && $hosts === []) { continue; } if ($forcePersist) { $this->persistenceManager->persistAll(); } try { $redirects = $this->redirectStorage->addRedirect($sourceUriPath, $targetUriPath, $statusCode, $hosts); /** @var Redirect $redirect */ foreach ($redirects as $redirect) { $this->outputRedirectLine('<info>++</info>', $redirect); $messageArguments = [$redirect->getSourceUriPath(), $redirect->getTargetUriPath(), $redirect->getStatusCode(), $redirect->getHost() ?: 'all host']; $this->logger->log(vsprintf('Redirect import success, sourceUriPath=%s, targetUriPath=%s, statusCode=%d, hosts=%s', $messageArguments), LOG_ERR); } $this->persistenceManager->persistAll(); } catch (Exception $exception) { $messageArguments = [$sourceUriPath, $targetUriPath, $statusCode, $hosts ? json_encode($hosts) : 'all host']; $this->outputLine(' <error>!!</error> %s => %s <comment>(%d)</comment> - %s', $messageArguments); $this->outputLine(' Message: %s', [$exception->getMessage()]); $this->logger->log(vsprintf('Redirect import error, sourceUriPath=%s, targetUriPath=%s, statusCode=%d, hosts=%s', $messageArguments), LOG_ERR); $this->logger->logException($exception); $hasErrors = true; } $counter++; if ($counter % 50 === 0) { $this->persistenceManager->persistAll(); $this->persistenceManager->clearState(); } } $this->outputLine(); if ($hasErrors === true) { $this->outputLine(' <error>!!</error> some errors appeared during import, please check the log or the CLI output.'); } $this->outputLegend(); }
/** * * * @param array $humanReadableContextProperties * @param boolean $addDimensionDefaults * @return \Neos\ContentRepository\Domain\Service\Context * @throws Exception */ protected function getContextForProperties(array $humanReadableContextProperties, $addDimensionDefaults = false) { if ($this->isolated === true) { $this->callStepInSubProcess(__METHOD__, sprintf(' %s %s %s %s', 'string', escapeshellarg($humanReadableContextProperties), 'integer', escapeshellarg($addDimensionDefaults))); } else { /** @var \Neos\ContentRepository\Domain\Service\ContextFactoryInterface $contextFactory */ $contextFactory = $this->getObjectManager()->get(\Neos\ContentRepository\Domain\Service\ContextFactoryInterface::class); $contextProperties = array(); if (isset($humanReadableContextProperties['Language'])) { $contextProperties['dimensions']['language'] = Arrays::trimExplode(',', $humanReadableContextProperties['Language']); } if (isset($humanReadableContextProperties['Workspace'])) { $contextProperties['workspaceName'] = $humanReadableContextProperties['Workspace']; $this->createWorkspaceIfNeeded($contextProperties['workspaceName']); } else { $this->createWorkspaceIfNeeded(); } if (isset($humanReadableContextProperties['Hidden'])) { $contextProperties['hidden'] = $humanReadableContextProperties['Hidden']; } foreach ($humanReadableContextProperties as $propertyName => $propertyValue) { // Set flexible dimensions from features if (strpos($propertyName, 'Dimension: ') === 0) { $contextProperties['dimensions'][substr($propertyName, strlen('Dimension: '))] = Arrays::trimExplode(',', $propertyValue); } // FIXME We lack a good API to manipulate dimension values explicitly or assign multiple values, so we are doing this via target dimension values if (strpos($propertyName, 'Target dimension: ') === 0) { if ($propertyValue === '') { $propertyValue = null; } $contextProperties['targetDimensions'][substr($propertyName, strlen('Target dimension: '))] = $propertyValue; } } if ($addDimensionDefaults) { $contentDimensionRepository = $this->getObjectManager()->get(\Neos\ContentRepository\Domain\Repository\ContentDimensionRepository::class); $availableDimensions = $contentDimensionRepository->findAll(); foreach ($availableDimensions as $dimension) { if (isset($contextProperties['dimensions'][$dimension->getIdentifier()]) && !in_array($dimension->getDefault(), $contextProperties['dimensions'][$dimension->getIdentifier()])) { $contextProperties['dimensions'][$dimension->getIdentifier()][] = $dimension->getDefault(); } } } $contextProperties['invisibleContentShown'] = true; return $contextFactory->create($contextProperties); } }
/** * @param QueryInterface $query * @param $nodeTypeFilter * @return array */ protected function getNodeTypeFilterConstraints(QueryInterface $query, $nodeTypeFilter) { $includeNodeTypeConstraints = []; $excludeNodeTypeConstraints = []; $nodeTypeFilterParts = Arrays::trimExplode(',', $nodeTypeFilter); foreach ($nodeTypeFilterParts as $nodeTypeFilterPart) { $nodeTypeFilterPart = trim($nodeTypeFilterPart); if (strpos($nodeTypeFilterPart, '!') === 0) { $negate = true; $nodeTypeFilterPart = substr($nodeTypeFilterPart, 1); } else { $negate = false; } $nodeTypeFilterPartSubTypes = array_merge([$nodeTypeFilterPart], $this->nodeTypeManager->getSubNodeTypes($nodeTypeFilterPart, false)); foreach ($nodeTypeFilterPartSubTypes as $nodeTypeFilterPartSubType) { if ($negate === true) { $excludeNodeTypeConstraints[] = $query->logicalNot($query->equals('nodeType', $nodeTypeFilterPartSubType)); } else { $includeNodeTypeConstraints[] = $query->equals('nodeType', $nodeTypeFilterPartSubType); } } } $constraints = $excludeNodeTypeConstraints; if (count($includeNodeTypeConstraints) > 0) { $constraints[] = $query->logicalOr($includeNodeTypeConstraints); } return $constraints; }
/** * @When /^I create the following accounts:$/ */ public function iCreateTheFollowingAccounts(TableNode $table) { foreach ($table->getHash() as $row) { $user = $this->getObjectManager()->get(UserService::class)->createUser($row['User'], $row['Password'], $row['First Name'], $row['Last Name'], Arrays::trimExplode(',', $row['Roles'])); } $this->getSubcontext('flow')->persistAll(); }
/** * Shows a list of all defined privilege targets and the effective permissions * * @param string $privilegeType The privilege type ("entity", "method" or the FQN of a class implementing PrivilegeInterface) * @param string $roles A comma separated list of role identifiers. Shows policy for an unauthenticated user when left empty. */ public function showEffectivePolicyCommand($privilegeType, $roles = '') { $systemRoleIdentifiers = ['Neos.Flow:Everybody', 'Neos.Flow:Anonymous', 'Neos.Flow:AuthenticatedUser']; if (strpos($privilegeType, '\\') === false) { $privilegeType = sprintf('\\Neos\\Flow\\Security\\Authorization\\Privilege\\%s\\%sPrivilegeInterface', ucfirst($privilegeType), ucfirst($privilegeType)); } if (!class_exists($privilegeType) && !interface_exists($privilegeType)) { $this->outputLine('The privilege type "%s" was not defined.', [$privilegeType]); $this->quit(1); } if (!is_subclass_of($privilegeType, PrivilegeInterface::class)) { $this->outputLine('"%s" does not refer to a valid Privilege', [$privilegeType]); $this->quit(1); } $requestedRoles = []; foreach (Arrays::trimExplode(',', $roles) as $roleIdentifier) { try { if (in_array($roleIdentifier, $systemRoleIdentifiers)) { continue; } $currentRole = $this->policyService->getRole($roleIdentifier); $requestedRoles[$roleIdentifier] = $currentRole; foreach ($currentRole->getAllParentRoles() as $currentParentRole) { if (!in_array($currentParentRole, $requestedRoles)) { $requestedRoles[$currentParentRole->getIdentifier()] = $currentParentRole; } } } catch (NoSuchRoleException $exception) { $this->outputLine('The role %s was not defined.', [$roleIdentifier]); $this->quit(1); } } if (count($requestedRoles) > 0) { $requestedRoles['Neos.Flow:AuthenticatedUser'] = $this->policyService->getRole('Neos.Flow:AuthenticatedUser'); } else { $requestedRoles['Neos.Flow:Anonymous'] = $this->policyService->getRole('Neos.Flow:Anonymous'); } $requestedRoles['Neos.Flow:Everybody'] = $this->policyService->getRole('Neos.Flow:Everybody'); $this->outputLine('Effective Permissions for the roles <b>%s</b> ', [implode(', ', $requestedRoles)]); $this->outputLine(str_repeat('-', $this->output->getMaximumLineLength())); $definedPrivileges = $this->policyService->getAllPrivilegesByType($privilegeType); $permissions = []; /** @var PrivilegeInterface $definedPrivilege */ foreach ($definedPrivileges as $definedPrivilege) { $accessGrants = 0; $accessDenies = 0; $permission = 'ABSTAIN'; /** @var Role $requestedRole */ foreach ($requestedRoles as $requestedRole) { $privilegeType = $requestedRole->getPrivilegeForTarget($definedPrivilege->getPrivilegeTarget()->getIdentifier()); if ($privilegeType === null) { continue; } if ($privilegeType->isGranted()) { $accessGrants++; } elseif ($privilegeType->isDenied()) { $accessDenies++; } } if ($accessDenies > 0) { $permission = '<error>DENY</error>'; } if ($accessGrants > 0 && $accessDenies === 0) { $permission = '<success>GRANT</success>'; } $permissions[$definedPrivilege->getPrivilegeTarget()->getIdentifier()] = $permission; } ksort($permissions); foreach ($permissions as $privilegeTargetIdentifier => $permission) { $formattedPrivilegeTargetIdentifier = wordwrap($privilegeTargetIdentifier, $this->output->getMaximumLineLength() - 10, PHP_EOL . str_repeat(' ', 10), true); $this->outputLine('%-70s %s', [$formattedPrivilegeTargetIdentifier, $permission]); } }