Browse Source

implementing image upload with vich/uploader-bundle

master
art.dambrine 4 years ago
parent
commit
a9be58302c
  1. 1
      .gitignore
  2. 3
      composer.json
  3. 163
      composer.lock
  4. 1
      config/bundles.php
  5. 12
      config/packages/vich_uploader.yaml
  6. 31
      migrations/Version20210401194203.php
  7. 31
      migrations/Version20210401194958.php
  8. 31
      migrations/Version20210401200205.php
  9. 31
      migrations/Version20210401200906.php
  10. 31
      migrations/Version20210401202700.php
  11. 31
      migrations/Version20210401202758.php
  12. 15
      src/Controller/PokemonController.php
  13. 78
      src/Entity/Pokemon.php
  14. 9
      src/Form/PokemonType.php
  15. 15
      symfony.lock
  16. 4
      templates/pokemon/show.html.twig

1
.gitignore

@ -1,4 +1,5 @@
.idea/ .idea/
/public/images/pokemons
###> symfony/framework-bundle ### ###> symfony/framework-bundle ###
/.env.local /.env.local
/.env.local.php /.env.local.php

3
composer.json

@ -43,7 +43,8 @@
"symfony/web-link": "5.2.*", "symfony/web-link": "5.2.*",
"symfony/yaml": "5.2.*", "symfony/yaml": "5.2.*",
"twig/extra-bundle": "^2.12|^3.0", "twig/extra-bundle": "^2.12|^3.0",
"twig/twig": "^2.12|^3.0" "twig/twig": "^2.12|^3.0",
"vich/uploader-bundle": "^1.17"
}, },
"require-dev": { "require-dev": {
"symfony/browser-kit": "^5.2", "symfony/browser-kit": "^5.2",

163
composer.lock

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "7f19c1fbf5a162c6ac24cf3f55978592", "content-hash": "4193f9739f8bbbcc296b1562066343b1",
"packages": [ "packages": [
{ {
"name": "api-platform/core", "name": "api-platform/core",
@ -1683,6 +1683,66 @@
], ],
"time": "2021-01-14T21:52:44+00:00" "time": "2021-01-14T21:52:44+00:00"
}, },
{
"name": "jms/metadata",
"version": "2.5.0",
"source": {
"type": "git",
"url": "https://github.com/schmittjoh/metadata.git",
"reference": "b5c52549807b2d855b3d7e36ec164c00eb547338"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/schmittjoh/metadata/zipball/b5c52549807b2d855b3d7e36ec164c00eb547338",
"reference": "b5c52549807b2d855b3d7e36ec164c00eb547338",
"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",
"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"
],
"time": "2021-03-07T19:20:09+00:00"
},
{ {
"name": "knplabs/knp-components", "name": "knplabs/knp-components",
"version": "v3.0.2", "version": "v3.0.2",
@ -7506,6 +7566,107 @@
], ],
"time": "2021-02-08T09:54:36+00:00" "time": "2021-02-08T09:54:36+00:00"
}, },
{
"name": "vich/uploader-bundle",
"version": "1.17.0",
"source": {
"type": "git",
"url": "https://github.com/dustin10/VichUploaderBundle.git",
"reference": "ac1d4d1d73fa89fe4cb1d00205f01dc7144434ca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dustin10/VichUploaderBundle/zipball/ac1d4d1d73fa89fe4cb1d00205f01dc7144434ca",
"reference": "ac1d4d1d73fa89fe4cb1d00205f01dc7144434ca",
"shasum": ""
},
"require": {
"ext-simplexml": "*",
"jms/metadata": "^2.4",
"php": "^7.3 || ^8.0",
"symfony/config": "^4.4 || ^5.0",
"symfony/console": "^4.4 || ^5.0",
"symfony/dependency-injection": "^4.4 || ^5.0",
"symfony/event-dispatcher-contracts": "^1.1 || ^2.0",
"symfony/form": "^4.4 || ^5.0",
"symfony/http-foundation": "^4.4 || ^5.0",
"symfony/http-kernel": "^4.4 || ^5.0",
"symfony/mime": "^4.4 || ^5.0",
"symfony/property-access": "^4.4 || ^5.0",
"symfony/string": "^5.0"
},
"conflict": {
"league/flysystem": "<2.0"
},
"require-dev": {
"alcaeus/mongo-php-adapter": "^1.2",
"doctrine/doctrine-bundle": "^2.2",
"doctrine/mongodb-odm": "^1.2 || ^2.0",
"doctrine/orm": "^2.7",
"ext-sqlite3": "*",
"knplabs/knp-gaufrette-bundle": "^0.7",
"league/flysystem-bundle": "^2.0",
"league/flysystem-memory": "^2.0",
"matthiasnoback/symfony-dependency-injection-test": "^4.1",
"mikey179/vfsstream": "^1.6",
"phpunit/phpunit": "^9.5",
"symfony/asset": "^4.4 || ^5.0",
"symfony/browser-kit": "^4.4 || ^5.0",
"symfony/css-selector": "^4.4 || ^5.0",
"symfony/doctrine-bridge": "^4.4 || ^5.0",
"symfony/dom-crawler": "^4.4 || ^5.0",
"symfony/framework-bundle": "^4.4 || ^5.0",
"symfony/phpunit-bridge": "^5.2",
"symfony/security-csrf": "^4.4 || ^5.0",
"symfony/translation": "^4.4 || ^5.0",
"symfony/twig-bridge": "^4.4 || ^5.0",
"symfony/twig-bundle": "^4.4 || ^5.0",
"symfony/validator": "^4.4 || ^5.0",
"symfony/var-dumper": "^4.4 || ^5.0",
"symfony/yaml": "^4.4 || ^5.0"
},
"suggest": {
"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",
"ocramius/proxy-manager": "To use lazy services",
"oneup/flysystem-bundle": "For integration with Flysystem",
"symfony/asset": "To generate better links",
"symfony/yaml": "To use YAML mapping"
},
"type": "symfony-bundle",
"extra": {
"branch-alias": {
"dev-master": "1.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"
],
"time": "2021-02-26T16:07:21+00:00"
},
{ {
"name": "webmozart/assert", "name": "webmozart/assert",
"version": "1.10.0", "version": "1.10.0",

1
config/bundles.php

@ -15,4 +15,5 @@ return [
Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true], Nelmio\CorsBundle\NelmioCorsBundle::class => ['all' => true],
ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true], ApiPlatform\Core\Bridge\Symfony\Bundle\ApiPlatformBundle::class => ['all' => true],
Knp\Bundle\PaginatorBundle\KnpPaginatorBundle::class => ['all' => true], Knp\Bundle\PaginatorBundle\KnpPaginatorBundle::class => ['all' => true],
Vich\UploaderBundle\VichUploaderBundle::class => ['all' => true],
]; ];

