betamfd/file-handler-bundle

Handle files from symfony

Installs: 187

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Forks: 1

Type:symfony-bundle

v2.11.0 2023-05-23 20:45 UTC

README

This is a simple file handler I've built to use across several of my Symfony projects. It takes a handled form and creates a File entity, filling it, and saves your file to the drive in a customizable location.

This was primarily written for private uploads - images and documents that need to be behind a login. As of version 2.0.0, it now allows for a public path to be set so that uploads can be set to a public location like /web/ or /public/ depending on your setup. The change does require a database update and a change to the configuration variables. File uploads will default to the private location.

Composer Install

composer require betamfd/file-handler-bundle

Enable the Bundle

Enable the bundle by adding it to the list of registered bundles in the app/AppKernel.php file of your project:

    new BetaMFD\FileHandlerBundle\BetaMFDFileHandlerBundle(),

Or if you're using a newer version of Symfony, enable it in the config/bundles.php file of your project:

    BetaMFD\FileHandlerBundle\BetaMFDFileHandlerBundle::class => ['all' => true],

Add Entities

Create a File Entity and extend it from the model. Create an ID field. It doesn't have to be a generated value but if it's not, you may want to write your own setter with any custom logic. A basic setter is in the model.

<?php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Table(name="file")
 * @ORM\Entity(repositoryClass="FileRepository")
 */
class File extends \BetaMFD\FileHandlerBundle\Model\File
{
    /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\Column(name="id", type="integer", nullable=false)
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    protected $id;
}

    //any other fields or logic you want

}

<?php

namespace App\Entity;

class FileRepository extends \BetaMFD\FileHandlerBundle\Model\FileRepository
{
  // any custom logic you want
}

You can use whatever you want for a user entity. At this time the only requirement is that there is a function getName() which returns a string, preferably the user's name for logging purposes.

Implement the user interface to ensure compatibility with required functions.

<?php
// src/App/Entity/User.php

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="user")
 */
class User
implements \BetaMFD\FileHandlerBundle\Model\UserInterface
{
    // ...

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    // ...

}

You must tell the code where the User entity is

# app/config/config.yml

doctrine:
    orm:
        resolve_target_entities:
            # Set this to your User Entity
            BetaMFD\FileHandlerBundle\Model\UserInterface: App\Entity\User

Custom Settings

There are a few settings you should review and update. Depending on your version of symfony this could be in config.yml or config/packages/beta_mfd_file_handler.yaml

beta_mfd_file_handler:
  private_upload_location: '%kernel.project_dir%/var/uploads/'
  public_upload_location: '%kernel.project_dir%/web/uploads/'
  file_entity: 'App\Entity\File'

Using the File Handler Service

In your controller, inject \BetaMFD\FileHandlerBundle\Service\FileHandler

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController as Controller;

class SomeController extends Controller
{
    private $fileService;

    public function __construct(
        \BetaMFD\FileHandlerBundle\Service\FileHandler $fileService
    ) {
        $this->fileService = $fileService;
    }

    public function useFormAction(Request $request)
    {
        //Make sure to use your own upload file form!
        $form = $this->createForm(UploadFileType::class);
        $form->handleRequest($request);
        if ($form->isSubmitted() and $form->isValid()) {
            $service = $this->fileService;
            $service->allowAll(); //allow all allowed filetypes
            //set the file, check the filename and extension
            $service->handleForm($form);
            //OPTIONAL: rename file
            $new_name = 'YourPrefix_' . $service->getUnspacedFileName();
            //use isExtensionOkay() or testFileType()
            //The file type was tested in handleForm() and isExtensionOkay()
            // is just returning the boolean flag set in handleForm()
            if ($service->isExtensionOkay() and $service->testName($new_name)) {
                //file a-okay!
                $file = $service->newFile('rga', $new_name);
                if ($file) {
                    // your custom logic
                    // like attach file entity to another entity or whatever here
                    $em = $this->getDoctrine()->getManager();
                    $em->flush();
                    //return whatever you need here
                    $this->addFlash('success', 'File added!');
                    return $this->redirectToRoute('some_route');
                } else {
                    foreach ($service->getErrors() as $e) {
                        $this->addFlash('error', $e);
                    }
                    return $this->redirectToRoute('some_route');
                }
            } else {
                //there were errors
                //add flash errors and stop trying to upload.
                foreach ($service->getErrors() as $e) {
                    $this->addFlash('error', $e);
                }
                //return something here or don't and just load the page
            }
        }
        $return['files_form'] = $form->createView();
        return $this->render('your_awesome_form_template.html.twig', $return);
    }

    public function straightFileHandlingAction(Request $request)
    {
        $file = $request->files->get('file');
        $service = $this->fileService;
        $service->allowAll(); //allow all allowed filetypes
        $service->setUploadedFile($file);
        //OPTIONAL: rename file
        $new_name = 'YourPrefix_' . $service->getUnspacedFileName();
        if ($service->testFileType() and $service->testName($new_name)) {
            //file a-okay!
            $file = $service->newFile('your_subfolder', $new_name);
            if ($file) {
                // your custom logic
                // like attach file entity to another entity or whatever here
                $em = $this->getDoctrine()->getManager();
                $em->flush();
                //return whatever you need here
                return new Response();
            } else {
                $err = $service->getErrors();
                //exception or flash bag
                throw new \Exception(reset($err));
            }
        } else {
            //there were errors
            //exception or flash bag
            $err = $service->getErrors();
            throw new \Exception(reset($err));
        }
        //return whatever you need to here
    }
}