| @@ -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 | |||
| @@ -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.*" | |||
| } | |||
| }, | |||
| @@ -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", | |||
| @@ -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], | |||
| ]; | |||
| @@ -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 | |||
| @@ -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 } | |||
| @@ -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'); | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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] : []; | |||
| } | |||
| } | |||
| @@ -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": { | |||