symfony 2 upload one up bundle - symfony

I use the OneUp bundle for symfony 2, method's listener class is never call
//service.yml
amd_picture.uploadListener:
class: Amd\PictureBundle\Services\UploadListener
arguments: ["#doctrine.orm.entity_manager"]
tag:
- {name: kernel.event_listener, event: oneup_uploader.post_chunk_upload, method: onUpload}
the listener class implements the onUpload method and the corresponding event , is it the rigth event to listen ???
class UploadListener {
private $doctrine;
public function __construct($doctrine) {
$this->doctrine = $doctrine;
}
public function onUpload(PostChunkUploadEvent $event) {
//source code
}
}
the srcipt for the front end template
<script>
YUI().use('uploader', function(Y) {
var uploader = new Y.Uploader(
{
multipleFiles: true,
uploadURL: "{{ oneup_uploader_endpoint('gallery') }}",
width: "300px",
height: "60px"
}).render("#fileupload");
</script>
i don't find why the onUpload method is never call?

you have to use the postPersitentEvent in you use statement:
use Oneup\UploaderBundle\Event\PostPersistEvent;

Small correction:
//service.yml
amd_picture.uploadListener:
class: Amd\PictureBundle\Services\UploadListener
arguments: ["#doctrine.orm.entity_manager"]
tag:
- {name: kernel.event_listener, event: oneup_uploader.post_persist, method: onUpload}
Is not tag. Is:
tags:
- {name: kernel.event_listener, event: oneup_uploader.post_persist, method: onUpload}

The YUI3-Uploader is not able to split files into chunks, therefore the YUI3Controller of the OneupUploaderBundle does not support it either. This means there is no post_chunk_upload which will be dispatched and your EventListener is never called.
If you want to process your file after it is uploaded successfully, try listen to the PostPersistEvent like described in the bundles manual.
//service.yml
amd_picture.uploadListener:
class: Amd\PictureBundle\Services\UploadListener
arguments: ["#doctrine.orm.entity_manager"]
tag:
- {name: kernel.event_listener, event: oneup_uploader.post_persist, method: onUpload}
And be sure to pass a PostPersistEvent object to the listener.
use Oneup\UploaderBundle\Event\PostPersistEvent;
class UploadListener {
public function onUpload(PostPersistEvent $event)
{
//...
}
}

Related

Sylius/Symfony: Image Upload with custom entity

I'm trying to use Sylius' ImagesUploadListener for a custom entity.
In the documentation it says I should listen to an event like "sylius.shipping_method.pre_create". For my custom entity there is no event called that I could hook on.
So what I tried was hooking on the product.pre_create event and giving my entity as a parameter, but it seems that the image upload is only triggered on the product entity and my entity configuration is ignored. Although the ImagesUploadListener is triggered two times, once from the core and once from my configuration.
The error I get is "Column 'path' cannot be null" which basically means that the ImagesUploadListener was not performing the image upload before saving the entity.
app.listener.images_upload:
class: Sylius\Bundle\CoreBundle\EventListener\ImagesUploadListener
parent: sylius.listener.images_upload
autowire: true
autoconfigure: false
public: false
tags:
- { name: kernel.event_listener, event: sylius.product.pre_create, entity: MyBundle\Entity\MyEntity, method: uploadImages }
There should be an event to hook on if you created the entity correctly (the Sylius way). You need to define the entity as a Resource:
# config/packages/sylius_resource.yaml
sylius_resource:
resources:
app.name_of_etity:
driver: doctrine/orm
classes:
model: App\Entity\NameOfEntity
If you defined the resource like this, the events would be:
event: app.system_manual.pre_create
event: app.app.name_of_entity.pre_update
Follow this guide:
https://docs.sylius.com/en/1.6/cookbook/entities/custom-model.html
Update
Because you are managing your custom entity through the existing product form the above will not work. To make it work, you can create your own event listener.
final class ProductSeoTranslationImagesUploadListener
{
/** #var ImageUploaderInterface */
private $uploader;
public function __construct(ImageUploaderInterface $uploader)
{
$this->uploader = $uploader;
}
public function uploadImages(GenericEvent $event): void
{
$subject = $event->getSubject();
// Add a ProductSeoInterface so you can use this check:
Assert::isInstanceOf($subject, ProductSeoInterface::class);
foreach ($subject->getSeo()->getTranslations() as $translation) {
Assert::isInstanceOf($translation, ImagesAwareInterface::class);
$this->uploadSubjectImages($translation);
}
}
private function uploadSubjectImages(ImagesAwareInterface $subject): void
{
$images = $subject->getImages();
foreach ($images as $image) {
if ($image->hasFile()) {
$this->uploader->upload($image);
}
// Upload failed? Let's remove that image.
if (null === $image->getPath()) {
$images->removeElement($image);
}
}
}
}
Tip: Create a (Product)SeoInterface so you can perform the type check.
Don't forget to register the eventListener:
App\EventListener\ProductSeoTranslationImagesUploadListener:
tags:
- {
name: kernel.event_listener,
event: sylius.product.pre_create,
method: uploadImages,
}
- {
name: kernel.event_listener,
event: sylius.product.pre_update,
method: uploadImages,
}

How to configure symfony2/3 to handle different domains serving different views?

Is it possible to configure symfony2/3 to handle more than 1 domain with different views?
For example I have site1.com and site2.com, I would create a site1 and site2 folders inside app/Resources/views and serve a different set of templates depending on the domain.
Models and controllers should be in common so site1.com/mypage and site2.com/mypage should serve the same content with different layout.
Any suggestion or best practice related to it is welcome.
Thanks
Check for the host in your controller :
namespace Acme\FooBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
class DemoController
{
public function showAction(Request $request)
{
switch($request->getHost())
{
case 'site1.com':
return $this->render('site1/show.html.twig');
break;
case 'site2.com':
return $this->render('site2/show.html.twig');
break;
default:
return $this->render('default/show.html.twig');
}
}
}
EDIT : Something more generic
Create a onKernelRequest listener :
namespace AppBundle\EventListener;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class DomainRequestListener
{
public function onKernelRequest(GetResponseEvent $event)
{
$request = $event->getRequest();
$host = explode('.',$request->getHost());
$request->request->attributes->set('_domain',$host[0]);
}
}
Add this listener in services.yml :
app.listener.domain_request:
class: AppBundle\EventListener\DomainRequestListener
tags:
- { name: kernel.event_listener, event: kernel.request, method: onKernelRequest}
Then you can use the '_domain' routing parameter in all your controllers :
return $this->render($request->attributes->get('_domain').'/show.html.twig');
Not tested, but I expect the following should work. You'll want to register a kernel request listener that uses the Twig loader service (responsible for locating the templates) and registers a path based on the request's hostname.
Create a request listener:
<?php
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class RegisterTwigPathSubscriber implements EventSubscriberInterface
{
private $loader;
public function __construct(\Twig_Loader_Filesystem $loader)
{
$this->loader = $loader;
}
public static function getSubscribedEvents()
{
return [
KernelEvents::REQUEST => 'registerTwigPath'
];
}
public function registerTwigPath(GetResponseEvent $event)
{
$host = $event->getRequest()->getHost();
$path = '...'; // determine path based on hostname
$this->loader->addPath($path, 'Theme'); // the second argument is a namespace for templates located under this folder and can be chosen
}
}
Register the event listener:
services:
register_twig_path_listener:
class: RegisterTwigPathSubscriber
arguments: ["#twig.loader"]
tags: [{ name: kernel.event_subscriber }]
Now to reference the template:
return $this->render('#Theme/path/to/actual/template.html.twig');

Exception only shown on DEV env. symfony2

I've got little problem.
I've overrided all html exception templates in app/Resources/TwigBundle/Resources/Exception...
My problem is, that these error pages are only rendered when I'm on the dev env.
When it comes to prod I'll get something like:
http://i.stack.imgur.com/GHd7t.png
Please help me out.
You can do it by registering a service listening to the kernel.view event.
in your service.yml:
your.kernel_listener:
class: Your\AppBundle\EventListener\KernelListener
arguments: [#kernel]
tags:
- { name: kernel.event_listener, event: kernel.view, method: onKernelView }
in your class KernelListener:
namespace Your\AppBundle\EventListener;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\HttpFoundation\Response;
class KernelListener
{
private $kernel;
public function __construct(Kernel $kernel)
{
$this->kernel = $kernel;
}
public function onKernelView(GetResponseForControllerResultEvent $event)
{
if ($this->kernel->getEnvironment() == 'dev') {
$result = $event->getControllerResult();
$response = new Response(print_r($result, true), 200, array('Content-Type' => 'text/html'));
$event->setResponse($response);
}
}
}
Have a look at this guide.

Symfony2 : onKernelResponse called twice as MASTER_REQUEST

I'm using the event listener onKernelResponse.
I used :
if (HttpKernelInterface::MASTER_REQUEST != $event->getRequestType()) {
return;
}
It's having a MASTER_REQUEST twice in my action, there is one before the <!DOCTYPE html> <html> <head>etc, and the other one as excepted after the end of the layout.
He is my services.yml :
history.listener:
class: VENDOR\MyBundle\Service\HistoryListener
arguments: [#doctrine.orm.entity_manager, #logger, #history]
tags:
- { name: kernel.event_listener, event: kernel.controller, method: onKernelController }
- { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }
Did I do something wrong?
Finally found the origin of the problem : the debug toolbar !
It actually sends an ajax request, meaning another MASTER_REQUEST..
My solution is to filter on Controller, with a white/black list of controller's names.
UPDATE:
Here is the code I'm using (so you can easily exclude some other controllers if needed).
public function __construct()
{
$this->classesExcluded = array("Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController");
}
public function onKernelController(FilterControllerEvent $event)
{
$controller = $event->getController();
if (!is_array($controller) || HttpKernelInterface::MASTER_REQUEST != $event->getRequestType() || in_array(get_class($controller[0]), $this->classesExcluded)) {
return;
}
// ...
}

Making an Object accessible in a controllers which was set in kernel.controller Event

How can make an Object accessible in a controllers which was set in kernel.controller Event?
I have a onKernelController method which is run before controller and I need some data in a controller which was set in onKernelController.
You can use dependency injection to solve this:
1) Turn your object/class into a service and inject it into the listener.
services:
your_object:
class: Your\Namespace\YourObjectClass
your_listener:
class: Your\Namespace\YourListener
arguments: [ #your_object ]
tags:
- { name: kernel.controller, event: kernel.request, method: onKernelController }
2) Set some property (can be an object aswell) on the injected object
listener class
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
class YourListener
{
protected $object;
public function __construct($object)
{
$this->object = $object;
}
public function onKernelController(FilterControllerEvent $event)
{
// ...
$object->setProperty('some_property_value');
}
}
3.) Get the property inside a container-aware controller (or turn your controller into a service aswell and inject #your_object )
controller
use Symfony\Component\DependencyInjection\ContainerAware;
// or: use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class SomeController extends ContainerAware // or: extends Controller
{
public function someAction()
{
$property = $this->container->get('your_object')->getProperty;
// $property => 'some_property_value'
}

Resources