partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

ImageController.php (5932B)


      1 <?php
      2 
      3 namespace PartKeepr\ImageBundle\Controller;
      4 
      5 use Doctrine\ORM\EntityManager;
      6 use Gaufrette\Exception\FileNotFound;
      7 use Imagine\Gd\Imagine;
      8 use Imagine\Image\Box;
      9 use Nelmio\ApiDocBundle\Annotation\ApiDoc;
     10 use PartKeepr\ImageBundle\Entity\CachedImage;
     11 use PartKeepr\ImageBundle\Entity\Image as PartKeeprImage;
     12 use PartKeepr\ImageBundle\Response\ImageResponse;
     13 use PartKeepr\UploadedFileBundle\Controller\FileController;
     14 use PartKeepr\UploadedFileBundle\Entity\UploadedFile;
     15 use Symfony\Component\HttpFoundation\Request;
     16 use Symfony\Component\HttpFoundation\Response;
     17 
     18 abstract class ImageController extends FileController
     19 {
     20     /**
     21      * @ApiDoc(
     22      *  description="Returns a scaled and cached image. Note that the binary data is directly returned.",
     23      *  parameters={
     24      *      {"name"="maxWidth", "dataType"="integer", "required"=false, "description"="The width in pixels"},
     25      *      {"name"="maxHeight", "dataType"="integer", "required"=false, "description"="The height in pixels"}
     26      *  }
     27      * )
     28      *
     29      * @param Request $request
     30      * @param         $id
     31      *
     32      * @return ImageResponse|Response
     33      */
     34     public function getImageAction(Request $request, $id)
     35     {
     36         /**
     37          * @var EntityManager
     38          */
     39         $em = $this->getDoctrine()->getManager();
     40 
     41         /**
     42          * @var PartKeeprImage
     43          */
     44         $image = $em->find($this->getEntityClass(), $id);
     45 
     46         $width = $request->get('maxWidth');
     47         $height = $request->get('maxHeight');
     48 
     49         if ($width === null) {
     50             $width = 200;
     51         }
     52 
     53         if ($height === null) {
     54             $height = 200;
     55         }
     56 
     57         if ($image === null) {
     58             return new ImageResponse($width, $height, 404, '404 not found');
     59         }
     60 
     61         try {
     62             $file = $this->fitWithin($image, $width, $height);
     63         } catch (FileNotFound $e) {
     64             $this->get('logger')->error($e->getMessage());
     65 
     66             return new ImageResponse($width, $height, 404, '404 not found');
     67         } catch (\Exception $e) {
     68             $this->get('logger')->error($e->getMessage());
     69 
     70             return new ImageResponse($width, $height, 500, '500 Server Error');
     71         }
     72 
     73         return new Response(file_get_contents($file), 200, ['Content-Type' => 'image/png']);
     74     }
     75 
     76     /**
     77      * Returns the path to the image cache directory.
     78      *
     79      * @return string
     80      */
     81     public function getImageCacheDirectory()
     82     {
     83         return $this->container->getParameter('partkeepr.image_cache_directory');
     84     }
     85 
     86     /**
     87      * Ensures that the image cache directory exists.
     88      *
     89      * @todo Implement checks if the cache directory has actually been created
     90      * @todo 0777 might not be the best solution
     91      */
     92     public function ensureCacheDirExists()
     93     {
     94         if (!is_dir($this->getImageCacheDirectory())) {
     95             mkdir($this->getImageCacheDirectory(), 0777, true);
     96         }
     97     }
     98 
     99     /**
    100      * Scales the image to fit within the given size.
    101      *
    102      * @param UploadedFile $image   The image to scale
    103      * @param int          $width   The width
    104      * @param int          $height  The height
    105      * @param bool         $padding If true, pad the output image to the given size (transparent background).
    106      *
    107      * @return string The path to the scaled file
    108      */
    109     public function fitWithin(UploadedFile $image, $width, $height, $padding = false)
    110     {
    111         $this->ensureCacheDirExists();
    112 
    113         if ($padding) {
    114             $mode = 'fwp';
    115         } else {
    116             $mode = 'fw';
    117         }
    118 
    119         $outputFile = $this->getImageCacheFilename($image, $width, $height, $mode);
    120 
    121         if ($this->hasCacheFile($image, $width, $height, $mode) && file_exists($outputFile)) {
    122             return $outputFile;
    123         }
    124 
    125         $imagine = new Imagine();
    126 
    127         $localCacheFile = $this->getImageCacheDirectory().$image->getFullFilename();
    128         $storage = $this->get('partkeepr_uploadedfile_service')->getStorage($image);
    129 
    130         file_put_contents($localCacheFile, $storage->read($image->getFullFilename()));
    131 
    132         $imagine->open($localCacheFile)
    133             ->thumbnail(new Box($width, $height))
    134             ->save($outputFile);
    135 
    136         $cachedImage = new CachedImage($image, $outputFile);
    137         $this->getDoctrine()->getManager()->persist($cachedImage);
    138 
    139         return $outputFile;
    140     }
    141 
    142     /**
    143      * Returns the path to an image which has been cached in a particular width, height and mode.
    144      *
    145      * @param UploadedFile $image  The image
    146      * @param int          $width  The width
    147      * @param int          $height The height
    148      * @param string       $mode   The mode
    149      *
    150      * @return string
    151      */
    152     public function getImageCacheFilename(UploadedFile $image, $width, $height, $mode)
    153     {
    154         $outputFile = $this->getImageCacheDirectory();
    155         $outputFile .= '/'.sha1($image->getFilename());
    156         $outputFile .= $width.'x'.$height.'_'.$mode.'.png';
    157 
    158         return $outputFile;
    159     }
    160 
    161     /**
    162      * Checks if the database contains the cache file.
    163      *
    164      * @param UploadedFile $image
    165      * @param              $width
    166      * @param              $height
    167      * @param              $mode
    168      *
    169      * @return bool
    170      */
    171     protected function hasCacheFile(UploadedFile $image, $width, $height, $mode)
    172     {
    173         $cacheFilename = $this->getImageCacheFilename($image, $width, $height, $mode);
    174 
    175         /**
    176          * @var EntityManager
    177          */
    178         $em = $this->getDoctrine()->getManager();
    179 
    180         $queryBuilder = $em->createQueryBuilder();
    181         $queryBuilder->select('COUNT(c)')
    182             ->from('PartKeepr\ImageBundle\Entity\CachedImage', 'c')
    183             ->where('c.cacheFile = :file')
    184             ->setParameter('file', $cacheFilename);
    185 
    186         if ($queryBuilder->getQuery()->getSingleScalarResult() > 0) {
    187             return true;
    188         } else {
    189             return false;
    190         }
    191     }
    192 }