From d9a84990cf78a670b12ee6969e6c5a2a7e9a11ed Mon Sep 17 00:00:00 2001 From: Dennis Fridrich Date: Sun, 10 Apr 2016 20:40:47 +0200 Subject: [PATCH] [FrameworkBundle] Add file helper to Controller --- .../FrameworkBundle/Controller/Controller.php | 20 +++ .../Tests/Controller/ControllerTest.php | 128 ++++++++++++++++++ 2 files changed, 148 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php index db436a03c4..c6db25721f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php @@ -13,9 +13,12 @@ namespace Symfony\Bundle\FrameworkBundle\Controller; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerAwareTrait; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -123,6 +126,23 @@ abstract class Controller implements ContainerAwareInterface return new JsonResponse($data, $status, $headers); } + /** + * Returns a BinaryFileResponse object with original or customized file name and disposition header. + * + * @param File|string $file File object or path to file to be sent as response + * @param string|null $fileName File name to be sent to response or null (will use original file name) + * @param string $disposition Disposition of response ("attachment" is default, other type is "inline") + * + * @return BinaryFileResponse + */ + protected function file($file, $fileName = null, $disposition = ResponseHeaderBag::DISPOSITION_ATTACHMENT) + { + $response = new BinaryFileResponse($file); + $response->setContentDisposition($disposition, $fileName === null ? $response->getFile()->getFileName() : $fileName); + + return $response; + } + /** * Adds a flash message to the current session for type. * diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTest.php index 4063a00ab7..2821e7faf8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTest.php @@ -14,10 +14,13 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Controller; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpFoundation\ResponseHeaderBag; use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; @@ -209,6 +212,126 @@ class ControllerTest extends TestCase $this->assertEquals('{}', $response->getContent()); } + public function testFile() + { + /* @var ContainerInterface $container */ + $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); + $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); + $container->set('kernel', $kernel); + + $controller = new TestController(); + $controller->setContainer($container); + + /* @var BinaryFileResponse $response */ + $response = $controller->file(new File(__FILE__)); + $this->assertInstanceOf(BinaryFileResponse::class, $response); + $this->assertSame(200, $response->getStatusCode()); + if ($response->headers->get('content-type')) { + $this->assertSame('text/x-php', $response->headers->get('content-type')); + } + $this->assertContains(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $response->headers->get('content-disposition')); + $this->assertContains(basename(__FILE__), $response->headers->get('content-disposition')); + } + + public function testFileAsInline() + { + $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); + $controller = new TestController(); + $controller->setContainer($container); + + /* @var BinaryFileResponse $response */ + $response = $controller->file(new File(__FILE__), null, ResponseHeaderBag::DISPOSITION_INLINE); + + $this->assertInstanceOf(BinaryFileResponse::class, $response); + $this->assertSame(200, $response->getStatusCode()); + if ($response->headers->get('content-type')) { + $this->assertSame('text/x-php', $response->headers->get('content-type')); + } + $this->assertContains(ResponseHeaderBag::DISPOSITION_INLINE, $response->headers->get('content-disposition')); + $this->assertContains(basename(__FILE__), $response->headers->get('content-disposition')); + } + + public function testFileWithOwnFileName() + { + $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); + $controller = new TestController(); + $controller->setContainer($container); + + /* @var BinaryFileResponse $response */ + $fileName = 'test.php'; + $response = $controller->file(new File(__FILE__), $fileName); + + $this->assertInstanceOf(BinaryFileResponse::class, $response); + $this->assertSame(200, $response->getStatusCode()); + if ($response->headers->get('content-type')) { + $this->assertSame('text/x-php', $response->headers->get('content-type')); + } + $this->assertContains(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $response->headers->get('content-disposition')); + $this->assertContains($fileName, $response->headers->get('content-disposition')); + } + + public function testFileWithOwnFileNameAsInline() + { + $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerInterface'); + $controller = new TestController(); + $controller->setContainer($container); + + /* @var BinaryFileResponse $response */ + $fileName = 'test.php'; + $response = $controller->file(new File(__FILE__), $fileName, ResponseHeaderBag::DISPOSITION_INLINE); + + $this->assertInstanceOf(BinaryFileResponse::class, $response); + $this->assertSame(200, $response->getStatusCode()); + if ($response->headers->get('content-type')) { + $this->assertSame('text/x-php', $response->headers->get('content-type')); + } + $this->assertContains(ResponseHeaderBag::DISPOSITION_INLINE, $response->headers->get('content-disposition')); + $this->assertContains($fileName, $response->headers->get('content-disposition')); + } + + public function testFileFromPath() + { + $controller = new TestController(); + + /* @var BinaryFileResponse $response */ + $response = $controller->file(__FILE__); + + $this->assertInstanceOf(BinaryFileResponse::class, $response); + $this->assertSame(200, $response->getStatusCode()); + if ($response->headers->get('content-type')) { + $this->assertSame('text/x-php', $response->headers->get('content-type')); + } + $this->assertContains(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $response->headers->get('content-disposition')); + $this->assertContains(basename(__FILE__), $response->headers->get('content-disposition')); + } + + public function testFileFromPathWithCustomizedFileName() + { + $controller = new TestController(); + + /* @var BinaryFileResponse $response */ + $response = $controller->file(__FILE__, 'test.php'); + + $this->assertInstanceOf(BinaryFileResponse::class, $response); + $this->assertSame(200, $response->getStatusCode()); + if ($response->headers->get('content-type')) { + $this->assertSame('text/x-php', $response->headers->get('content-type')); + } + $this->assertContains(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $response->headers->get('content-disposition')); + $this->assertContains('test.php', $response->headers->get('content-disposition')); + } + + /** + * @expectedException \Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException + */ + public function testFileWhichDoesNotExist() + { + $controller = new TestController(); + + /* @var BinaryFileResponse $response */ + $response = $controller->file('some-file.txt', 'test.php'); + } + public function testIsGranted() { $authorizationChecker = $this->getMock('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface'); @@ -494,6 +617,11 @@ class TestController extends Controller return parent::json($data, $status, $headers, $context); } + public function file($file, $fileName = null, $disposition = ResponseHeaderBag::DISPOSITION_ATTACHMENT) + { + return parent::file($file, $fileName, $disposition); + } + public function isGranted($attributes, $object = null) { return parent::isGranted($attributes, $object);