Last active
June 7, 2021 07:53
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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(), | |
# .... | |
]; | |
# .... | |
} | |
# ... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
media_action: | |
resource: '@MediaBundle/Action/' | |
type: 'annotation' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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')); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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..." | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"@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" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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() | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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