Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save benjaminrau/7010ad3becd6a5d86339d1926b518e61 to your computer and use it in GitHub Desktop.
Save benjaminrau/7010ad3becd6a5d86339d1926b518e61 to your computer and use it in GitHub Desktop.
File Upload (JSON) and store with Sonata Media Bundle (based on ApiPlatform 2.0, Symfony 3.1)
<?php
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Kernel;
class AppKernel extends Kernel
{
public function registerBundles()
{
$bundles = [
# ....
new Sonata\MediaBundle\SonataMediaBundle(),
new Emma\MediaBundle\MediaBundle(),
# ....
];
# ....
}
# ...
}
doctrine:
dbal:
types:
json: Sonata\Doctrine\Types\JsonType
sonata_media:
class:
media: Emma\MediaBundle\Entity\MediaElement
db_driver: doctrine_orm
default_context: default
contexts:
default:
providers:
- sonata.media.provider.dailymotion
- sonata.media.provider.youtube
- sonata.media.provider.image
- sonata.media.provider.file
- sonata.media.provider.vimeo
formats:
small: { width: 100 , quality: 70}
big: { width: 500 , quality: 70}
cdn:
server:
path: /uploads/media
filesystem:
local:
directory: "%kernel.root_dir%/../web/uploads/media"
create: false
media_action:
resource: '@MediaBundle/Action/'
type: 'annotation'
parameters:
services:
listener.view.serialize:
class: Emma\MediaBundle\EventListener\SerializeListener
arguments:
- '@api_platform.serializer'
- '@api_platform.serializer.context_builder'
- '@service_container'
tags:
- { name: 'kernel.event_listener', event: 'kernel.view', priority: 17 }
<?php
namespace Emma\MediaBundle\EventListener;
use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
use Emma\MediaBundle\Entity\MediaElement;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\VarDumper\VarDumper;
final class SerializeListener
{
private $serializer;
private $serializerContextBuilder;
private $container;
public function __construct(SerializerInterface $serializer, SerializerContextBuilderInterface $serializerContextBuilder, Container $container)
{
$this->serializer = $serializer;
$this->serializerContextBuilder = $serializerContextBuilder;
$this->container = $container;
}
/**
* Serializes the data to the requested format.
*
* @param GetResponseForControllerResultEvent $event
*/
public function onKernelView(GetResponseForControllerResultEvent $event)
{
$controllerResult = $event->getControllerResult();
$request = $event->getRequest();
if (!$controllerResult instanceof MediaElement) {
return;
}
$provider = $this->container->get($controllerResult->getProviderName());
$controllerResult->setPublicUrl($event->getRequest()->getSchemeAndHttpHost() . $provider->generatePublicUrl($controllerResult, 'default_large'));
}
}
POST /api/media_elements HTTP/1.1
Host: emma-api.devloc.site
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJleHAiOjE0NzYzNTgwMjAsInVzZXJuYW1lIjoiZHJ3aG9AZW1tYS5sb2MiLCJpYXQiOiIxNDc2MjcxNjIwIn0.X2ZVrJdsbzDAYUucFzXQE-AKfnV5yA1QHaFhUT41MVWvkaIDA5VxkDVrqeGioitmnVRiOwT-SXfKP8Smqusoh3_-xUrk1M3Q1wz2QKktWlZwQqJ4CK7c5cCqWg9Hy5UaXXdlFHq_6sTVh8VjGt6Q-FPE4Hp8PGfmTwm6R5oZ-xYUJ23lCmVNNOB-C6R6nRgWwe2FO4D2Lbz6Wx9RV1HOQQCkppdf5IzFW95g-vGSNNFQDOyVB7ytJmtBpJSr5wnAaHxiSHMxutad7JqjYHARejggKYtGmiEcF90xIGEvNzEkuxeNGOOH-reZVDXwOAv1V4JpdN-1pgVxFy2fvQ2xSCN4v18_AlvJmRuof3W60qx4BZ6nTtK_CQSSLltzbZ-4yYpwLl4spNt13yapPOS8wQSO1vHf5R2ugq2k9tUODoqQFK-pXZWT9f6ys6BxD4U4-nWjsNVQmiWZae_6bScMzU7yPFzPaPZHVIneA-htBRqVQ4XkeKeQRKlpNlw3xiA-_p72qvttVaTJsgMzdY2zchKEl_e1KA2pdiPIWn5Mg-yV_v2dS7Z9Hh_xIDgr8AtBrGiI-YEkdmNwcZWqlzHAw3oBVKuPUoYMle5p0BZAgWvGYxiOdKMDF65ypRkdop6Xr6iaVErterzp1mWJZVE5uHv2_xJl1PdiGHbCaYfWKZU
Content-Type: application/json
Cache-Control: no-cache
{
"fileName": "testbild-83.png",
"data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABaQAAASMCAYAAA..."
}
{
"@context": "/api/contexts/MediaElement",
"@id": "/api/media_elements/d23f6372-909f-11e6-b60a-ca5a65ec716d",
"@type": "MediaElement",
"publicUrl": "https://emma-api.devloc.site/uploads/media/default/0001/01/thumb_d23f6372-909f-11e6-b60a-ca5a65ec716d_default_large.png"
}
<?php
namespace Emma\MediaBundle\Action;
use Doctrine\Common\Persistence\ManagerRegistry;
use Emma\MediaBundle\Entity\MediaElement;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sonata\MediaBundle\Entity\MediaManager;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\Serializer;
use Emma\MediaBundle\Dto as Dto;
class UploadAction
{
/**
* @var Serializer
*/
private $serializer;
/**
* @var MediaManager
*/
private $mediaManager;
/**
* @var Router
*/
private $router;
public function __construct(Serializer $serializer, MediaManager $mediaManager, Router $router) {
$this->serializer = $serializer;
$this->mediaManager = $mediaManager;
$this->router = $router;
}
/**
* @param Request $request
* @return Response
*
* @Route(
* name="api_media_elements_post_collection",
* path="/api/media_elements",
* )
* @Method("POST")
*/
public function __invoke(Request $request)
{
if ($request->getContentType() !== 'json')
{
return null;
}
/** @var Dto\MediaElement $mediaElementDto */
$mediaElementDto = $this->serializer->deserialize($request->getContent(), Dto\MediaElement::class, $request->getContentType());
if (MediaElement::isSupportedMimeType($mediaElementDto->getMimeType()) && $uploadedFile = $this->createTempFile($mediaElementDto)) {
$mediaElement = new MediaElement();
$mediaElement->setBinaryContent($uploadedFile);
$mediaElement->setContext('default');
$mediaElement->setProviderName($mediaElement->getProviderForMimeType($mediaElementDto->getMimeType()));
$this->mediaManager->save($mediaElement);
return new RedirectResponse($this->router->generate('api_media_elements_get_item', array('id' => $mediaElement->getId())));
}
return new Response('', Response::HTTP_BAD_REQUEST);
}
/**
* @param Dto\MediaElement $mediaElementDto
* @return UploadedFile
*/
private function createTempFile(Dto\MediaElement $mediaElementDto) {
if (!$binaryContent = $mediaElementDto->getBinaryContent())
{
return false;
}
$temporaryFileName = tempnam(sys_get_temp_dir(), 'upload_action_');
file_put_contents($temporaryFileName, $binaryContent);
return new UploadedFile(
$temporaryFileName,
$mediaElementDto->getFileName()
);
}
}
<?php
namespace Emma\MediaBundle\Dto;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\VarDumper\VarDumper;
class MediaElement
{
/**
* @var string
* @Assert\NotNull
*/
private $fileName;
/**
* @var string
* @Assert\NotNull
*/
private $data;
/**
* @return string
*/
public function getData() {
return $this->data;
}
/**
* @param string $data
*/
public function setData($data) {
$this->data = $data;
}
/**
* @return string
*/
public function getFileName() {
return $this->fileName;
}
/**
* @param string $fileName
*/
public function setFileName($fileName) {
$this->fileName = $fileName;
}
public function getMimeType() {
$attributes = $this->extractAttributes();
return $attributes['mimeType'];
}
public function getBinaryContent() {
$attributes = $this->extractAttributes();
return $attributes['binaryContent'];
}
public function getBase64Content() {
$attributes = $this->extractAttributes();
return $attributes['base64Content'];
}
/**
* @return array
*/
private function extractAttributes() {
$attributes = array(
'base64Content' => '',
'binaryContent' => '',
'mimeType' => '',
'fileExtension' => '',
);
if (!$this->getData())
{
return $attributes;
}
list($mimeType, $data) = explode(';', $this->getData());
list(, $attributes['mimeType']) = explode(':', $mimeType);
list(, $attributes['fileExtension']) = explode('/', $mimeType);
list(, $attributes['base64Content']) = explode(',', $data);
$attributes['binaryContent'] = base64_decode($attributes['base64Content']);
return $attributes;
}
}
<?php
namespace Emma\MediaBundle\Entity;
use Doctrine\ORM\Mapping AS ORM;
use Sonata\MediaBundle\Entity\BaseMedia;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation\Groups;
use ApiPlatform\Core\Annotation\ApiResource;
/**
* @ApiResource(
* itemOperations={
* "get"={"method"="GET"}
* },
* collectionOperations={
* "get"={"method"="GET"}
* }
* )
*
* @ORM\Entity
* @ORM\Table(name="MediaElement")
*/
class MediaElement extends BaseMedia
{
const PROVIDER_IMAGE = "sonata.media.provider.image";
const PROVIDER_FILE = "sonata.media.provider.file";
public static $MIMETYPE_TO_PROVIDER = array(
'image/png' => self::PROVIDER_IMAGE,
'image/gif' => self::PROVIDER_IMAGE,
'image/jpg' => self::PROVIDER_IMAGE,
'image/jpeg' => self::PROVIDER_IMAGE,
'image/bmp' => self::PROVIDER_IMAGE,
'application/pdf' => self::PROVIDER_FILE,
);
/**
* @ORM\Id
* @ORM\Column(type="guid")
* @ORM\GeneratedValue(strategy="UUID")
*/
private $id;
/**
* @var string
* @Groups({"api_mediaelement_get_item"})
*/
protected $publicUrl;
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
/**
* @return string
*/
public function getPublicUrl() {
return $this->publicUrl;
}
/**
* @param string $publicUrl
*/
public function setPublicUrl($publicUrl) {
$this->publicUrl = $publicUrl;
}
public static function isSupportedMimeType($mimeType) {
return isset(self::$MIMETYPE_TO_PROVIDER[$mimeType]);
}
public static function getProviderForMimeType($mimeType) {
return isset(self::$MIMETYPE_TO_PROVIDER[$mimeType]) ? self::$MIMETYPE_TO_PROVIDER[$mimeType] : null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment