Symfony VichUploaderBundle autowiring on DownloadHandler in a controller - symfony

I'm using Symfony 4 with VichUploaderBundle 1.9 and I'm having hard time injecting the DownloadHandler service in my controller in order to send file to the client.
I'm also using HashidsBundle in order to convert my entity ID to something like jFaJ in my URLs.
As stated in the VichUploaderBundle documentation, I'm injecting the service in my controller like this :
public function download(Wallpaper $wallpaper, DownloadHandler $downloadHandler)
{
return $downloadHandler->downloadObject($wallpaper->getMedia(), 'uploadedFile');
}
Here is the error I'm having:
Argument 2 passed to App\Controller\WallpapersController::download()
must be an instance of Vich\UploaderBundle\Handler\DownloadHandler,
integer given, called in
/mnt/c/Users/user/Documents/Dev/symfony/vendor/symfony/http-kernel/HttpKernel.php
on line 151
I also tried to manually call the service by adding the following line in my controller:
$this->get('vich_uploader.download_handler');
But it's still not working, I have this error now:
Service "vich_uploader.download_handler" not found: even though it exists in the app's container, the container inside "App\Controller\WallpapersController" is a smaller service locator that only knows about the "doctrine", "form.factory", "http_kernel", "parameter_bag", "request_stack", "router", "security.authorization_checker", "security.csrf.token_manager", "security.token_storage", "serializer", "session" and "twig" services. Try using dependency injection instead.

You can return the file using BinaryFileResponse.
public function download(Wallpaper $wallpaper): BinaryFileResponse
{
$file = new BinaryFileResponse($wallpaper->getMedia());
return $file;
}
For more info, check
https://github.com/aythanztdev/prbtcnccd/blob/master/src/Controller/MediaObject/ShowMediaObjectAction.php

Related

Is there a way to prevent multiple executions of controller method in Symfony 4?

I have a service which I use both from a custom command and an HTML page. I want to prevent multiple executions of the the service in parallel. For the command there is the Lock component that does that. But is it possible to achieve the same thing for a controller method ?
The lock component doesn't work if the service is called from a controller:
$store = new FlockStore(sys_get_temp_dir());
$factory = new Factory($store);
$lock = $factory->createLock('MY_SERVICE');
I wanted to avoid calling the command from the controller (that's why I created a service) mainly because the service doesn't have the same output for the HTML page and the CLI.
Inject the lock Factory into your service directly instead of creating the lock in the command AND in the controller.
First you have to install Lock Component:
composer require symfony/lock
Then, for example, you can declare your service like this:
use Symfony\Component\Lock\Factory as LockFactory;
class MyService {
private $lock;
public function __construct(LockFactory $lockFactory) {
$this->lock = $lockFactory->createLock('LOCK_KEY');
}
public function doWork() {
$this->lock->acquire();
try {
// DO THINGS
} finally {
$this->lock->release();
}
}
}
I said:
The lock component doesn't work if the service is called from a controller:
Actually the issue I had was the Symfony built-in dev server which is single-threaded, so requests can't be executed in parallel, while the CLI PHP is multi-threaded. I couldn't run the script in parallel through the dev server, request were queued, service script was never locked.
The lock component is working the same whether it's called from a command or a controller.
Using the lock like this in the service works fine:
use Symfony\Component\Lock\Factory;
use Symfony\Component\Lock\Store\FlockStore;
$store = new FlockStore(sys_get_temp_dir());
$factory = new Factory($store);
$lock = $factory->createLock('LOCK_KEY');
if ($lock->acquire()) {
//some locked code
$lock->release();
}

Symfony2: How to access a service inside an extension's load() method?

Is it possible to get the doctrine service inside a bundle extension?
I can access the container, but can't get the doctrine service.
...
class UltroExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container){
$dm = $container->get('doctrine_mongodb');
...
}
}
I get this error: The service definition "doctrine_mongodb" does not exist.
The container hasn't been built/compiled yet - that's why you only get a ContainerBuiler object passed to the load() method.
you can't get a service object from the builder as it's not holding the services but only the service definitions at that point.
Use a compiler pass instead. More information can be found in the documentation chapter Compiling the container.
Maybe your problem can be solved using a service factory, too.

Is it possible to mock our own service?

