Ver código fonte

normalization of media object

master
Daniel 2 anos atrás
pai
commit
56df8be376
11 arquivos alterados com 422 adições e 5 exclusões
  1. +4
    -1
      README.md
  2. +3
    -2
      composer.json
  3. +174
    -1
      composer.lock
  4. +1
    -0
      config/bundles.php
  5. +15
    -0
      config/packages/vich_uploader.yaml
  6. +7
    -1
      config/services.yaml
  7. +35
    -0
      migrations/Version20240125102320.php
  8. +33
    -0
      src/Controller/CreateMediaObjectAction.php
  9. +75
    -0
      src/Entity/MediaObject.php
  10. +63
    -0
      src/Serializer/MediaObjectNormalizer.php
  11. +12
    -0
      symfony.lock

+ 4
- 1
README.md Ver arquivo

@@ -106,4 +106,7 @@
- File Uploading:
https://api-platform.com/docs/core/file-upload/
https://github.com/dustin10/VichUploaderBundle/blob/master/docs/index.md
>>>>>>> Stashed changes

# List Routes and Service Tags
- ddev exec bin/console debug:router
- ddev exec bin/console debug:container

+ 3
- 2
composer.json Ver arquivo

@@ -43,7 +43,8 @@
"symfony/yaml": "7.0.*",
"symfonycasts/micro-mapper": "^0.1.4",
"twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0"
"twig/twig": "^2.12|^3.0",
"vich/uploader-bundle": "^2.3"
},
"config": {
"allow-plugins": {
@@ -90,7 +91,7 @@
},
"extra": {
"symfony": {
"allow-contrib": false,
"allow-contrib": true,
"require": "7.0.*"
}
},


+ 174
- 1
composer.lock Ver arquivo

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "90d8363fb071963db3a216753262c590",
"content-hash": "e41f83bf907500bc2cae3d1f8eb56816",
"packages": [
{
"name": "api-platform/core",
@@ -1561,6 +1561,70 @@
],
"time": "2023-10-06T06:47:41+00:00"
},
{
"name": "jms/metadata",
"version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/schmittjoh/metadata.git",
"reference": "7ca240dcac0c655eb15933ee55736ccd2ea0d7a6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/schmittjoh/metadata/zipball/7ca240dcac0c655eb15933ee55736ccd2ea0d7a6",
"reference": "7ca240dcac0c655eb15933ee55736ccd2ea0d7a6",
"shasum": ""
},
"require": {
"php": "^7.2|^8.0"
},
"require-dev": {
"doctrine/cache": "^1.0",
"doctrine/coding-standard": "^8.0",
"mikey179/vfsstream": "^1.6.7",
"phpunit/phpunit": "^8.5|^9.0",
"psr/container": "^1.0|^2.0",
"symfony/cache": "^3.1|^4.0|^5.0",
"symfony/dependency-injection": "^3.1|^4.0|^5.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"Metadata\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Johannes M. Schmitt",
"email": "schmittjoh@gmail.com"
},
{
"name": "Asmir Mustafic",
"email": "goetas@gmail.com"
}
],
"description": "Class/method/property metadata management in PHP",
"keywords": [
"annotations",
"metadata",
"xml",
"yaml"
],
"support": {
"issues": "https://github.com/schmittjoh/metadata/issues",
"source": "https://github.com/schmittjoh/metadata/tree/2.8.0"
},
"time": "2023-02-15T13:44:18+00:00"
},
{
"name": "lcobucci/clock",
"version": "3.2.0",
@@ -7832,6 +7896,115 @@
],
"time": "2023-11-21T18:54:41+00:00"
},
{
"name": "vich/uploader-bundle",
"version": "2.3.0",
"source": {
"type": "git",
"url": "https://github.com/dustin10/VichUploaderBundle.git",
"reference": "0d748cfe676bcf894b3f324f69797c9b9d124aa5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dustin10/VichUploaderBundle/zipball/0d748cfe676bcf894b3f324f69797c9b9d124aa5",
"reference": "0d748cfe676bcf894b3f324f69797c9b9d124aa5",
"shasum": ""
},
"require": {
"doctrine/persistence": "^3",
"ext-simplexml": "*",
"jms/metadata": "^2.4",
"php": "^8.1",
"symfony/config": "^5.4 || ^6.0 || ^7.0",
"symfony/console": "^5.4 || ^6.0 || ^7.0",
"symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0",
"symfony/event-dispatcher-contracts": "^3.1",
"symfony/http-foundation": "^5.4 || ^6.0 || ^7.0",
"symfony/http-kernel": "^5.4 || ^6.0 || ^7.0",
"symfony/mime": "^5.4 || ^6.0 || ^7.0",
"symfony/property-access": "^5.4 || ^6.0 || ^7.0",
"symfony/string": "^5.4 || ^6.0 || ^7.0"
},
"conflict": {
"doctrine/annotations": "<1.12",
"league/flysystem": "<2.0"
},
"require-dev": {
"dg/bypass-finals": "^1.3",
"doctrine/doctrine-bundle": "^2.7",
"doctrine/mongodb-odm": "^2.4",
"doctrine/orm": "^2.13",
"ext-sqlite3": "*",
"knplabs/knp-gaufrette-bundle": "dev-master",
"league/flysystem-bundle": "^2.3",
"league/flysystem-memory": "^2.0",
"matthiasnoback/symfony-dependency-injection-test": "^4.3",
"mikey179/vfsstream": "^1.6.11",
"phpunit/phpunit": "^9.6",
"symfony/asset": "^5.4 || ^6.0",
"symfony/browser-kit": "^5.4 || ^6.0 || ^7.0",
"symfony/css-selector": "^5.4 || ^6.0 || ^7.0",
"symfony/doctrine-bridge": "^5.4 || ^6.0 || ^7.0",
"symfony/dom-crawler": "^5.4 || ^6.0 || ^7.0",
"symfony/form": "^5.4 || ^6.0 || ^7.0",
"symfony/framework-bundle": "^5.4 || ^6.0 || ^7.0",
"symfony/phpunit-bridge": "^7.0",
"symfony/security-csrf": "^5.4 || ^6.0 || ^7.0",
"symfony/translation": "^5.4 || ^6.0 || ^7.0",
"symfony/twig-bridge": "^5.4 || ^6.0 || ^7.0",
"symfony/twig-bundle": "^5.4 || ^6.0 || ^7.0",
"symfony/validator": "^5.4 || ^6.0 || ^7.0",
"symfony/var-dumper": "^5.4 || ^6.0 || ^7.0",
"symfony/yaml": "^5.4 || ^6.0 || ^7.0",
"yoast/phpunit-polyfills": "^2.0"
},
"suggest": {
"doctrine/annotations": "If you use doctrine/doctrine-bundle >2.7, this package is required to use annotations",
"doctrine/doctrine-bundle": "For integration with Doctrine",
"doctrine/mongodb-odm-bundle": "For integration with Doctrine ODM",
"doctrine/orm": "For integration with Doctrine ORM",
"doctrine/phpcr-odm": "For integration with Doctrine PHPCR",
"knplabs/knp-gaufrette-bundle": "For integration with Gaufrette",
"league/flysystem-bundle": "For integration with Flysystem",
"liip/imagine-bundle": "To generate image thumbnails",
"oneup/flysystem-bundle": "For integration with Flysystem",
"symfony/asset": "To generate better links",
"symfony/form": "To handle uploads in forms",
"symfony/yaml": "To use YAML mapping"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"Vich\\UploaderBundle\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Dustin Dobervich",
"email": "ddobervich@gmail.com"
}
],
"description": "Ease file uploads attached to entities",
"homepage": "https://github.com/dustin10/VichUploaderBundle",
"keywords": [
"file uploads",
"upload"
],
"support": {
"issues": "https://github.com/dustin10/VichUploaderBundle/issues",
"source": "https://github.com/dustin10/VichUploaderBundle/tree/2.3.0"
},
"time": "2023-12-18T07:49:22+00:00"
},
{
"name": "webmozart/assert",
"version": "1.11.0",


+ 1
- 0
config/bundles.php Ver arquivo

@@ -17,4 +17,5 @@ return [
Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true],
Symfonycasts\MicroMapper\SymfonycastsMicroMapperBundle::class => ['all' => true],
Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
];

