/** * {@inheritdoc} */ public function render(BlockContextInterface $blockContext, Response $response = null) { $block = $blockContext->getBlock(); if ($this->logger) { $this->logger->info(sprintf('[cms::renderBlock] block.id=%d, block.type=%s ', $block->getId(), $block->getType())); } try { $service = $this->blockServiceManager->get($block); $service->load($block); $response = $service->execute($blockContext, $this->createResponse($blockContext, $response)); if (!$response instanceof Response) { $response = null; throw new \RuntimeException('A block service must return a Response object'); } $response = $this->addMetaInformation($response, $blockContext, $service); } catch (\Exception $exception) { if ($this->logger) { $this->logger->critical(sprintf('[cms::renderBlock] block.id=%d - error while rendering block - %s', $block->getId(), $exception->getMessage())); } // reseting the state object $this->lastResponse = null; $response = $this->exceptionStrategyManager->handleException($exception, $blockContext->getBlock(), $response); } return $response; }
/** * @param BlockInterface $block * @param array $settings * * @return array */ private function resolve(BlockInterface $block, $settings) { $optionsResolver = new \Sonata\BlockBundle\Util\OptionsResolver(); $this->setDefaultSettings($optionsResolver, $block); $service = $this->blockService->get($block); $service->setDefaultSettings($optionsResolver, $block); // Caching method reflection $serviceClass = get_class($service); if (!isset($this->reflectionCache[$serviceClass])) { $reflector = new \ReflectionMethod($service, 'setDefaultSettings'); $isOldOverwritten = $reflector->getDeclaringClass()->getName() !== 'Sonata\\BlockBundle\\Block\\AbstractBlockService'; // Prevention for service classes implementing directly the interface and not extends the new base class if (!method_exists($service, 'configureSettings')) { $isNewOverwritten = false; } else { $reflector = new \ReflectionMethod($service, 'configureSettings'); $isNewOverwritten = $reflector->getDeclaringClass()->getName() !== 'Sonata\\BlockBundle\\Block\\AbstractBlockService'; } $this->reflectionCache[$serviceClass] = array('isOldOverwritten' => $isOldOverwritten, 'isNewOverwritten' => $isNewOverwritten); } if ($this->reflectionCache[$serviceClass]['isOldOverwritten'] && !$this->reflectionCache[$serviceClass]['isNewOverwritten']) { @trigger_error('The Sonata\\BlockBundle\\Block\\BlockServiceInterface::setDefaultSettings() method is deprecated since version 2.3 and will be removed in 3.0. Use configureSettings() instead. This method will be added to the BlockServiceInterface with SonataBlockBundle 3.0.', E_USER_DEPRECATED); } return $optionsResolver->resolve($settings); }
/** * @param BlockInterface $block * * @return BlockInterface */ private function loadBlockDefaults(BlockInterface $block) { $service = $this->blockManager->get($block); $resolver = new OptionsResolver(); $service->setDefaultSettings($resolver); try { $block->setSettings($resolver->resolve($block->getSettings())); } catch (InvalidOptionsException $e) { // @TODO : add a logging error or a flash message } $service->load($block); return $block; }
/** * @param mixed $block * @param array $options * * @return null|Response */ public function render($block, array $options = array()) { $blockContext = $this->blockContextManager->get($block, $options); if (!$blockContext instanceof BlockContextInterface) { return ''; } $stats = array(); if ($this->stopwatch) { $stats = $this->startTracing($blockContext->getBlock()); } $service = $this->blockServiceManager->get($blockContext->getBlock()); $this->computeAssets($blockContext, $stats); $useCache = $blockContext->getSetting('use_cache'); $cacheKeys = $response = false; $cacheService = $useCache ? $this->getCacheService($blockContext->getBlock(), $stats) : false; if ($cacheService) { $cacheKeys = array_merge($service->getCacheKeys($blockContext->getBlock()), $blockContext->getSetting('extra_cache_keys')); if ($this->stopwatch) { $stats['cache']['keys'] = $cacheKeys; } // Please note, some cache handler will always return true (js for instance) // This will allows to have a non cacheable block, but the global page can still be cached by // a reverse proxy, as the generated page will never get the generated Response from the block. if ($cacheService->has($cacheKeys)) { $cacheElement = $cacheService->get($cacheKeys); if ($this->stopwatch) { $stats['cache']['from_cache'] = false; } if (!$cacheElement->isExpired() && $cacheElement->getData() instanceof Response) { /* @var Response $response */ if ($this->stopwatch) { $stats['cache']['from_cache'] = true; } $response = $cacheElement->getData(); } } } if (!$response) { $recorder = null; if ($this->cacheManager) { $recorder = $this->cacheManager->getRecorder(); if ($recorder) { $recorder->add($blockContext->getBlock()); $recorder->push(); } } $response = $this->blockRenderer->render($blockContext); $contextualKeys = $recorder ? $recorder->pop() : array(); if ($this->stopwatch) { $stats['cache']['contextual_keys'] = $contextualKeys; } if ($response->isCacheable() && $cacheKeys && $cacheService) { $cacheService->set($cacheKeys, $response, $response->getTtl(), $contextualKeys); } } if ($this->stopwatch) { $stats['cache']['created_at'] = $response->getDate(); $stats['cache']['ttl'] = $response->getTtl() ?: 0; $stats['cache']['age'] = $response->getAge(); } // update final ttl for the whole Response if ($this->cacheHandler) { $this->cacheHandler->updateMetadata($response, $blockContext); } if ($this->stopwatch) { $this->stopTracing($blockContext->getBlock(), $stats); } return $response->getContent(); }
/** * {@inheritdoc} * * @param BaseBlock $object */ public function postRemove($object) { $this->blockManager->get($object)->postRemove($object); }
/** * {@inheritdoc} */ protected function configureFormFields(FormMapper $formMapper) { $block = $this->getSubject(); $dashboard = false; if ($this->getParent()) { $dashboard = $this->getParent()->getSubject(); if (!$dashboard instanceof DashboardInterface) { throw new \RuntimeException('The BlockAdmin must be attached to a parent DashboardAdmin'); } if ($block->getId() === null) { // new block $block->setType($this->request->get('type')); $block->setDashboard($dashboard); } if ($block->getDashboard()->getId() != $dashboard->getId()) { throw new \RuntimeException('The dashboard reference on BlockAdmin and parent admin are not the same'); } } $isComposer = $this->hasRequest() ? $this->getRequest()->get('composer', false) : false; $generalGroupOptions = $optionsGroupOptions = array(); if ($isComposer) { $generalGroupOptions['class'] = 'hidden'; $optionsGroupOptions['name'] = ''; } $formMapper->with($this->trans('form.field_group_general'), $generalGroupOptions); $containerBlockTypes = $this->containerBlockTypes; $isContainerRoot = $block && in_array($block->getType(), $containerBlockTypes) && !$this->hasParentFieldDescription(); $isStandardBlock = $block && !in_array($block->getType(), $containerBlockTypes) && !$this->hasParentFieldDescription(); if (!$isComposer) { $formMapper->add('name'); } elseif (!$isContainerRoot) { $formMapper->add('name', 'hidden'); } $formMapper->end(); if ($isContainerRoot || $isStandardBlock) { $formMapper->with($this->trans('form.field_group_general'), $generalGroupOptions); $service = $this->blockManager->get($block); // need to investigate on this case where $dashboard == null ... this should not be possible if ($isStandardBlock && $dashboard && !empty($containerBlockTypes)) { $formMapper->add('parent', 'entity', array('class' => $this->getClass(), 'query_builder' => function (EntityRepository $repository) use($dashboard, $containerBlockTypes) { return $repository->createQueryBuilder('a')->andWhere('a.dashboard = :dashboard AND a.type IN (:types)')->setParameters(array('dashboard' => $dashboard, 'types' => $containerBlockTypes)); }), array('admin_code' => $this->getCode())); } if ($isComposer) { $formMapper->add('enabled', 'hidden', array('data' => true)); } else { $formMapper->add('enabled'); } if ($isStandardBlock) { $formMapper->add('position', 'integer'); } $formMapper->end(); $formMapper->with($this->trans('form.field_group_options'), $optionsGroupOptions); if ($block->getId() > 0) { $service->buildEditForm($formMapper, $block); } else { $service->buildCreateForm($formMapper, $block); } // When editing a container in composer view, hide some settings if ($isContainerRoot && $isComposer) { $formMapper->remove('children'); $formMapper->add('name', 'text', array('required' => true)); $formSettings = $formMapper->get('settings'); $formSettings->remove('code'); $formSettings->remove('layout'); $formSettings->remove('template'); } $formMapper->end(); } else { $formMapper->with($this->trans('form.field_group_options'), $optionsGroupOptions)->add('type', 'sonata_block_service_choice', array('context' => 'sonata_dashboard_bundle'))->add('enabled')->add('position', 'integer')->end(); } }