/**
  * {@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;
 }
 protected function getBlockContext(BlockServiceInterface $blockService)
 {
     $this->blockServiceManager->expects($this->once())->method('get')->will($this->returnValue($blockService));
     $block = $this->getMock('Sonata\\BlockBundle\\Model\\BlockInterface');
     $block->expects($this->once())->method('getSettings')->will($this->returnValue(array()));
     $blockContext = $this->blockContextManager->get($block);
     $this->assertInstanceOf('Sonata\\BlockBundle\\Block\\BlockContextInterface', $blockContext);
     return $blockContext;
 }
 /**
  * @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;
 }
 /**
  * Test rendering a block that throws an exception.
  */
 public function testRenderBlockWithException()
 {
     // GIVEN
     // mock a block service that throws an user exception
     $service = $this->getMock('Sonata\\BlockBundle\\Block\\BlockServiceInterface');
     $service->expects($this->once())->method('load');
     $exception = $this->getMock('\\Exception');
     $service->expects($this->once())->method('execute')->will($this->returnCallback(function () use($exception) {
         throw $exception;
     }));
     $this->blockServiceManager->expects($this->once())->method('get')->will($this->returnValue($service));
     // mock the exception strategy manager to return a response when given the correct exception
     $response = $this->getMock('Symfony\\Component\\HttpFoundation\\Response');
     $this->exceptionStrategyManager->expects($this->once())->method('handleException')->with($this->equalTo($exception))->will($this->returnValue($response));
     // mock the logger to ensure a crit message is logged
     $this->logger->expects($this->once())->method('critical');
     // mock a block object
     $block = $this->getMock('Sonata\\BlockBundle\\Model\\BlockInterface');
     $blockContext = new BlockContext($block);
     // WHEN
     $result = $this->renderer->render($blockContext);
     // THEN
     $this->assertEquals($response, $result, 'Should return the response provider by the exception manager');
 }
 /**
  * @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();
     }
 }