I want to mock a service that is required in a class constructor. I have an exception of PHPUnit : MyService is required, Mock_MyService_0afc7fc1 given.
But with the Request, EntityManager or other Symfony 2 component, I haven't this issue.
Here is my Class's construct :
use Acme\Bundle\Service\MyService;
use Symfony\Component\HttpFoundation\Request;
...
public function __construct(MyService $service, Request $request)
{
and my mock :
...
$service = $this->getMock('MyService');
$class = new Class($service, $request);
It's impossible to mock our own service ? Only Symfony 2 component ?
PS : If I delete MyServicelike that : public function __construct($service, Request $request), this works. But I want to define my variable with it :(
The issue is that PHPUnit at the time of the test execution can't find (or autoload) your MyService class.
That means that you'll probably run into the same issues with other Mocking libraries as all of them require the original class to exist to scan it and create the mock.
It happens because you need to tell PHPUnit the Fully-Qualified Class Name.
Change your code to $this->getMock("\Acme\Bundle\Service\MyService"); and it should work out.
(Still, give mockery a try. It's a nice library)

Accessing services directory when setting up Zend AMF in Codeigniter

I followed the instructions in this tutorial to set up Zend AMF as a way of passing data from my flash app to my PHP app:
http://codeigniter.com/forums/viewthread/180414/
So I have the directory structure and everything as described there. This is my gateway controller:
class Gateway extends CI_Controller
{
function __construct()
{
parent::__construct();
$this->load->library('zend');
//root_folder + application + controllers + amf + services
define('SERVICES_FOLDER', APPPATH.'controllers/amf/services/');
}
public function index()
{
$server = new Zend_Amf_Server();
$server->setProduction(false);
//$server->addFunction('testservice');
$server->addDirectory(SERVICES_FOLDER);
echo $server->handle();
}
}
And the APPPATH is /application/ so the path defined by SERVIES_FOLDER is "/application/controllers/amf/services" which is where my file 'testservice.php' sits.
When I try and connect to that service in flash:
var gateway:String = "http://mysite.com/amf/gateway";
con.connect(gateway);
con.call("Testservice.getMessage", new Responder(onResult, onFault));
It calls the onFault method and displays the error:
Plugin by name 'Testservice' was not found in the registry;
Which makes me think that the addDirectory() line in Gateway.php was the problem somehow. Interestingly, I also cannot access the testservice function through a URL, ie by going to mysite.com/amf/services/testservice.
Any thoughts on what might be going on here?
Figured it out, sort of.
Instead of using the addDirectory method which I was having no luck with, I used the setClass method and created another class within the gateway.php file that has the functions, and now I can connect to those functions from flash.
I had an issue with this when using parent::__construct() in my service controllers. Once I removed that, the problem went away.

Routing in Silex/Symfony. Providing a default route

I'm attempting to do something using Silex (which uses the Symfony routing component - so the answer may be applicable to Symfony as well)
I am adding Silex to a legacy application to provide routing but I need to respect the existing applications default implementation for loading files (which is simply to load the file from the file system form the URL specified).
edit: for clarification:
Existing file is loaded from the file system, as an include within an parent template, after a series of bootstrapping calls have been made.
What I'm finding is that in the absence of a defined route to match the legacy pages, Silex is throwing an exception.
I really need a way to provide a default (fallback) mechanism for handling those legacy pages - but my pattern has to match the entire url (not just one fragment).
Is this possible?
// Include Silex for routing
require_once(CLASS_PATH . 'Silex/silex.phar');
// Init Silex
$app = new Silex\Application();
// route for new code
// matches for new restful interface (like /category/add/mynewcategory)
$app->match('/category/{action}/{name}/', function($action, $name){
//do RESTFUL things
});
// route for legacy code (If I leave this out then Silex
// throws an exception beacuse it hasn't matched any routes
$app->match('{match_the_entire_url_including_slashes}', function($match_the_entire_url_including_slashes){
//do legacy stuff
});
$app->run();
This must be a common use case. I'm trying to provide a way to have a RESTFUL interface alongside legacy code (load /myfolder/mysubfolder/my_php_script.php)
I found the answer within the symfony cookbook...
http://symfony.com/doc/2.0/cookbook/routing/slash_in_parameter.html
$app->match('{url}', function($url){
//do legacy stuff
})->assert('url', '.+');
You can use the error handling, with something like that :
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
$app->error(function (\Exception $e) use ($app) {
if ($e instanceof NotFoundHttpException) {
return new Response('The requested page could not be found. '.$app['request']->getRequestUri(), 404);
}
$code = ($e instanceof HttpException) ? $e->getStatusCode() : 500;
return new Response('We are sorry, but something went terribly wrong.', $code);
});

Resources