+ 15
- 0
config/packages/vich_uploader.yaml Ver arquivo

@@ -0,0 +1,15 @@
vich_uploader:
db_driver: orm
metadata:
type: attribute
mappings:
media_object:
uri_prefix: /media
upload_destination: '%kernel.project_dir%/public/media'
# Will rename uploaded files using a uniqueid as a prefix.
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
download:
uri_prefix: /download
upload_destination: '%kernel.project_dir%/public/download'
# Will rename uploaded files using a uniqueid as a prefix.
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer

+ 7
- 1
config/services.yaml Ver arquivo

@@ -27,4 +27,10 @@ services:
class: App\EventListener\AuthenticationSuccessListener
tags:
- { name: kernel.event_listener, event: lexik_jwt_authentication.on_authentication_success, method: onAuthenticationSuccessResponse }
arguments: ['@symfonycasts.micro_mapper', '@api_platform.iri_converter']
arguments: ['@symfonycasts.micro_mapper', '@api_platform.iri_converter']

App\Serializer\MediaObjectNormalizer:
arguments:
$storage: '@vich_uploader.storage.file_system'
tags:
- { name: 'api_platform.jsonld.normalizer.item', priority: 1000 }

+ 35
- 0
migrations/Version20240125102320.php Ver arquivo

@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240125102320 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE media_object (id INT AUTO_INCREMENT NOT NULL, file_path VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE api_token DROP FOREIGN KEY FK_7BA2F5EB5E70BCD7');
$this->addSql('DROP TABLE api_token');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE api_token (id INT AUTO_INCREMENT NOT NULL, owned_by_id INT NOT NULL, expires_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', token VARCHAR(68) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, scopes JSON NOT NULL COMMENT \'(DC2Type:json)\', INDEX IDX_7BA2F5EB5E70BCD7 (owned_by_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB COMMENT = \'\' ');
$this->addSql('ALTER TABLE api_token ADD CONSTRAINT FK_7BA2F5EB5E70BCD7 FOREIGN KEY (owned_by_id) REFERENCES user (id)');
$this->addSql('DROP TABLE media_object');
}
}

