feature #18502 [FrameworkBundle] Add file helper to Controller (dfridrich)
This PR was squashed before being merged into the 3.2-dev branch (closes #18502).
Discussion
----------
[FrameworkBundle] Add file helper to Controller
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | no
| New feature? | yes
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets |
| License | MIT
| Doc PR | https://github.com/symfony/symfony-docs/pull/6454
I think it would be more "sexy" to serve files from controller easier (like `json()` helper does).
**This Controller helper allows user to serve files to Response in these ways:**
* pass `Symfony\Component\HttpFoundation\File` (or `Symfony\Component\HttpFoundation\UploadedFile`) instance
* [REMOVED] provide content as `string` and specify file name (mime type will be auto recognized)
* provide path to file (you are still able to specify other than original file name)
**Examples**
return $this->file($uploadedFile);
// ...or...
return $this->file('/path/to/my/picture.jpg');
Commits
-------
d9a8499
[FrameworkBundle] Add file helper to Controller
This commit is contained in:
commit
1e263c0b29
@ -13,9 +13,12 @@ namespace Symfony\Bundle\FrameworkBundle\Controller;
|
|||||||
|
|
||||||
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
|
||||||
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
|
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\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||||
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||||
@ -123,6 +126,23 @@ abstract class Controller implements ContainerAwareInterface
|
|||||||
return new JsonResponse($data, $status, $headers);
|
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.
|
* Adds a flash message to the current session for type.
|
||||||
*
|
*
|
||||||
|
@ -14,10 +14,13 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Controller;
|
|||||||
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
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\JsonResponse;
|
||||||
use Symfony\Component\HttpFoundation\Request;
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
use Symfony\Component\HttpFoundation\RequestStack;
|
use Symfony\Component\HttpFoundation\RequestStack;
|
||||||
use Symfony\Component\HttpFoundation\Response;
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
|
||||||
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
|
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
|
||||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||||
@ -209,6 +212,126 @@ class ControllerTest extends TestCase
|
|||||||
$this->assertEquals('{}', $response->getContent());
|
$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()
|
public function testIsGranted()
|
||||||
{
|
{
|
||||||
$authorizationChecker = $this->getMock('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface');
|
$authorizationChecker = $this->getMock('Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface');
|
||||||
@ -494,6 +617,11 @@ class TestController extends Controller
|
|||||||
return parent::json($data, $status, $headers, $context);
|
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)
|
public function isGranted($attributes, $object = null)
|
||||||
{
|
{
|
||||||
return parent::isGranted($attributes, $object);
|
return parent::isGranted($attributes, $object);
|
||||||
|
Reference in New Issue
Block a user