12
config/packages/vich_uploader.yaml

@ -0,0 +1,12 @@
vich_uploader:
db_driver: orm
mappings:
pokemon_image:
uri_prefix: /images/pokemons
upload_destination: '%kernel.project_dir%/public/images/pokemons'
namer: Vich\UploaderBundle\Naming\SmartUniqueNamer
inject_on_load: false
delete_on_update: true
delete_on_remove: true

31
migrations/Version20210401194203.php

@ -0,0 +1,31 @@
<?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 Version20210401194203 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('ALTER TABLE pokemon ADD image_name VARCHAR(255) NOT NULL, ADD image_size INT NOT NULL');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE pokemon DROP image_name, DROP image_size');
}
}

31
migrations/Version20210401194958.php

@ -0,0 +1,31 @@
<?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 Version20210401194958 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('ALTER TABLE pokemon ADD updated_at DATETIME NOT NULL');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE pokemon DROP updated_at');
}
}

31
migrations/Version20210401200205.php

@ -0,0 +1,31 @@
<?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 Version20210401200205 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('ALTER TABLE pokemon DROP image_name, DROP image_size, DROP updated_at');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE pokemon ADD image_name VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`, ADD image_size INT NOT NULL, ADD updated_at DATETIME NOT NULL');
}
}

31
migrations/Version20210401200906.php

@ -0,0 +1,31 @@
<?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 Version20210401200906 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('ALTER TABLE pokemon ADD image_name VARCHAR(255) NOT NULL, ADD image_size INT NOT NULL, ADD updated_at DATETIME NOT NULL');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE pokemon DROP image_name, DROP image_size, DROP updated_at');
}
}

31
migrations/Version20210401202700.php

@ -0,0 +1,31 @@
<?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 Version20210401202700 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('ALTER TABLE pokemon CHANGE image_name image_name VARCHAR(255) DEFAULT NULL');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE pokemon CHANGE image_name image_name VARCHAR(255) CHARACTER SET utf8mb4 NOT NULL COLLATE `utf8mb4_unicode_ci`');
}
}

31
migrations/Version20210401202758.php

@ -0,0 +1,31 @@
<?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 Version20210401202758 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('ALTER TABLE pokemon CHANGE image_size image_size INT DEFAULT NULL');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE pokemon CHANGE image_size image_size INT NOT NULL');
}
}

15
src/Controller/PokemonController.php

@ -10,12 +10,24 @@ use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Annotation\Route;
use Knp\Component\Pager\PaginatorInterface; use Knp\Component\Pager\PaginatorInterface;
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
/** /**
* @Route("/pokemon") * @Route("/pokemon")
*/ */
class PokemonController extends AbstractController class PokemonController extends AbstractController
{ {
/**
* @var UploaderHelper
*/
protected $uploaderHelper;
public function __construct(UploaderHelper $uploaderHelper)
{
$this->uploaderHelper = $uploaderHelper;
}
/** /**
* @Route("/", name="pokemon_index", methods={"GET"}) * @Route("/", name="pokemon_index", methods={"GET"})
*/ */
@ -70,8 +82,11 @@ class PokemonController extends AbstractController
*/ */
public function show(Pokemon $pokemon): Response public function show(Pokemon $pokemon): Response
{ {
$imagePath = $this->uploaderHelper->asset($pokemon, 'imageFile');
return $this->render('pokemon/show.html.twig', [ return $this->render('pokemon/show.html.twig', [
'pokemon' => $pokemon, 'pokemon' => $pokemon,
'imagePath' => $imagePath,
]); ]);
} }

78
src/Entity/Pokemon.php

@ -8,9 +8,12 @@ use ApiPlatform\Core\Annotation\ApiResource;
use Symfony\Component\Serializer\Annotation\Groups; use Symfony\Component\Serializer\Annotation\Groups;
use ApiPlatform\Core\Annotation\ApiFilter; use ApiPlatform\Core\Annotation\ApiFilter;
use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter; use ApiPlatform\Core\Bridge\Doctrine\Orm\Filter\SearchFilter;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
/** /**
* @ORM\Entity(repositoryClass=PokemonRepository::class) * @ORM\Entity(repositoryClass=PokemonRepository::class)
* @Vich\Uploadable
* @ApiResource( * @ApiResource(
* normalizationContext={ * normalizationContext={
* "groups"={"pokemon_read"} * "groups"={"pokemon_read"}
@ -82,6 +85,36 @@ class Pokemon
*/ */
private $numero; private $numero;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* @Vich\UploadableField(mapping="pokemon_image", fileNameProperty="imageName", size="imageSize")
*
* @var File|null
*/
private $imageFile;
/**
* @ORM\Column(type="string",nullable=true)
*
* @var string|null
*/
private $imageName;
/**
* @ORM\Column(type="integer",nullable=true)
*
* @var int|null
*/
private $imageSize;
/**
* @ORM\Column(type="datetime")
*
* @var \DateTimeInterface|null
*/
private $updatedAt;
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
@ -194,4 +227,49 @@ class Pokemon
return $this; return $this;
} }
/**
* If manually uploading a file (i.e. not using Symfony Form) ensure an instance
* of 'UploadedFile' is injected into this setter to trigger the update. If this
* bundle's configuration parameter 'inject_on_load' is set to 'true' this setter
* must be able to accept an instance of 'File' as the bundle will inject one here
* during Doctrine hydration.
*
* @param File|\Symfony\Component\HttpFoundation\File\UploadedFile|null $imageFile
*/
public function setImageFile(?File $imageFile = null): void
{
$this->imageFile = $imageFile;
if (null !== $imageFile) {
// It is required that at least one field changes if you are using doctrine
// otherwise the event listeners won't be called and the file is lost
$this->updatedAt = new \DateTimeImmutable();
}
}
public function getImageFile(): ?File
{
return $this->imageFile;
}
public function setImageName(?string $imageName): void
{
$this->imageName = $imageName;
}
public function getImageName(): ?string
{
return $this->imageName;
}
public function setImageSize(?int $imageSize): void
{
$this->imageSize = $imageSize;
}
public function getImageSize(): ?int
{
return $this->imageSize;
}
} }

9
src/Form/PokemonType.php

@ -10,6 +10,7 @@ use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\OptionsResolver\OptionsResolver;
use Vich\UploaderBundle\Form\Type\VichFileType;
class PokemonType extends AbstractType class PokemonType extends AbstractType
{ {
@ -39,6 +40,14 @@ class PokemonType extends AbstractType
'choice_label' => 'name', 'choice_label' => 'name',
'label' => 'Generation' 'label' => 'Generation'
)) ))
->add('imageFile', VichFileType::class, [
'required' => false,
'allow_delete' => true,
'delete_label' => 'Remove file',
'download_uri' => true,
'download_label' => true,
'asset_helper' => true,
])
; ;
} }

15
symfony.lock

@ -105,6 +105,9 @@
"friendsofphp/proxy-manager-lts": { "friendsofphp/proxy-manager-lts": {
"version": "v1.0.3" "version": "v1.0.3"
}, },
"jms/metadata": {
"version": "2.5.0"
},
"knplabs/knp-components": { "knplabs/knp-components": {
"version": "v3.0.2" "version": "v3.0.2"
}, },
@ -553,6 +556,18 @@
"twig/twig": { "twig/twig": {
"version": "v3.3.0" "version": "v3.3.0"
}, },
"vich/uploader-bundle": {
"version": "1.5",
"recipe": {
"repo": "github.com/symfony/recipes-contrib",
"branch": "master",
"version": "1.5",
"ref": "c4f5755b37fb65b9c6a3cbdae91205c15a137ed4"
},
"files": [
"config/packages/vich_uploader.yaml"
]
},
"webmozart/assert": { "webmozart/assert": {
"version": "1.10.0" "version": "1.10.0"
}, },

4
templates/pokemon/show.html.twig

@ -5,6 +5,10 @@
{% block body %} {% block body %}
<h1>Pokemon</h1> <h1>Pokemon</h1>
{% if imagePath %}
<img src={{ imagePath }} alt="pokemon-img" height="100px">
{% endif %}
<table class="table"> <table class="table">
<tbody> <tbody>

Loading…
Cancel
Save