public function register(Application $app) { $app['config'] = $app->share(function ($app) { $config = new Config($app); $config->initialize(); return $config; }); $app['config.environment'] = $app->share(function ($app) { $appPath = $app['resources']->getPath('app'); $viewPath = $app['resources']->getPath('view'); $environment = new Environment($appPath, $viewPath, $app['cache'], $app['extend.action'], Bolt\Version::VERSION); return $environment; }); $app['config.validator'] = $app->share(function ($app) { $validator = new ConfigValidator($app['controller.exception'], $app['config'], $app['resources']); return $validator; }); $app['config.listener'] = $app->share(function ($app) { return new ConfigListener($app); }); if (!isset($app['config.pre_boot'])) { $this->preBoot($app['resources']); $app['config.pre_boot'] = true; } }
/** * Initialize the configuration value. */ public function initialize() { if (!$this->checked) { $this->config->checkConfig(); $this->checked = true; $this->data = $this->config->get($this->path, $this->default); } }
/** * {@inheritdoc} */ public function check(ExceptionControllerInterface $exceptionController) { $exceptions = $this->config->getExceptions(); if ($exceptions === null) { return null; } return $exceptionController->systemCheck(Validator::CHECK_CONFIG, $exceptions); }
public function setUp() { $this->_filesystem = PHPUnit_Extension_FunctionMocker::start($this, 'Symfony\\Component\\Filesystem')->mockFunction('file_exists')->mockFunction('is_dir')->mockFunction('is_readable')->mockFunction('is_writable')->mockFunction('rmdir')->mockFunction('touch')->mockFunction('unlink')->getMock(); $this->_validation = PHPUnit_Extension_FunctionMocker::start($this, 'Bolt\\Configuration\\Validation')->mockFunction('extension_loaded')->mockFunction('file_exists')->mockFunction('get_magic_quotes_gpc')->mockFunction('ini_get')->mockFunction('is_dir')->mockFunction('is_readable')->mockFunction('is_writable')->mockFunction('rmdir')->mockFunction('touch')->mockFunction('unlink')->getMock(); $this->extensionController = $this->prophesize(Controller\Exception::class); $this->config = $this->prophesize(Config::class); $this->resourceManager = $this->prophesize(ResourceManager::class); $this->validator = new Validator($this->extensionController->reveal(), $this->config->reveal(), $this->resourceManager->reveal()); }
/** * Return an array of ContentTypes with the table name is the key. * * @param Config $config * * @return array */ private function getNormalisedContentTypes(Config $config) { $normalised = []; $contentTypes = $config->get('contenttypes'); foreach ($contentTypes as $contentType) { $normalised[$contentType['tablename']] = $contentType; } return $normalised; }
/** * Kernel request listener callback. * * @param GetResponseEvent $event */ public function onKernelRequest(GetResponseEvent $event) { if (!$event->isMasterRequest()) { return; } $contenttypes = $this->config->get('contenttypes', []); foreach ($contenttypes as $contenttype) { $contenttype = $this->em->getContentType($contenttype['slug']); // Check if we need to 'publish' any 'timed' records, or 'depublish' any expired records. $this->em->publishTimedRecords($contenttype); $this->em->depublishExpiredRecords($contenttype); } }
/** * Add base snippets to the response. */ protected function addSnippets() { $this->queue->add(Target::END_OF_HEAD, '<meta name="generator" content="Bolt">'); if ($this->config->get('general/canonical')) { $canonical = $this->resources->getUrl('canonicalurl'); $this->queue->add(Target::END_OF_HEAD, $this->encode('<link rel="canonical" href="%s">', $canonical)); } if ($favicon = $this->config->get('general/favicon')) { $host = $this->resources->getUrl('hosturl'); $theme = $this->resources->getUrl('theme'); $this->queue->add(Target::END_OF_HEAD, $this->encode('<link rel="shortcut icon" href="%s%s%s">', $host, $theme, $favicon)); } }
/** * Add base snippets to the response. */ protected function addSnippets() { $generatorSnippet = (new Snippet())->setLocation(Target::END_OF_HEAD)->setCallback('<meta name="generator" content="Bolt">'); $this->queue->add($generatorSnippet); $canonicalUrl = $this->canonical->getUrl(); $canonicalSnippet = (new Snippet())->setLocation(Target::END_OF_HEAD)->setCallback($this->encode('<link rel="canonical" href="%s">', $canonicalUrl)); $this->queue->add($canonicalSnippet); if ($favicon = $this->config->get('general/favicon')) { $faviconUrl = $this->packages->getUrl($favicon, 'theme'); $faviconSnippet = (new Snippet())->setLocation(Target::END_OF_HEAD)->setCallback($this->encode('<link rel="shortcut icon" href="%s">', $faviconUrl)); $this->queue->add($faviconSnippet); } }
/** * Build the schema for Bolt ContentType tables. * * @param Schema $schema * @param Config $config * * @return \Doctrine\DBAL\Schema\Table[] */ public function getSchemaTables(Schema $schema, Config $config) { /** @var $fieldManager FieldManager */ $fieldManager = $config->getFields(); $contentTypes = $config->get('contenttypes'); $tables = []; foreach ($this->tables->keys() as $name) { $contentType = $contentTypes[$name]; $tables[$name] = $this->tables[$name]->buildTable($schema, $this->prefix . $name, $name); if (isset($contentType['fields']) && is_array($contentType['fields'])) { $this->addContentTypeTableColumns($this->tables[$name], $tables[$name], $contentType['fields'], $fieldManager); } } return $tables; }
/** * Handle errors thrown in the application. * * @param GetResponseForExceptionEvent $event */ public function onKernelException(GetResponseForExceptionEvent $event) { if ($this->isProfilerRequest($event->getRequest())) { return; } $exception = $event->getException(); $message = $exception->getMessage(); $statusCode = Response::HTTP_INTERNAL_SERVER_ERROR; if ($exception instanceof HttpExceptionInterface) { $statusCode = $exception->getStatusCode(); } // Log the error message $level = LogLevel::CRITICAL; if ($exception instanceof HttpExceptionInterface && $exception->getStatusCode() < 500) { $level = LogLevel::WARNING; } $this->logger->log($level, $message, ['event' => 'exception', 'exception' => $exception]); // Get and send the response if ($this->isJsonRequest($event->getRequest())) { $response = new JsonResponse(['success' => false, 'errorType' => get_class($exception), 'code' => $statusCode, 'message' => $message]); } elseif ($this->config->get('general/debug_error_use_symfony')) { return null; } else { $response = $this->exceptionController->kernelException($event); } $response->setStatusCode($statusCode); $event->setResponse($response); }
/** * Build a valid AJAX response for in-place saves that account for pre/post * save events. * * @param Entity\Content $content * @param boolean $flush * * @return JsonResponse */ private function createJsonUpdate(Entity\Content $content, $flush) { /* * Flush any buffers from saveConent() dispatcher hooks * and make sure our JSON output is clean. * * Currently occurs due to exceptions being generated in the dispatchers * in \Bolt\Storage::saveContent() * StorageEvents::PRE_SAVE * StorageEvents::POST_SAVE */ if ($flush) { Response::closeOutputBuffers(0, false); } $val = $content->toArray(); if (isset($val['datechanged'])) { $val['datechanged'] = (new Carbon($val['datechanged']))->toIso8601String(); } // Adjust decimal point as some locales use a comma and… JavaScript $lc = localeconv(); $fields = $this->config->get('contenttypes/' . $content->getContenttype() . '/fields'); foreach ($fields as $key => $values) { if ($values['type'] === 'float' && $lc['decimal_point'] === ',') { $val[$key] = str_replace('.', ',', $val[$key]); } } // Unset flashbag for ajax $this->loggerFlash->clear(); return new JsonResponse($val); }
/** * Check (and update) any records that need to be updated from "published" to "held". */ public function holdExpiredRecords() { foreach ($this->contentTypeNames as $contentTypeName) { $this->timedHandleRecords($contentTypeName, 'hold'); } $this->cache->save(self::CACHE_KEY_HOLD, true, $this->config->get('general/caching/duration', 10)); }
private function loadThemeConfig(Config $config, $theme, $childTheme) { $themePath = $this->app['resources']->getPath('themebase') . '/' . $theme; if (file_exists($themePath)) { $configFile = $themePath . '/config.yml'; // insert parent path right after child path. $twigPath = $config->get('twigpath'); if ($twigPath) { $childThemePath = $this->app['resources']->getPath('themebase') . '/' . $childTheme; $key = array_search($childThemePath, $twigPath); if ($key !== false) { array_splice($twigPath, $key, 1, array($childThemePath, $themePath)); } $config->set('twigpath', $twigPath); } if (file_exists($configFile)) { $themeConfig = self::mergeConfigFile($configFile); if ($themeConfig) { // load parent theme config, but without overwriting, because child prevails $config->set('theme', Arr::mergeRecursiveDistinct($themeConfig, $config->get('theme'))); // multiple levels allowed if (!empty($themeConfig['parent'])) { $this->loadThemeConfig($config, $themeConfig['parent'], $theme); } } } } }
/** * Does some checks to see whether a ContentType should appear in search results. * This is based on ContentType options. * * @param string $contentType * * @return boolean */ protected function isInvisible($contentType) { $info = $this->config->get('contenttypes/' . $contentType); if ($info) { if (array_key_exists('viewless', $info) && $info['viewless'] == true) { return true; } if (array_key_exists('searchable', $info) && $info['searchable'] == false) { return true; } } return false; }
/** * Fetch a listing of ContentType records. * * @param string $contentTypeSlug * @param ListingOptions $options */ public function action($contentTypeSlug, ListingOptions $options) { // Order has to be set carefully. Either set it explicitly when the user // sorts, or fall back to what's defined in the contenttype. Except for // a ContentType that has a "grouping taxonomy", as that should override // it. That exception state is handled by the query OrderHandler. $contenttype = $this->em->getContentType($contentTypeSlug); $contentParameters = ['paging' => true, 'hydrate' => true, 'order' => $options->getOrder() ?: $contenttype['sort'], 'page' => $options->getPage(), 'filter' => $options->getFilter()]; // Set the amount of items to show per page if (!empty($contenttype['recordsperpage'])) { $contentParameters['limit'] = $contenttype['recordsperpage']; } else { $contentParameters['limit'] = $this->config->get('general/recordsperpage'); } // Filter on taxonomies if ($options->getTaxonomies() !== null) { foreach ($options->getTaxonomies() as $taxonomy => $value) { $contentParameters[$taxonomy] = $value; } } return $this->getContent($contentTypeSlug, $contentParameters, $options); }
/** * Insert jQuery, if it's not inserted already. * * Some of the patterns that 'match' are: * - jquery.js * - jquery.min.js * - jquery-latest.js * - jquery-latest.min.js * - jquery-1.8.2.min.js * - jquery-1.5.js * * @param Request $request * @param Response $response */ protected function addJquery(Request $request, Response $response) { if (!$this->config->get('general/add_jquery', false) && !$this->config->get('theme/add_jquery', false)) { return; } if (Zone::isFrontend($request) === false) { return; } $html = $response->getContent(); $regex = '/<script(.*)jquery(-latest|-[0-9\\.]*)?(\\.min)?\\.js/'; if (!preg_match($regex, $html)) { $jqueryfile = $this->resources->getPath('app/view/js/jquery-2.2.4.min.js'); $asset = (new Snippet())->setLocation(Target::BEFORE_JS)->setCallback('<script src="' . $jqueryfile . '"></script>'); $this->injector->inject($asset, $asset->getLocation(), $response); } }
/** * Insert jQuery, if it's not inserted already. * * Some of the patterns that 'match' are: * - jquery.js * - jquery.min.js * - jquery-latest.js * - jquery-latest.min.js * - jquery-1.8.2.min.js * - jquery-1.5.js * * @param string $html * * @return string HTML */ protected function addJquery($html) { if (!$this->config->get('general/add_jquery', false) && !$this->config->get('theme/add_jquery', false)) { return $html; } $zone = Zone::FRONTEND; if ($request = $this->requestStack->getCurrentRequest()) { $zone = Zone::get($request); } $regex = '/<script(.*)jquery(-latest|-[0-9\\.]*)?(\\.min)?\\.js/'; if ($zone === Zone::FRONTEND && !preg_match($regex, $html)) { $jqueryfile = $this->resources->getPath('app/view/js/jquery-2.1.4.min.js'); $asset = (new Snippet())->setLocation(Target::BEFORE_JS)->setCallback('<script src="' . $jqueryfile . '"></script>'); $html = $this->injector->inject($asset, $asset->getLocation(), $html); } return $html; }
/** * Gets slugs from config imploded for regex. * * @param string $key contenttypes or taxonomy * @param bool $singular Include singular slugs * * @return string */ protected function configAssert($key, $singular) { $types = $this->config->get($key); // No types, nothing to assert. The route _DOES_ expect a string, so // we return a regex that never matches. if (empty($types)) { return '$.'; } $slugs = []; foreach ($types as $type) { $slugs[] = $type['slug']; if ($singular) { $slugs[] = $type['singular_slug']; } } return implode('|', $slugs); }
protected function doDatabaseSqliteCheck(Controller\Exception $exceptionController, array $dbConfig) { if (extension_loaded('pdo_sqlite') === false) { return $exceptionController->databaseDriver('missing', 'SQLite', 'pdo_sqlite'); } // If in-memory connection, skip path checks if (isset($dbConfig['memory']) && $dbConfig['memory'] === true) { return null; } $fs = new Filesystem(); $file = $dbConfig['path']; // If the file is present, make sure it is writable if ($fs->exists($file)) { try { $fs->touch($file); } catch (IOException $e) { return $exceptionController->databasePath('file', $file, 'is not writable'); } return null; } // If the file isn't present, make sure the directory // exists and is writable so the file can be created $dir = dirname($file); if (!$fs->exists($dir)) { // At this point, it is possible that the site has been moved and // the configured Sqlite database file path is no longer relevant // to the site's root path $cacheJson = $this->resourceManager->getPath('cache/config-cache.json'); if ($fs->exists($cacheJson)) { $fs->remove($cacheJson); $this->config->initialize(); if (!$fs->exists($dir)) { return $exceptionController->databasePath('folder', $dir, 'does not exist'); } } else { return $exceptionController->databasePath('folder', $dir, 'does not exist'); } } try { $fs->touch($dir); } catch (IOException $e) { return $exceptionController->databasePath('folder', $dir, 'is not writable'); } return null; }
/** * StorageEvents::PRE_SAVE event callback. * * @param StorageEvent $event */ public function preSave(StorageEvent $event) { $request = $this->requestStack->getCurrentRequest(); if ($request === null) { return; } $contentType = $this->boltConfig->get('contenttypes/' . $event->getContentType()); $translatableFields = $this->getTranslatableFields($contentType['fields']); /** @var Content $record */ $record = $event->getContent(); $values = $record->serialize(); $localeValues = []; if (empty($translatableFields)) { return; } $localeSlug = $request->get('_locale'); $record->set($localeSlug . 'slug', $values['slug']); $locales = $this->config->getLocales(); if ($values['_locale'] == reset($locales)->getSlug()) { $record->set($localeSlug . 'data', '[]'); return; } if ($values['id']) { /** @var Content $defaultContent */ $defaultContent = $this->query->getContent($event->getContentType(), ['id' => $values['id'], 'returnsingle' => true]); } if (in_array('templatefields', $translatableFields)) { $templateFields = $this->boltConfig->get('theme/templatefields/' . $values['template'] . '/fields'); foreach ($templateFields as $key => $field) { if ($field['type'] === 'repeater') { $values['templatefields'][$key] = json_encode($values['templatefields'][$key]); } } } foreach ($translatableFields as $field) { $localeValues[$field] = $values[$field]; if ($values['id']) { $record->set($field, $defaultContent->get($field)); } else { $record->set($field, ''); } } $localeJson = json_encode($localeValues); $record->set($localeSlug . 'data', $localeJson); }
/** * Add an extension to be registered. * * @param ExtensionInterface $extension * @param DirectoryInterface $baseDir * @param string $relativeUrl * @param string|null $composerName * * @throws \RuntimeException * * @return ResolvedExtension */ public function add(ExtensionInterface $extension, DirectoryInterface $baseDir, $relativeUrl, $composerName = null) { if ($this->registered) { throw new \RuntimeException(Trans::__('Can not add extensions after they are registered.')); } // Set paths in the extension $extension->setBaseDirectory($baseDir)->setRelativeUrl($relativeUrl); // Determine if enabled $enabled = $this->config->get('extensions/' . $extension->getId(), true); if ($composerName !== null) { // Map composer name to ID $this->composerNames[$composerName] = $extension->getId(); // Check if enabled by composer name $enabled = $this->config->get("extensions/{$composerName}", $enabled); } // Instantiate resolved extension and mark enabled/disabled $resolved = (new ResolvedExtension($extension))->setEnabled($enabled); return $this->extensions[$extension->getId()] = $resolved; }
/** * Determine which templates will result in templatefields. * * @param ContentType $contentType * @param Content $content * * @return array */ private function getTemplateFieldTemplates(ContentType $contentType, Content $content) { $templateFieldTemplates = []; $templateFieldsConfig = $this->config->get('theme/templatefields'); if ($templateFieldsConfig) { $templateFieldTemplates = array_keys($templateFieldsConfig); // Special case for default template $toRepair = []; foreach ($contentType['fields'] as $name => $field) { if ($field['type'] === 'templateselect' && !empty($content->values[$name])) { $toRepair[$name] = $content->values[$name]; $content->set($name, ''); } } if ($content->hasTemplateFields()) { $templateFieldTemplates[] = ''; } foreach ($toRepair as $name => $value) { $content->set($name, $value); } } return $templateFieldTemplates; }
/** * Get the array of configured acceptable file extensions. * * @return array */ public function getAllowedUploadExtensions() { return $this->config->get('general/accept_file_types'); }
/** * Shorthand to add a field to both the new and legacy managers. * * @param $name * @param $handler */ public function addFieldType($name, $handler) { $this->setHandler($name, $handler); $this->customHandlers[] = $name; $this->boltConfig->getFields()->addField($handler); }