Upload multiple files in PHP form - php

I am currently uploading single image file at a time to mysql database, However I need to upload 800 images, so I want to select all images and upload them by one click. This is my PHP controller
/**
* #Route("/insert", name="satellite_images_create")
*/
public function insertAction(Request $request)
{
$satelliteImage=new satelliteImage;
$form=$this->createFormBuilder($satelliteImage)
->add('file')
->add('save',SubmitType::class,array('label'=>'Insert Image','attr'=>array('class'=>'btn btn-primary','style'=>'margin-bottom:15px')))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em=$this->getDoctrine()->getManager();
$satelliteImage->upload();
$em->persist($satelliteImage);
$em->flush();
$this->addFlash(
'notice',
'Image inserted successfully'
);
return $this->redirectToRoute('satellite_images');
}
return $this->render('satelliteImages/insert.html.twig',array(
'form'=>$form->createView()));
}
SatelliteImage ENTITY has a function to handle the upload
public function upload()
{
// the file property can be empty if the field is not required
if (null === $this->getFile()) {
return;
}
$imgFile=$this->getFile();
$this->setImage(file_get_contents($imgFile));
$this->getFile()->move(
$this->getUploadRootDir(),
$this->getFile()->getClientOriginalName()
);
// set the path property to the filename where you've saved the file
$this->path = $this->getFile()->getClientOriginalName();
// clean up the file property as you won't need it anymore
$this->file = null;
}
And here is my twig file
{% extends 'base.html.twig' %}
{% block body %}
<h2 class="page-header">Insert Image</h2>
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% endblock %}
How I modify the form and the upload function so that I can select all the image files to be uploaded?Thanks.

I would recommend checking out DropzoneJS http://www.dropzonejs.com/
It is a javascript front end for handling multiple file uploads. It works by passing the files to a PHP backend for storage / processing.
EDIT - ADDITION
If you need info on how to use DropzoneJS with symfony2 then check out Multi upload Symfony 2.3 with Dropzone
Also, this question is basically a duplicate of Problems With Multiple File Upload In Symfony2

Related

How to pass custom option to twig template of custom Symfony FormType?

