/** * Checks the cache for the route path given in the Request and returns the result * * @param Request $httpRequest * @return array|boolean the cached route values or FALSE if no cache entry was found */ public function getCachedMatchResults(Request $httpRequest) { $cachedResult = $this->routeCache->get($this->buildRouteCacheIdentifier($httpRequest)); if ($cachedResult !== false) { $this->systemLogger->log(sprintf('Router route(): A cached Route with the cache identifier "%s" matched the path "%s".', $this->buildRouteCacheIdentifier($httpRequest), $httpRequest->getRelativePath()), LOG_DEBUG); } return $cachedResult; }
/** * Provides an XML comment containing the exception * * @param string $typoScriptPath path causing the exception * @param \Exception $exception exception to handle * @param integer $referenceCode * @return string */ protected function handle($typoScriptPath, \Exception $exception, $referenceCode) { $this->systemLogger->logException($exception); if (isset($referenceCode)) { return sprintf('<!-- Exception while rendering %s: %s (%s) -->', $this->formatScriptPath($typoScriptPath, ''), htmlspecialchars($exception->getMessage()), $referenceCode); } else { return sprintf('<!-- Exception while rendering %s: %s -->', $this->formatScriptPath($typoScriptPath, ''), htmlspecialchars($exception->getMessage())); } }
/** * @param array $redirects * @return void * @throws Exception */ public function emitRedirectCreated(array $redirects) { foreach ($redirects as $redirect) { if (!$redirect instanceof RedirectInterface) { throw new Exception('Redirect should implement RedirectInterface', 1460139669); } $this->_redirectService->emitRedirectCreated($redirect); $this->_logger->log(sprintf('Redirect from %s %s -> %s (%d) added', $redirect->getHost(), $redirect->getSourceUriPath(), $redirect->getTargetUriPath(), $redirect->getStatusCode()), LOG_DEBUG); } }
/** * Before advice for all methods annotated with "@Flow\Session(autoStart=true)". * Those methods will trigger a session initialization if a session does not exist * yet. * * @param JoinPointInterface $joinPoint The current join point * @return void * @fixme The pointcut expression below does not consider the options of the session annotation – needs adjustments in the AOP framework * @Flow\Before("methodAnnotatedWith(Neos\Flow\Annotations\Session)") */ public function initializeSession(JoinPointInterface $joinPoint) { if ($this->session->isStarted() === true) { return; } $objectName = $this->objectManager->getObjectNameByClassName(get_class($joinPoint->getProxy())); $methodName = $joinPoint->getMethodName(); $this->systemLogger->log(sprintf('Session initialization triggered by %s->%s.', $objectName, $methodName), LOG_DEBUG); $this->session->start(); }
/** * Renders the exception in HTML for display * * @param string $typoScriptPath path causing the exception * @param \Exception $exception exception to handle * @param integer $referenceCode * @return string */ protected function handle($typoScriptPath, \Exception $exception, $referenceCode) { $messageArray = array('header' => 'An exception was thrown while Neos tried to render your page', 'content' => htmlspecialchars($exception->getMessage()), 'stacktrace' => $this->formatTypoScriptPath($typoScriptPath), 'referenceCode' => $this->formatErrorCodeMessage($referenceCode)); $messageBody = sprintf('<p class="neos-message-content">%s</p>' . '<p class="neos-message-stacktrace"><code>%s</code></p>', $messageArray['content'], $messageArray['stacktrace']); if ($referenceCode) { $messageBody = sprintf('%s<p class="neos-reference-code">%s</p>', $messageBody, $messageArray['referenceCode']); } $message = sprintf('<div class="neos-message-header"><div class="neos-message-icon"><i class="icon-warning-sign"></i></div><h1>%s</h1></div>' . '<div class="neos-message-wrapper">%s</div>', $messageArray['header'], $messageBody); $this->systemLogger->logException($exception); return $message; }
/** * Filters the classnames available for object management by filter expressions that either include or exclude classes. * * @param array $classNames All classnames per package * @param array $filterConfiguration The filter configuration to apply * @param string $includeOrExclude if this is an "include" or "exclude" filter * @return array the remaining class * @throws InvalidConfigurationTypeException */ protected function applyClassFilterConfiguration($classNames, $filterConfiguration, $includeOrExclude = 'include') { if (!in_array($includeOrExclude, ['include', 'exclude'])) { throw new \InvalidArgumentException('The argument $includeOrExclude must be one of "include" or "exclude", the given value was not allowed.', 1423726253); } foreach ($filterConfiguration as $packageKey => $filterExpressions) { if (!array_key_exists($packageKey, $classNames)) { $this->systemLogger->log('The package "' . $packageKey . '" specified in the setting "Neos.Flow.object.' . $includeOrExclude . 'Classes" was either excluded or is not loaded.', LOG_DEBUG); continue; } if (!is_array($filterExpressions)) { throw new InvalidConfigurationTypeException('The value given for setting "Neos.Flow.object.' . $includeOrExclude . 'Classes.\'' . $packageKey . '\'" is invalid. It should be an array of expressions. Check the syntax in the YAML file.', 1422357272); } $classesForPackageUnderInspection = $classNames[$packageKey]; $classNames[$packageKey] = []; foreach ($filterExpressions as $filterExpression) { $classesForPackageUnderInspection = array_filter($classesForPackageUnderInspection, function ($className) use($filterExpression, $includeOrExclude) { $match = preg_match('/' . $filterExpression . '/', $className); return $includeOrExclude === 'include' ? $match === 1 : $match !== 1; }); if ($includeOrExclude === 'include') { $classNames[$packageKey] = array_merge($classNames[$packageKey], $classesForPackageUnderInspection); $classesForPackageUnderInspection = $classNames[$packageKey]; } else { $classNames[$packageKey] = $classesForPackageUnderInspection; } } if ($classNames[$packageKey] === []) { unset($classNames[$packageKey]); } } return $classNames; }
/** * Checks if the specified method matches with the method annotation filter pattern * * @param string $className Name of the class to check against - not used here * @param string $methodName Name of the method * @param string $methodDeclaringClassName Name of the class the method was originally declared in * @param mixed $pointcutQueryIdentifier Some identifier for this query - must at least differ from a previous identifier. Used for circular reference detection - not used here * @return boolean TRUE if the class matches, otherwise FALSE */ public function matches($className, $methodName, $methodDeclaringClassName, $pointcutQueryIdentifier) { if ($methodDeclaringClassName === null || !method_exists($methodDeclaringClassName, $methodName)) { return false; } $designatedAnnotations = $this->reflectionService->getMethodAnnotations($methodDeclaringClassName, $methodName, $this->annotation); if ($designatedAnnotations !== [] || $this->annotationValueConstraints === []) { $matches = $designatedAnnotations !== []; } else { // It makes no sense to check property values for an annotation that is used multiple times, we shortcut and check the value against the first annotation found. $firstFoundAnnotation = $designatedAnnotations; $annotationProperties = $this->reflectionService->getClassPropertyNames($this->annotation); foreach ($this->annotationValueConstraints as $propertyName => $expectedValue) { if (!array_key_exists($propertyName, $annotationProperties)) { $this->systemLogger->log('The property "' . $propertyName . '" declared in pointcut does not exist in annotation ' . $this->annotation, LOG_NOTICE); return false; } if ($firstFoundAnnotation->{$propertyName} === $expectedValue) { $matches = true; } else { return false; } } } return $matches; }
/** * Log a deprecation message once * * @return void */ protected function logDeprecation() { if (!static::$loggedDeprecation) { static::$loggedDeprecation = true; $this->logger->log('Neos.Media is configured to simulate the deprecated Neos 1.2 behaviour. Please check the setting "Neos.Media.behaviourFlag".', LOG_DEBUG); } }
/** * Checks if the specified method matches against the method name * expression. * * Returns TRUE if method name, visibility and arguments constraints match and the target * method is not final. * * @param string $className Ignored in this pointcut filter * @param string $methodName Name of the method to match against * @param string $methodDeclaringClassName Name of the class the method was originally declared in * @param mixed $pointcutQueryIdentifier Some identifier for this query - must at least differ from a previous identifier. Used for circular reference detection. * @return boolean TRUE if the class matches, otherwise FALSE * @throws Exception */ public function matches($className, $methodName, $methodDeclaringClassName, $pointcutQueryIdentifier) { $matchResult = preg_match('/^' . $this->methodNameFilterExpression . '$/', $methodName); if ($matchResult === false) { throw new Exception('Error in regular expression', 1168876915); } elseif ($matchResult !== 1) { return false; } switch ($this->methodVisibility) { case 'public': if (!($methodDeclaringClassName !== null && $this->reflectionService->isMethodPublic($methodDeclaringClassName, $methodName))) { return false; } break; case 'protected': if (!($methodDeclaringClassName !== null && $this->reflectionService->isMethodProtected($methodDeclaringClassName, $methodName))) { return false; } break; } if ($methodDeclaringClassName !== null && $this->reflectionService->isMethodFinal($methodDeclaringClassName, $methodName)) { return false; } $methodArguments = $methodDeclaringClassName === null ? [] : $this->reflectionService->getMethodParameters($methodDeclaringClassName, $methodName); foreach (array_keys($this->methodArgumentConstraints) as $argumentName) { $objectAccess = explode('.', $argumentName, 2); $argumentName = $objectAccess[0]; if (!array_key_exists($argumentName, $methodArguments)) { $this->systemLogger->log('The argument "' . $argumentName . '" declared in pointcut does not exist in method ' . $methodDeclaringClassName . '->' . $methodName, LOG_NOTICE); return false; } } return true; }
/** * @param array $nodes */ public function assignNodes(array $nodes) { $data = array(); foreach ($nodes as $node) { if ($node->getPath() !== '/') { $q = new FlowQuery(array($node)); $closestDocumentNode = $q->closest('[instanceof Neos.Neos:Document]')->get(0); if ($closestDocumentNode !== null) { $data[] = array('nodeContextPath' => $node->getContextPath(), 'documentNodeContextPath' => $closestDocumentNode->getContextPath()); } else { $this->systemLogger->log('You have a node that is no longer connected to a parent. Path: ' . $node->getPath() . ' (Identifier: ' . $node->getIdentifier() . ')'); } } } $this->assign('value', array('data' => $data, 'success' => true)); }
/** * Handles the given exception * * @param object $exception The exception object - can be \Exception, or some type of \Throwable in PHP 7 * @return void */ public function handleException($exception) { // Ignore if the error is suppressed by using the shut-up operator @ if (error_reporting() === 0) { return; } $this->renderingOptions = $this->resolveCustomRenderingOptions($exception); if (is_object($this->systemLogger) && isset($this->renderingOptions['logException']) && $this->renderingOptions['logException']) { if ($exception instanceof \Throwable) { if ($this->systemLogger instanceof ThrowableLoggerInterface) { $this->systemLogger->logThrowable($exception); } else { // Convert \Throwable to \Exception for non-supporting logger implementations $this->systemLogger->logException(new \Exception($exception->getMessage(), $exception->getCode())); } } elseif ($exception instanceof \Exception) { $this->systemLogger->logException($exception); } } switch (PHP_SAPI) { case 'cli': $this->echoExceptionCli($exception); break; default: $this->echoExceptionWeb($exception); } }
/** * Iterates over all existing sessions and removes their data if the inactivity * timeout was reached. * * @return integer The number of outdated entries removed * @api */ public function collectGarbage() { if ($this->inactivityTimeout === 0) { return 0; } if ($this->metaDataCache->has('_garbage-collection-running')) { return false; } $sessionRemovalCount = 0; $this->metaDataCache->set('_garbage-collection-running', true, [], 120); foreach ($this->metaDataCache->getIterator() as $sessionIdentifier => $sessionInfo) { if ($sessionIdentifier === '_garbage-collection-running') { continue; } $lastActivitySecondsAgo = $this->now - $sessionInfo['lastActivityTimestamp']; if ($lastActivitySecondsAgo > $this->inactivityTimeout) { if ($sessionInfo['storageIdentifier'] === null) { $this->systemLogger->log('SESSION INFO INVALID: ' . $sessionIdentifier, LOG_WARNING, $sessionInfo); } else { $this->storageCache->flushByTag($sessionInfo['storageIdentifier']); $sessionRemovalCount++; } $this->metaDataCache->remove($sessionIdentifier); } if ($sessionRemovalCount >= $this->garbageCollectionMaximumPerRun) { break; } } $this->metaDataCache->remove('_garbage-collection-running'); return $sessionRemovalCount; }
/** * Detects changes of the files and directories to be monitored and emits signals * accordingly. * * @return void * @api */ public function detectChanges() { if ($this->changedFiles === null || $this->changedPaths === null) { $this->loadDetectedDirectoriesAndFiles(); $changesDetected = false; $this->changedPaths = $this->changedFiles = []; $this->changedFiles = $this->detectChangedFiles($this->monitoredFiles); foreach ($this->monitoredDirectories as $path => $filenamePattern) { $changesDetected = $this->detectChangesOnPath($path, $filenamePattern) ? true : $changesDetected; } if ($changesDetected) { $this->saveDetectedDirectoriesAndFiles(); } $this->directoriesAndFiles = null; } $changedFileCount = count($this->changedFiles); $changedPathCount = count($this->changedPaths); if ($changedFileCount > 0) { $this->emitFilesHaveChanged($this->identifier, $this->changedFiles); } if ($changedPathCount > 0) { $this->emitDirectoriesHaveChanged($this->identifier, $this->changedPaths); } if ($changedFileCount > 0 || $changedPathCount) { $this->systemLogger->log(sprintf('File Monitor "%s" detected %s changed files and %s changed directories.', $this->identifier, $changedFileCount, $changedPathCount), LOG_INFO); } }
/** * Returns the query result count * * @return integer The query result count * @throws Exception\DatabaseConnectionException * @api */ public function count() { try { $originalQuery = $this->queryBuilder->getQuery(); $dqlQuery = clone $originalQuery; $dqlQuery->setParameters($originalQuery->getParameters()); $dqlQuery->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_TREE_WALKERS, [CountWalker::class]); $offset = $dqlQuery->getFirstResult(); $limit = $dqlQuery->getMaxResults(); if ($offset !== null) { $dqlQuery->setFirstResult(null); } $numberOfResults = (int) $dqlQuery->getSingleScalarResult(); if ($offset !== null) { $numberOfResults = max(0, $numberOfResults - $offset); } if ($limit !== null) { $numberOfResults = min($numberOfResults, $limit); } return $numberOfResults; } catch (\Doctrine\ORM\ORMException $ormException) { $this->systemLogger->logException($ormException); return 0; } catch (\PDOException $pdoException) { throw new Exception\DatabaseConnectionException($pdoException->getMessage(), $pdoException->getCode()); } }
/** * Import sites content * * This command allows for importing one or more sites or partial content from an XML source. The format must * be identical to that produced by the export command. * * If a filename is specified, this command expects the corresponding file to contain the XML structure. The * filename php://stdin can be used to read from standard input. * * If a package key is specified, this command expects a Sites.xml file to be located in the private resources * directory of the given package (Resources/Private/Content/Sites.xml). * * @param string $packageKey Package key specifying the package containing the sites content * @param string $filename relative path and filename to the XML file containing the sites content * @return void */ public function importCommand($packageKey = null, $filename = null) { $exceedingArguments = $this->request->getExceedingArguments(); if (isset($exceedingArguments[0]) && $packageKey === null && $filename === null) { if (file_exists($exceedingArguments[0])) { $filename = $exceedingArguments[0]; } elseif ($this->packageManager->isPackageAvailable($exceedingArguments[0])) { $packageKey = $exceedingArguments[0]; } } if ($packageKey === null && $filename === null) { $this->outputLine('You have to specify either "--package-key" or "--filename"'); $this->quit(1); } $site = null; if ($filename !== null) { try { $site = $this->siteImportService->importFromFile($filename); } catch (\Exception $exception) { $this->systemLogger->logException($exception); $this->outputLine('<error>During the import of the file "%s" an exception occurred: %s, see log for further information.</error>', array($filename, $exception->getMessage())); $this->quit(1); } } else { try { $site = $this->siteImportService->importFromPackage($packageKey); } catch (\Exception $exception) { $this->systemLogger->logException($exception); $this->outputLine('<error>During the import of the "Sites.xml" from the package "%s" an exception occurred: %s, see log for further information.</error>', array($packageKey, $exception->getMessage())); $this->quit(1); } } $this->outputLine('Import of site "%s" finished.', array($site->getName())); }
/** * Output an error message and log the exception. * * @param \Exception $exception * @return void */ protected function handleException(\Exception $exception) { $this->outputLine('<error>%s</error>', [$exception->getMessage()]); $this->outputLine(); $this->outputLine('The exception details have been logged to the Flow system log.'); $this->systemLogger->logException($exception); $this->quit(1); }
/** * Matches a \Neos\Flow\Mvc\RequestInterface against the configured CSRF pattern rules and * searches for invalid csrf tokens. If this returns TRUE, the request is invalid! * * @param RequestInterface $request The request that should be matched * @return boolean TRUE if the pattern matched, FALSE otherwise * @throws AuthenticationRequiredException */ public function matchRequest(RequestInterface $request) { if (!$request instanceof ActionRequest || $request->getHttpRequest()->isMethodSafe()) { $this->systemLogger->log('CSRF: No token required, safe request', LOG_DEBUG); return false; } if ($this->authenticationManager->isAuthenticated() === false) { $this->systemLogger->log('CSRF: No token required, not authenticated', LOG_DEBUG); return false; } if ($this->securityContext->areAuthorizationChecksDisabled() === true) { $this->systemLogger->log('CSRF: No token required, authorization checks are disabled', LOG_DEBUG); return false; } $controllerClassName = $this->objectManager->getClassNameByObjectName($request->getControllerObjectName()); $actionMethodName = $request->getControllerActionName() . 'Action'; if (!$this->hasPolicyEntryForMethod($controllerClassName, $actionMethodName)) { $this->systemLogger->log(sprintf('CSRF: No token required, method %s::%s() is not restricted by a policy.', $controllerClassName, $actionMethodName), LOG_DEBUG); return false; } if ($this->reflectionService->isMethodTaggedWith($controllerClassName, $actionMethodName, 'skipcsrfprotection')) { $this->systemLogger->log(sprintf('CSRF: No token required, method %s::%s() is tagged with a "skipcsrfprotection" annotation', $controllerClassName, $actionMethodName), LOG_DEBUG); return false; } $httpRequest = $request->getHttpRequest(); if ($httpRequest->hasHeader('X-Flow-Csrftoken')) { $csrfToken = $httpRequest->getHeader('X-Flow-Csrftoken'); } else { $internalArguments = $request->getMainRequest()->getInternalArguments(); $csrfToken = isset($internalArguments['__csrfToken']) ? $internalArguments['__csrfToken'] : null; } if (empty($csrfToken)) { $this->systemLogger->log(sprintf('CSRF: token was empty but a valid token is required for %s::%s()', $controllerClassName, $actionMethodName), LOG_DEBUG); return true; } if (!$this->securityContext->hasCsrfProtectionTokens()) { throw new AuthenticationRequiredException(sprintf('CSRF: No CSRF tokens in security context, possible session timeout. A valid token is required for %s::%s()', $controllerClassName, $actionMethodName), 1317309673); } if ($this->securityContext->isCsrfProtectionTokenValid($csrfToken) === false) { $this->systemLogger->log(sprintf('CSRF: token was invalid but a valid token is required for %s::%s()', $controllerClassName, $actionMethodName), LOG_DEBUG); return true; } $this->systemLogger->log(sprintf('CSRF: Successfully verified token for %s::%s()', $controllerClassName, $actionMethodName), LOG_DEBUG); return false; }
/** * Flushes I18n caches if translation files have changed * * @param array $changedFiles A list of full paths to changed files * @return void * @see flushSystemCachesByChangedFiles() */ protected function flushTranslationCachesByChangedFiles(array $changedFiles) { foreach ($changedFiles as $pathAndFilename => $status) { if (preg_match('/\\/Translations\\/.+\\.xlf/', $pathAndFilename) === 1) { $this->systemLogger->log('The localization files have changed, thus flushing the I18n XML model cache.', LOG_INFO); $this->getCache('Flow_I18n_XmlModelCache')->flush(); break; } } }
/** * Get a single property reduced to a simple type (no objects) representation * * @param NodeInterface $node * @param string $propertyName * @return mixed */ public function getProperty(NodeInterface $node, $propertyName) { if ($propertyName[0] === '_') { $propertyValue = ObjectAccess::getProperty($node, ltrim($propertyName, '_')); } else { $propertyValue = $node->getProperty($propertyName); } $dataType = $node->getNodeType()->getPropertyType($propertyName); try { $convertedValue = $this->convertValue($propertyValue, $dataType); } catch (PropertyException $exception) { $this->systemLogger->logException($exception); $convertedValue = null; } if ($convertedValue === null) { $convertedValue = $this->getDefaultValueForProperty($node->getNodeType(), $propertyName); } return $convertedValue; }
/** * Logs calls of collectGarbage() * * @Flow\AfterReturning("within(Neos\Flow\Session\SessionInterface) && method(.*->collectGarbage())") * @param JoinPointInterface $joinPoint The current joinpoint * @return void */ public function logCollectGarbage(JoinPointInterface $joinPoint) { $sessionRemovalCount = $joinPoint->getResult(); if ($sessionRemovalCount > 0) { $this->systemLogger->log(sprintf('%s: Triggered garbage collection and removed %s expired sessions.', $this->getClassName($joinPoint), $sessionRemovalCount), LOG_INFO); } elseif ($sessionRemovalCount === 0) { $this->systemLogger->log(sprintf('%s: Triggered garbage collection but no sessions needed to be removed.', $this->getClassName($joinPoint)), LOG_INFO); } elseif ($sessionRemovalCount === false) { $this->systemLogger->log(sprintf('%s: Ommitting garbage collection because another process is already running. Consider lowering the GC propability if these messages appear a lot.', $this->getClassName($joinPoint)), LOG_WARNING); } }
/** * Flush caches according to the previously registered node changes. * * @return void */ public function shutdownObject() { if ($this->tagsToFlush !== array()) { foreach ($this->tagsToFlush as $tag => $logMessage) { $affectedEntries = $this->contentCache->flushByTag($tag); if ($affectedEntries > 0) { $this->systemLogger->log(sprintf('Content cache: Removed %s entries %s', $affectedEntries, $logMessage), LOG_DEBUG); } } } }
/** * Refreshes this asset after the Resource or any other parameters affecting thumbnails have been modified * * @return void */ public function refresh() { $assetClassType = str_replace('Neos\\Media\\Domain\\Model\\', '', get_class($this)); $this->systemLogger->log(sprintf('%s: refresh() called, clearing all thumbnails. Filename: %s. PersistentResource SHA1: %s', $assetClassType, $this->getResource()->getFilename(), $this->getResource()->getSha1()), LOG_DEBUG); // whitelist objects so they can be deleted (even during safe requests) $this->persistenceManager->whitelistObject($this); foreach ($this->thumbnails as $thumbnail) { $this->persistenceManager->whitelistObject($thumbnail); } $this->thumbnails->clear(); }
/** * @param callable $callback a callback function to process every notification * @return void * @api */ public function flush(callable $callback = null) { foreach ($this->messages as $message) { /** @var Message $message */ $this->messages->detach($message); $this->systemLogger->log('ResourcePublishingMessage: ' . $message->getMessage(), $message->getSeverity()); if ($callback !== null) { $callback($message); } } }
/** * Returns a thumbnail of the given asset * * If the maximum width / height is not specified or exceeds the original asset's dimensions, the width / height of * the original asset is used. * * @param AssetInterface $asset The asset to render a thumbnail for * @param ThumbnailConfiguration $configuration * @return ImageInterface * @throws \Exception */ public function getThumbnail(AssetInterface $asset, ThumbnailConfiguration $configuration) { // Calculates the dimensions of the thumbnail to be generated and returns the thumbnail image if the new // dimensions differ from the specified image dimensions, otherwise the original image is returned. if ($asset instanceof ImageInterface) { if ($asset->getWidth() === null && $asset->getHeight() === null) { return $asset; } $maximumWidth = $configuration->getMaximumWidth() > $asset->getWidth() ? $asset->getWidth() : $configuration->getMaximumWidth(); $maximumHeight = $configuration->getMaximumHeight() > $asset->getHeight() ? $asset->getHeight() : $configuration->getMaximumHeight(); if ($configuration->isUpScalingAllowed() === false && $maximumWidth === $asset->getWidth() && $maximumHeight === $asset->getHeight()) { return $asset; } } $assetIdentifier = $this->persistenceManager->getIdentifierByObject($asset); $configurationHash = $configuration->getHash(); if (!isset($this->thumbnailCache[$assetIdentifier])) { $this->thumbnailCache[$assetIdentifier] = []; } if (isset($this->thumbnailCache[$assetIdentifier][$configurationHash])) { $thumbnail = $this->thumbnailCache[$assetIdentifier][$configurationHash]; } else { $thumbnail = $this->thumbnailRepository->findOneByAssetAndThumbnailConfiguration($asset, $configuration); $this->thumbnailCache[$assetIdentifier][$configurationHash] = $thumbnail; } $async = $configuration->isAsync(); if ($thumbnail === null) { try { $thumbnail = new Thumbnail($asset, $configuration, $async); $this->emitThumbnailCreated($thumbnail); // If the thumbnail strategy failed to generate a valid thumbnail if ($async === false && $thumbnail->getResource() === null && $thumbnail->getStaticResource() === null) { $this->thumbnailRepository->remove($thumbnail); return null; } if (!$this->persistenceManager->isNewObject($asset)) { $this->thumbnailRepository->add($thumbnail); } $asset->addThumbnail($thumbnail); // Allow thumbnails to be persisted even if this is a "safe" HTTP request: $this->persistenceManager->whiteListObject($thumbnail); $this->thumbnailCache[$assetIdentifier][$configurationHash] = $thumbnail; } catch (NoThumbnailAvailableException $exception) { $this->systemLogger->logException($exception); return null; } $this->persistenceManager->whiteListObject($thumbnail); $this->thumbnailCache[$assetIdentifier][$configurationHash] = $thumbnail; } elseif ($thumbnail->getResource() === null && $async === false) { $this->refreshThumbnail($thumbnail); } return $thumbnail; }
/** * Analyzes the Object Configuration provided by the compiler and builds the necessary PHP code for the proxy classes * to realize dependency injection. * * @return void */ public function build() { $this->objectConfigurations = $this->objectManager->getObjectConfigurations(); foreach ($this->objectConfigurations as $objectName => $objectConfiguration) { $className = $objectConfiguration->getClassName(); if ($className === '' || $this->compiler->hasCacheEntryForClass($className) === true) { continue; } if ($objectName !== $className || $this->reflectionService->isClassAbstract($className)) { continue; } $proxyClass = $this->compiler->getProxyClass($className); if ($proxyClass === false) { continue; } $this->systemLogger->log('Building DI proxy for "' . $className . '".', LOG_DEBUG); $constructorPreCode = ''; $constructorPostCode = ''; $constructorPreCode .= $this->buildSetInstanceCode($objectConfiguration); $constructorPreCode .= $this->buildConstructorInjectionCode($objectConfiguration); $setRelatedEntitiesCode = ''; if (!$this->reflectionService->hasMethod($className, '__sleep')) { $proxyClass->addTraits(['\\' . ObjectSerializationTrait::class]); $sleepMethod = $proxyClass->getMethod('__sleep'); $sleepMethod->addPostParentCallCode($this->buildSerializeRelatedEntitiesCode($objectConfiguration)); $setRelatedEntitiesCode = "\n " . '$this->Flow_setRelatedEntities();' . "\n"; } $wakeupMethod = $proxyClass->getMethod('__wakeup'); $wakeupMethod->addPreParentCallCode($this->buildSetInstanceCode($objectConfiguration)); $wakeupMethod->addPreParentCallCode($setRelatedEntitiesCode); $wakeupMethod->addPostParentCallCode($this->buildLifecycleInitializationCode($objectConfiguration, ObjectManagerInterface::INITIALIZATIONCAUSE_RECREATED)); $wakeupMethod->addPostParentCallCode($this->buildLifecycleShutdownCode($objectConfiguration)); $injectPropertiesCode = $this->buildPropertyInjectionCode($objectConfiguration); if ($injectPropertiesCode !== '') { $proxyClass->addTraits(['\\' . PropertyInjectionTrait::class]); $proxyClass->getMethod('Flow_Proxy_injectProperties')->addPreParentCallCode($injectPropertiesCode); $proxyClass->getMethod('Flow_Proxy_injectProperties')->overrideMethodVisibility('private'); $wakeupMethod->addPreParentCallCode(" \$this->Flow_Proxy_injectProperties();\n"); $constructorPostCode .= ' if (\'' . $className . '\' === get_class($this)) {' . "\n"; $constructorPostCode .= ' $this->Flow_Proxy_injectProperties();' . "\n"; $constructorPostCode .= ' }' . "\n"; } $constructorPostCode .= $this->buildLifecycleInitializationCode($objectConfiguration, ObjectManagerInterface::INITIALIZATIONCAUSE_CREATED); $constructorPostCode .= $this->buildLifecycleShutdownCode($objectConfiguration); $constructor = $proxyClass->getConstructor(); $constructor->addPreParentCallCode($constructorPreCode); $constructor->addPostParentCallCode($constructorPostCode); if ($this->objectManager->getContext()->isProduction()) { $this->compileStaticMethods($className, $proxyClass); } } }
/** * Called after a functional test in Flow, dumps everything in the database. * * @return void */ public function tearDown() { // "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']['path'] !== null) { $this->entityManager->clear(); $schemaTool = new SchemaTool($this->entityManager); $schemaTool->dropDatabase(); $this->systemLogger->log('Doctrine 2 schema destroyed.', LOG_NOTICE); } else { $this->systemLogger->log('Doctrine 2 destroy skipped, driver and path backend options not set!', LOG_NOTICE); } }
/** * @param string $resourcePath * @return string */ protected function getStaticResourceWebBaseUri($resourcePath) { $localizedResourcePathData = $this->i18nService->getLocalizedFilename($resourcePath); $matches = array(); try { if (preg_match('#resource://([^/]+)/Public/(.*)#', current($localizedResourcePathData), $matches) === 1) { $packageKey = $matches[1]; $path = $matches[2]; return $this->resourceManager->getPublicPackageResourceUri($packageKey, $path); } } catch (\Exception $exception) { $this->systemLogger->logException($exception); } return ''; }
/** * Finally evaluate the TypoScript path * * As PHP does not like throwing an exception here, we render any exception using the configured TypoScript exception * handler and will also catch and log any exceptions resulting from that as a last resort. * * @return string */ public function __toString() { try { return (string) $this->objectAccess(); } catch (\Exception $exceptionHandlerException) { try { // Throwing an exception in __toString causes a fatal error, so if that happens we catch them and use the context dependent exception handler instead. $contextDependentExceptionHandler = new ContextDependentHandler(); $contextDependentExceptionHandler->setRuntime($this->fusionRuntime); return $contextDependentExceptionHandler->handleRenderingException($this->path, $exception); } catch (\Exception $contextDepndentExceptionHandlerException) { $this->systemLogger->logException($contextDepndentExceptionHandlerException, array('path' => $this->path)); return sprintf('<!-- Exception while rendering exception in %s: %s (%s) -->', $this->path, $contextDepndentExceptionHandlerException->getMessage(), $contextDepndentExceptionHandlerException instanceof Exception ? 'see reference code ' . $contextDepndentExceptionHandlerException->getReferenceCode() . ' in log' : $contextDepndentExceptionHandlerException->getCode()); } } }
/** * Render the Uri. * * @return string The rendered URI or NULL if no URI could be resolved for the given node * @throws NeosException */ public function evaluate() { $baseNode = null; $baseNodeName = $this->getBaseNodeName() ?: 'documentNode'; $currentContext = $this->tsRuntime->getCurrentContext(); if (isset($currentContext[$baseNodeName])) { $baseNode = $currentContext[$baseNodeName]; } else { throw new NeosException(sprintf('Could not find a node instance in TypoScript context with name "%s" and no node instance was given to the node argument. Set a node instance in the TypoScript context or pass a node object to resolve the URI.', $baseNodeName), 1373100400); } try { return $this->linkingService->createNodeUri($this->tsRuntime->getControllerContext(), $this->getNode(), $baseNode, $this->getFormat(), $this->isAbsolute(), $this->getAdditionalParams(), $this->getSection(), $this->getAddQueryString(), $this->getArgumentsToBeExcludedFromQueryString()); } catch (NeosException $exception) { $this->systemLogger->logException($exception); return ''; } }
/** * Returns the current workspace. * * @param boolean $createWorkspaceIfNecessary DEPRECATED: If enabled, creates a workspace with the configured name if it doesn't exist already. This option is DEPRECATED, create workspace explicitly instead. * @return Workspace The workspace or NULL * @api */ public function getWorkspace($createWorkspaceIfNecessary = true) { if ($this->workspace !== null) { return $this->workspace; } $this->workspace = $this->workspaceRepository->findByIdentifier($this->workspaceName); if ($this->workspace === null && $createWorkspaceIfNecessary) { $liveWorkspace = $this->workspaceRepository->findByIdentifier('live'); $this->workspace = new Workspace($this->workspaceName, $liveWorkspace); $this->workspaceRepository->add($this->workspace); $this->systemLogger->log(sprintf('Notice: %s::getWorkspace() implicitly created the new workspace "%s". This behaviour is discouraged and will be removed in future versions. Make sure to create workspaces explicitly by adding a new workspace to the Workspace Repository.', __CLASS__, $this->workspaceName), LOG_NOTICE); } if ($this->workspace !== null) { $this->validateWorkspace($this->workspace); } return $this->workspace; }