Author: Bob den Otter, bob@twokings.nl
Beispiel #1
0
 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;
     }
 }
Beispiel #2
0
 /**
  * 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);
     }
 }
Beispiel #3
0
 /**
  * {@inheritdoc}
  */
 public function check(ExceptionControllerInterface $exceptionController)
 {
     $exceptions = $this->config->getExceptions();
     if ($exceptions === null) {
         return null;
     }
     return $exceptionController->systemCheck(Validator::CHECK_CONFIG, $exceptions);
 }
Beispiel #4
0
 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());
 }
Beispiel #5
0
 /**
  * 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;
 }
Beispiel #6
0
 /**
  * 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);
     }
 }
Beispiel #7
0
 /**
  * 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));
     }
 }
Beispiel #8
0
 /**
  * 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);
     }
 }
Beispiel #9
0
 /**
  * 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;
 }
Beispiel #10
0
 /**
  * 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);
 }
Beispiel #11
0
 /**
  * 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);
 }
Beispiel #12
0
 /**
  * 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);
                 }
             }
         }
     }
 }
Beispiel #14
0
 /**
  * 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;
 }
Beispiel #15
0
 /**
  * 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);
 }
Beispiel #16
0
 /**
  * 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);
     }
 }
Beispiel #17
0
 /**
  * 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;
 }
Beispiel #18
0
 /**
  * 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);
 }
Beispiel #19
0
 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);
 }
Beispiel #21
0
 /**
  * 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;
 }
Beispiel #22
0
 /**
  * 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;
 }
Beispiel #23
0
 /**
  * Get the array of configured acceptable file extensions.
  *
  * @return array
  */
 public function getAllowedUploadExtensions()
 {
     return $this->config->get('general/accept_file_types');
 }
Beispiel #24
0
 /**
  * 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);
 }