How can I pass custom options directly to the Twig template of a custom Symfony 3.4 FormType?
Context:
I have created a custom FormType which also uses a custom Twig template to render its form widget. The build-in options (e.g. translation_domain, lable_attr, etc.) are directly accessible in the template. How can I achieve the same for my custom options?
// MyCustomType.php
class MyCustomType extends AbstractType {
public function getBlockPrefix() {
return 'my_custom_field';
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'custom_option' => 'customOptionValue',
'translation_domain' => 'customTranslationDomain',
]);
$resolver->setAllowedTypes('custom_option', ['string']);
}
}
// form_widgets.html.twig
{% block my_custom_field_widget %}
{{ dump() }}
{{ translation_domain }}
{#{ custom_option }#}
{% endblock %}
Of course this form widget is not very useful, it only dumps the available variables and the content of translation_domain which is directly accessible. Adding {{ custom_option }} will lead to an error, since this option/variable is not available. Neither directly nor via form.vars.custom_option.
Only when setting the option as form var, it can be accessed in the template:
// MyCustomType.php
class MyCustomType extends AbstractType {
...
public function buildView(FormView $view, FormInterface $form, array $options) {
$view->vars['custom_option'] = $options['custom_option'];
}
}
// form_widgets.html.twig
{% block my_custom_field_widget %}
// fails
{{ custom_option }}
// works
{{ form.vars.custom_option }}
{% endblock %}
So, all built-in options are available in form_vars but can also be accessed directly (e.g. as form.vars.translation_domain' AND as translation_domain`).
How do I achieve the same for my custom options?
Of course accessing the option via form.vars... is no problem. However, I wonder if this is the correct solution since the build-in types are accessible directly. Are these just shortcuts (how are they added?) to the form.vars... or is this some other configuration?

Symfony 3 - Serve image within twig extension

I want to serve several images which are not avaible in public folder (web) using php for example path/to/myphp/script.php?image=imagereference&some=parameter
To improve performances and not using this approach I made a twig extension to do that.
<?php
#src/MyBundle/Service/DisplayImage.php
namespace MyBundle\Service;
#https://symfony.com/blog/new-in-symfony-2-4-the-request-stack
use Symfony\Component\HttpFoundation\RequestStack;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\Response;
class DisplayImage
{
private $entityManagerInterface;
private $requestStack;
public function __construct(EntityManagerInterface $entityManagerInterface, RequestStack $requestStack)
{
$this->entityManagerInterface = $entityManagerInterface;
$this->requestStack = $requestStack;
}
public function show(int $ref)
{
$photoPath = __DIR__ ."/../photoFolder/".$ref.".jpg";
$file = file_get_contents($photoPath);
$response = new Response();
$response->headers->set('Content-Type', 'image/jpeg');
$response->setContent($file);
return $response;
}
}
And into my twig template
{# src/MyBundle/Ressources/views/DisplayImage.html.twig #}
{% for ref in refs %}
<img src="{{ show(ref) }}"/>
{% endfor %}
But it doesn't work because the response returned is not a valid src path.
The only way I found is to base 64 encode the response returned
<?php
return "data:image/jpeg;base64," . base64_encode($file);
So my question is how generate URL that target my twig extension?
Something like path/to/twigExtension.php?ref=ref calls show(ref)
Maybe it's not the good way to achieve that.
This is a two step process.
you need to create to a valid link to each image (which will be a route to some kind of ImageController::show(id) controller-action)
The ImageController that takes the id (or imagename) and shouts out the binary content of the image file (or throws an error if a user is not granted to download the image). You can return a BinaryFileResponse here. Take a look here.

PHP Laravel How to get original pdf file name and make it downloadable

I want to make a page in my laravel-application, where it should be possible to download a bunch of PDF-files. I've created a Model and a Controller, and within my Nova backend, I have uploaded some pdf-files.
My Nova fields:
public function fields(Request $request) {
return [
Text::make('File name', 'file_name')
->rules('required'),
File::make('Download', 'file')
->disk('public')
->path('materials')
->storeOriginalName('file_original_name')
->storeSize('file_size')
->prunable(),
];
}
Then my model:
class Material extends Model {
protected $fillable = [
'file_name', 'file', 'file_original_name', 'file_size'
];
}
and my Controller:
use App\Material;
use Illuminate\Http\Request;
class MaterialController extends Controller {
public function files()
{
$files = Material::get();
return view('app.materials', compact('files'));
}
}
In my web.php, I do this:
Route::get('materials', 'MaterialController#files')->name('materials');
In my blade view:
#foreach ($files as $file)
<a href="{{ asset('storage/'. $file->file) }}" download>{{ $file->file_name }}</a>
#endforeach
So far this works, BUT when the orginal filename for example is 'myfile.pdf', $file->file returns something like 'dadjafmdahdyda2e23as.pdf', but I want the original name for the download.
How can I achieve that?
The download property according to MDN can be used in two ways:
Without a value, in which case the filename is determined by :
The Content-Disposition HTTP header
The final segment in the URL path
The media type (from the Content-Type header, the start of a data: URL, or Blob.type for a blob: URL)
With a value: In that case the value is used as a filename. \ and / are converted to underscores to prevent the generation of illegal filenames.
Your case is use case (2) so you can do:
#foreach ($files as $file)
{{ $file->file_name }}
#endforeach
Do read the documentation for any caveats (e.g. this doesn't work cross-origin).

How to check if a certain file already exists in symfony2?

I am working on symfony2 and currently I want to check if a file does exist. My scenario look something like this,, I have two files excel file and the docx file. If a person have an excel file for her/his transaction then it is automatically that the docx file is not applicable for her or him.And vice versa. How can I possibly do it in symfony2? A lot in the net but I don't know how to do it in my case,, thanks a lot :)
UPDATE
Controller:
public function documentType ($doc_type) {
$em = $this->getDoctrine()->getEntityManager();
$result = $em->getRepository('SupplierBundle:SupplierTransactionDetails')->findDocumentType('xlsx');
$result1 = $em->getRepository('SupplierBundle:SupplierTransactionDetails')->findDocumentType('docx');
// statement that will know if the file exists for that certain user if so the other document type will be not applicable for that user. Example: that user have docx file already then the xlsx will be N/A and vice versa
}
Repository :
public function findDocumentType ($doc_type) {
$em = $this->getEntityManager();
$query = $em->createQuery(
'SELECT a, b, c FROM SupplierBundle:SupplierTransaction Details a
JOIN a.supplierTransaction b
JOIN b.supplierDocType c
WHERE c.docType LIKE :doc_type'
)->setParameter('doc_type', $doc_type);
return $query->getResult();
}
You can just use plain PHP for this. For example:
$xls = 'sheet.xlsx';
$doc = 'document.docx';
if (file_exists($xls)) {
// User has an XLSX file
echo 'Download your sheet here.';
} elseif (file_exists($doc)) {
// User has a DOCX file
echo 'Download your document here.';
}
If you want to do it the Symfony2 way, you can use the Filesystem class, it has an exists() function. In a controller an instance is automatically available in the service container:
$em = $this->getDoctrine()->getManager();
$xlsx = $em->getRepository('SupplierBundle:SupplierTransactionDetail')->findDocumentType‌('xlsx');
$docx = $em->getRepository('SupplierBundle:SupplierTransactionDetail')->findDocumnetType‌('docx');
return [
'xlsx' => $xlsx instanceof SupplierTransactionDetail && $this->get('filesystem')->exists($xlsx->getFile()) ? $xlsx->getFile() : null,
'docx' => $docx instanceof SupplierTransactionDetail && $this->get('filesystem')->exists($docx->getFile()) ? $docx->getFile() : null,
];
In your twig template:
{% if xlsx is not empty %}
{{ xlsx }}
{% endif %}
{% if docx is not empty %}
{{ docx }}
{% endif %}

Routing to embedded Modules/Bundles/Controllers in Symfony 2

I fully edited this post after doing research:
I'd like to realize a sidebar in the admin section which is integrated in every page, f.e. http://example.com/admin/index/:
class MyController extends Controller {
protected $modules = array();
public function __construct(){
$this->modules[] = "ModuleController:mainAction";
$this->modules[] = "OtherModuleController:mainAction";
}
public function indexAction(Request $request){
// do stuff here
return $this->render("MyBundle:My:index.html.twig",$data);
}
}
In the view should happen something like:
{% block modules %}
{% for module in modules %}
{% render module %}
{% endfor %}
{% endblock %}
So far so good, but these modules can contain forms which send post requests. I'd like to stay on the same page (http://example.com/admin/index/), so the action attribute of the form stays empty. The problem is: The post request will never be recognized by the Modules. So one idea was to hide a field in the according form that contains the name of the route, transform it to the according uri and send a sub request (in MyController):
public function indexAction(Request $request){
if($request->request->has('hidden_module_route')){
// collect all parameters via $request->request->keys()
$uri = $router->generate($request->request->get('hidden_module_route'), $parameters);
// 1: resolve the uri to the according controller and replace the target in the $this->modules array
// or 2: (after step 1)
$req = $request->create($uri, 'POST');
$subresponse = $this->get('kernel')->handle($req,HttpKernelInterface::SUB_REQUEST);
// inject the response into the modules and handle it in the view
}
[...]
}
That would work for me, but I'm not happy to have these responsibilities in the controller and it feels like there should be a better solution (one Idea is to register a kernel.controller listener that handles sub requests and injects the paths to the controller (which perhaps is marked via interface...)).
What do you think?
You could try to send the main request to your modules, so that they can bind the form with it.
{% block modules %}
{% for module in modules %}
{% render module with {'mainRequest': app.request} %}
{% endfor %}
{% endblock %}
And the module:
public function moduleAction(Request $request, Request $mainRequest)
{
$form = ...;
if ($mainRequest->isMethod('POST')) {
$form->bindRequest($mainRequest);
if ($form->isValid()) {
// You can have a beer, that worked
}
}
}

Categories