<?php 
 
/* 
 * This file is part of the FOSRestBundle package. 
 * 
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/> 
 * 
 * For the full copyright and license information, please view the LICENSE 
 * file that was distributed with this source code. 
 */ 
 
namespace FOS\RestBundle\Controller; 
 
@trigger_error(sprintf('The %s\ExceptionController class is deprecated since FOSRestBundle 2.8.', __NAMESPACE__), E_USER_DEPRECATED); 
 
use FOS\RestBundle\Exception\FlattenException as FosFlattenException; 
use FOS\RestBundle\Util\ExceptionValueMap; 
use FOS\RestBundle\View\View; 
use FOS\RestBundle\View\ViewHandlerInterface; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\ErrorHandler\Exception\FlattenException; 
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; 
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; 
 
/** 
 * Custom ExceptionController that uses the view layer and supports HTTP response status code mapping. 
 * 
 * @deprecated since 2.8 
 */ 
class ExceptionController 
{ 
    private $viewHandler; 
    private $exceptionCodes; 
    private $showException; 
 
    public function __construct( 
        ViewHandlerInterface $viewHandler, 
        ExceptionValueMap $exceptionCodes, 
        bool $showException 
    ) { 
        $this->viewHandler = $viewHandler; 
        $this->exceptionCodes = $exceptionCodes; 
        $this->showException = $showException; 
    } 
 
    /** 
     * @param \Throwable $exception 
     */ 
    public function showAction(Request $request, $exception, DebugLoggerInterface $logger = null) 
    { 
        $currentContent = $this->getAndCleanOutputBuffering($request->headers->get('X-Php-Ob-Level', -1)); 
 
        if ($exception instanceof \Exception) { 
            $code = $this->getStatusCode($exception); 
        } else { 
            $code = $this->getStatusCodeFromThrowable($exception); 
        } 
        $templateData = $this->getTemplateData($currentContent, $code, $exception, $logger); 
 
        if ($exception instanceof \Exception) { 
            $view = $this->createView($exception, $code, $templateData, $request, $this->showException); 
        } else { 
            $view = $this->createViewFromThrowable($exception, $code, $templateData, $request, $this->showException); 
        } 
 
        $response = $this->viewHandler->handle($view); 
 
        return $response; 
    } 
 
    /** 
     * @param int  $code 
     * @param bool $showException 
     * 
     * @return View 
     */ 
    protected function createView(\Exception $exception, $code, array $templateData, Request $request, $showException) 
    { 
        return $this->createViewFromThrowable($exception, $code, $templateData); 
    } 
 
    /** 
     * @return int 
     */ 
    protected function getStatusCode(\Exception $exception) 
    { 
        return $this->getStatusCodeFromThrowable($exception); 
    } 
 
    private function createViewFromThrowable(\Throwable $exception, $code, array $templateData): View 
    { 
        $view = new View($exception, $code, $exception instanceof HttpExceptionInterface ? $exception->getHeaders() : []); 
        $view->setTemplateVar('raw_exception', false); 
        $view->setTemplateData($templateData, false); 
 
        return $view; 
    } 
 
    private function getTemplateData(string $currentContent, int $code, \Throwable $throwable, DebugLoggerInterface $logger = null): array 
    { 
        if (class_exists(FlattenException::class)) { 
            $exception = FlattenException::createFromThrowable($throwable); 
        } else { 
            $exception = FosFlattenException::createFromThrowable($throwable); 
        } 
 
        return [ 
            'exception' => $exception, 
            'status' => 'error', 
            'status_code' => $code, 
            'status_text' => array_key_exists($code, Response::$statusTexts) ? Response::$statusTexts[$code] : 'error', 
            'currentContent' => $currentContent, 
            'logger' => $logger, 
        ]; 
    } 
 
    /** 
     * Gets and cleans any content that was already outputted. 
     * 
     * This code comes from Symfony and should be synchronized on a regular basis 
     * see src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php 
     */ 
    private function getAndCleanOutputBuffering($startObLevel): string 
    { 
        if (ob_get_level() <= $startObLevel) { 
            return ''; 
        } 
        Response::closeOutputBuffers($startObLevel + 1, true); 
 
        return ob_get_clean(); 
    } 
 
    private function getStatusCodeFromThrowable(\Throwable $exception): int 
    { 
        // If matched 
        if ($statusCode = $this->exceptionCodes->resolveThrowable($exception)) { 
            return $statusCode; 
        } 
 
        // Otherwise, default 
        if ($exception instanceof HttpExceptionInterface) { 
            return $exception->getStatusCode(); 
        } 
 
        return 500; 
    } 
}