+ 33
- 0
src/Controller/CreateMediaObjectAction.php Ver arquivo

@@ -0,0 +1,33 @@
<?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 25.01.24
*/


namespace App\Controller;


use App\Entity\MediaObject;
use App\Serializer\MediaObjectNormalizer;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

#[AsController]
final class CreateMediaObjectAction extends AbstractController
{
public function __invoke(Request $request): MediaObject
{
$uploadedFile = $request->files->get('file');
if (!$uploadedFile) {
throw new BadRequestHttpException('"file" is required');
}

$mediaObject = new MediaObject();
$mediaObject->file = $uploadedFile;

return $mediaObject;
}
}

+ 75
- 0
src/Entity/MediaObject.php Ver arquivo

@@ -0,0 +1,75 @@
<?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 25.01.24
*/


namespace App\Entity;

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use ApiPlatform\OpenApi\Model;
use App\Controller\CreateMediaObjectAction;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

#[Vich\Uploadable]
#[ORM\Entity]
#[ApiResource(
types: ['https://schema.org/MediaObject'],
operations: [
new Get(),
new GetCollection(),
new Post(
controller: CreateMediaObjectAction::class,
openapi: new Model\Operation(
requestBody: new Model\RequestBody(
content: new \ArrayObject([
'multipart/form-data' => [
'schema' => [
'type' => 'object',
'properties' => [
'file' => [
'type' => 'string',
'format' => 'binary'
]
]
]
]
])
)
),
validationContext: ['groups' => ['Default', 'media_object_create']],
deserialize: false
)
],
normalizationContext: ['groups' => ['media_object:read']]
)]
class MediaObject
{
#[ORM\Id, ORM\Column, ORM\GeneratedValue]
private ?int $id = null;

#[ApiProperty(types: ['https://schema.org/contentUrl'])]
#[Groups(['media_object:read'])]
public ?string $contentUrl = null;

#[Vich\UploadableField(mapping: 'media_object', fileNameProperty: 'filePath')]
#[Assert\NotNull(groups: ['media_object_create'])]
public ?File $file = null;

#[ORM\Column(nullable: true)]
public ?string $filePath = null;

public function getId(): ?int
{
return $this->id;
}
}

+ 63
- 0
src/Serializer/MediaObjectNormalizer.php Ver arquivo

@@ -0,0 +1,63 @@
<?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 25.01.24
*/


namespace App\Serializer;


use App\Entity\MediaObject;
use Symfony\Component\DependencyInjection\Attribute\AsDecorator;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Vich\UploaderBundle\Storage\StorageInterface;

#[AsDecorator('api_platform.jsonld.normalizer.item')]
final class MediaObjectNormalizer implements NormalizerInterface, SerializerAwareInterface
{
private const ALREADY_CALLED = 'MEDIA_OBJECT_NORMALIZER_ALREADY_CALLED';

public function __construct(
private StorageInterface $storage,
private NormalizerInterface $normalizer
)
{
}

public function normalize($object, ?string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null
{
$context[self::ALREADY_CALLED] = true;

$object->contentUrl = $this->storage->resolveUri($object, 'file');

return $this->normalizer->normalize($object, $format, $context);
}

public function supportsNormalization($data, ?string $format = null, array $context = []): bool
{
if (isset($context[self::ALREADY_CALLED])) {
return false;
}

return $data instanceof MediaObject;
}

public function setSerializer(SerializerInterface $serializer): void
{
if ($this->normalizer instanceof SerializerAwareInterface) {
$this->normalizer->setSerializer($serializer);
}
}

public function getSupportedTypes(?string $format): array
{
if (method_exists($this->normalizer, 'getSupportedTypes')) {
return $this->normalizer->getSupportedTypes($format);
}

return 'jsonld' === $format ? ['*' => true] : [];
}
}

+ 12
- 0
symfony.lock Ver arquivo

@@ -300,6 +300,18 @@
"twig/extra-bundle": {
"version": "v3.8.0"
},
"vich/uploader-bundle": {
"version": "2.3",
"recipe": {
"repo": "github.com/symfony/recipes-contrib",
"branch": "main",
"version": "1.13",
"ref": "1b3064c2f6b255c2bc2f56461aaeb76b11e07e36"
},
"files": [
"config/packages/vich_uploader.yaml"
]
},
"zenstruck/foundry": {
"version": "1.36",
"recipe": {


Carregando…
Cancelar
Salvar