Skip to content

Commit

Permalink
minor #16269 Bump API Platform to 3.3 and refactor uploading avatar i…
Browse files Browse the repository at this point in the history
…mages (GSadee)

This PR was merged into the api-platform-3 branch.

Discussion
----------

| Q               | A
|-----------------|-----
| Branch?         | api-platform-3
| Bug fix?        | yes
| New feature?    | no
| BC breaks?      | no
| Deprecations?   | no<!-- don't forget to update the UPGRADE-*.md file -->
| Related tickets | 
| License         | MIT

<!--
 - Bug fixes must be submitted against the 1.12 or 1.13 branches
 - Features and deprecations must be submitted against the 1.14 branch
 - Features, removing deprecations and BC breaks must be submitted against the 2.0 branch
 - Make sure that the correct base branch is set

 To be sure you are not breaking any Backward Compatibilities, check the documentation:
 https://docs.sylius.com/en/latest/book/organization/backward-compatibility-promise.html
-->


Commits
-------
  Bump API Platform to 3.3
  [API] Implement state processor for uploading avatar images instead of controller
  [API] Remove the old avatar image before creating a new one
  [API] Make type optional in ImageCreatorInterface
  [Core] Add spec for setting null as image in admin user
  • Loading branch information
NoResponseMate committed May 17, 2024
2 parents bf43d8d + a97dca2 commit 8f8c08f
Show file tree
Hide file tree
Showing 14 changed files with 282 additions and 40 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"ext-intl": "*",
"ext-json": "*",
"ext-simplexml": "*",
"api-platform/core": "~3.2.2",
"api-platform/core": "^3.3",
"babdev/pagerfanta-bundle": "^3.0",
"behat/transliterator": "^1.3",
"doctrine/collections": "^1.6",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,55 +11,49 @@

declare(strict_types=1);

namespace Sylius\Bundle\ApiBundle\Controller;
namespace Sylius\Bundle\ApiBundle\Creator;

use Sylius\Bundle\ApiBundle\Exception\AdminUserNotFoundException;
use Sylius\Bundle\ApiBundle\Exception\NoFileUploadedException;
use Sylius\Component\Core\Model\AdminUserInterface;
use Sylius\Component\Core\Model\AvatarImageInterface;
use Sylius\Component\Core\Model\ImageInterface;
use Sylius\Component\Core\Repository\AvatarImageRepositoryInterface;
use Sylius\Component\Core\Uploader\ImageUploaderInterface;
use Sylius\Component\Resource\Factory\FactoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\HttpFoundation\Request;

final readonly class UploadAvatarImageAction
final class AvatarImageCreator implements ImageCreatorInterface
{
/**
* @param FactoryInterface<AvatarImageInterface> $avatarImageFactory
* @param RepositoryInterface<AdminUserInterface> $adminUserRepository
*/
public function __construct(
private FactoryInterface $avatarImageFactory,
private AvatarImageRepositoryInterface $avatarImageRepository,
private RepositoryInterface $adminUserRepository,
private ImageUploaderInterface $imageUploader,
) {
}

public function __invoke(Request $request): ImageInterface
/** @param array<mixed> $context */
public function create(string $ownerIdentifier, ?\SplFileInfo $file, ?string $type = null, array $context = []): ImageInterface
{
/** @var AdminUserInterface $owner */
$owner = $this->adminUserRepository->find($request->attributes->getString('id'));
if (null === $owner) {
throw new AdminUserNotFoundException();
}

/** @var UploadedFile $file */
$file = $request->files->get('file');
if (null === $file) {
throw new NoFileUploadedException();
}

/** @var ImageInterface $image */
$image = $this->avatarImageFactory->createNew();
$image->setFile($file);

$oldImage = $owner->getImage();
if ($oldImage !== null) {
$this->avatarImageRepository->remove($oldImage);
$owner = $this->adminUserRepository->find($ownerIdentifier);
if (null === $owner) {
throw new AdminUserNotFoundException();
}
$owner->setImage($image);

$this->imageUploader->upload($image);
$avatarImage = $this->avatarImageFactory->createNew();
$avatarImage->setFile($file);

$owner->setImage($avatarImage);

$this->imageUploader->upload($avatarImage);

return $image;
return $avatarImage;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,10 @@
interface ImageCreatorInterface
{
/** @param array<mixed> $context */
public function create(string $ownerCode, ?\SplFileInfo $file, ?string $type, array $context = []): ImageInterface;
public function create(
string $ownerIdentifier,
?\SplFileInfo $file,
?string $type = null,
array $context = [],
): ImageInterface;
}
4 changes: 2 additions & 2 deletions src/Sylius/Bundle/ApiBundle/Creator/ProductImageCreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,13 @@ public function __construct(
}

/** @param array<mixed> $context */
public function create(string $ownerCode, ?\SplFileInfo $file, ?string $type, array $context = []): ImageInterface
public function create(string $ownerIdentifier, ?\SplFileInfo $file, ?string $type = null, array $context = []): ImageInterface
{
if (null === $file) {
throw new NoFileUploadedException();
}

$owner = $this->productRepository->findOneBy(['code' => $ownerCode]);
$owner = $this->productRepository->findOneBy(['code' => $ownerIdentifier]);
if (null === $owner) {
throw new ProductNotFoundException();
}
Expand Down
4 changes: 2 additions & 2 deletions src/Sylius/Bundle/ApiBundle/Creator/TaxonImageCreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ public function __construct(
}

/** @param array<mixed> $context */
public function create(string $ownerCode, ?\SplFileInfo $file, ?string $type, array $context = []): ImageInterface
public function create(string $ownerIdentifier, ?\SplFileInfo $file, ?string $type = null, array $context = []): ImageInterface
{
if (null === $file) {
throw new NoFileUploadedException();
}

$owner = $this->taxonRepository->findOneBy(['code' => $ownerCode]);
$owner = $this->taxonRepository->findOneBy(['code' => $ownerIdentifier]);
if (null === $owner) {
throw new TaxonNotFoundException();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,12 @@

<operation
class="ApiPlatform\Metadata\Post"
controller="Sylius\Bundle\ApiBundle\Controller\UploadAvatarImageAction"
processor="sylius_api.state_processor.post.upload_avatar_image"
deserialize="false"
>
<inputFormats>
<format name="multipart">multipart/form-data</format>
</inputFormats>
<normalizationContext>
<values>
<value name="groups">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,6 @@
<argument type="service" id="Sylius\Bundle\CoreBundle\CatalogPromotion\Processor\CatalogPromotionRemovalProcessorInterface" />
</service>

<service id="Sylius\Bundle\ApiBundle\Controller\UploadAvatarImageAction">
<argument type="service" id="sylius.factory.avatar_image" />
<argument type="service" id="sylius.repository.avatar_image" />
<argument type="service" id="sylius.repository.admin_user" />
<argument type="service" id="sylius.image_uploader" />
</service>

<service id="Sylius\Bundle\ApiBundle\Controller\UploadProductImageAction">
<argument type="service" id="Sylius\Bundle\ApiBundle\Creator\ProductImageCreator" />
</service>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"
>
<services>
<service id="sylius_api.creator.avatar_image" class="Sylius\Bundle\ApiBundle\Creator\AvatarImageCreator">
<argument type="service" id="sylius.factory.avatar_image" />
<argument type="service" id="sylius.repository.admin_user" />
<argument type="service" id="sylius.image_uploader" />
<argument type="service" id="api_platform.symfony.iri_converter" />
</service>

<service id="Sylius\Bundle\ApiBundle\Creator\ProductImageCreator">
<argument type="service" id="sylius.factory.product_image" />
<argument type="service" id="sylius.repository.product" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,12 @@
<argument type="service" id="Sylius\Bundle\ApiBundle\Context\UserContextInterface" />
<tag name="api_platform.state_processor" />
</service>

<service id="sylius_api.state_processor.post.upload_avatar_image" class="Sylius\Bundle\ApiBundle\StateProcessor\Post\UploadAvatarImageProcessor">
<argument type="service" id="api_platform.doctrine.orm.state.persist_processor" />
<argument type="service" id="sylius_api.creator.avatar_image" />
<argument type="service" id="sylius.repository.avatar_image" />
<tag name="api_platform.state_processor" />
</service>
</services>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace Sylius\Bundle\ApiBundle\StateProcessor\Post;

use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProcessorInterface;
use Sylius\Bundle\ApiBundle\Creator\ImageCreatorInterface;
use Sylius\Component\Core\Repository\AvatarImageRepositoryInterface;

final readonly class UploadAvatarImageProcessor implements ProcessorInterface
{
public function __construct(
private ProcessorInterface $processor,
private ImageCreatorInterface $avatarImageCreator,
private AvatarImageRepositoryInterface $avatarImageRepository,
) {
}

public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = [])
{
if ($data !== null) {
$this->avatarImageRepository->remove($data);
}

$image = $this->avatarImageCreator->create(
$context['request']->attributes->getString('id'),
$context['request']->files->get('file'),
);

return $this->processor->process($image, $operation, $uriVariables, $context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

/*
* This file is part of the Sylius package.
*
* (c) Sylius Sp. z o.o.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace spec\Sylius\Bundle\ApiBundle\Creator;

use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Bundle\ApiBundle\Exception\AdminUserNotFoundException;
use Sylius\Bundle\ApiBundle\Exception\NoFileUploadedException;
use Sylius\Component\Core\Model\AdminUserInterface;
use Sylius\Component\Core\Model\AvatarImageInterface;
use Sylius\Component\Core\Uploader\ImageUploaderInterface;
use Sylius\Component\Resource\Factory\FactoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;

final class AvatarImageCreatorSpec extends ObjectBehavior
{
function let(
FactoryInterface $avatarImageFactory,
RepositoryInterface $adminUserRepository,
ImageUploaderInterface $imageUploader,
) {
$this->beConstructedWith($avatarImageFactory, $adminUserRepository, $imageUploader);
}

function it_creates_an_avatar_image(
FactoryInterface $avatarImageFactory,
RepositoryInterface $adminUserRepository,
ImageUploaderInterface $imageUploader,
AdminUserInterface $adminUser,
AvatarImageInterface $avatarImage,
): void {
$file = new \SplFileInfo(__FILE__);

$adminUserRepository->find('1')->willReturn($adminUser);

$avatarImageFactory->createNew()->willReturn($avatarImage);
$avatarImage->setFile($file)->shouldBeCalled();

$adminUser->setImage($avatarImage)->shouldBeCalled();

$imageUploader->upload($avatarImage)->shouldBeCalled();

$this->create('1', $file, null)->shouldReturn($avatarImage);
}

function it_throws_an_exception_if_admin_user_is_not_found(
FactoryInterface $avatarImageFactory,
RepositoryInterface $adminUserRepository,
ImageUploaderInterface $imageUploader,
): void {
$file = new \SplFileInfo(__FILE__);

$adminUserRepository->find('1')->willReturn(null);

$avatarImageFactory->createNew()->shouldNotBeCalled();
$imageUploader->upload(Argument::any())->shouldNotBeCalled();

$this
->shouldThrow(AdminUserNotFoundException::class)
->during('create', ['1', $file, null])
;
}

function it_throws_an_exception_if_there_is_no_uploaded_file(
FactoryInterface $avatarImageFactory,
RepositoryInterface $adminUserRepository,
ImageUploaderInterface $imageUploader,
): void {
$adminUserRepository->find('1')->shouldNotBeCalled();
$avatarImageFactory->createNew()->shouldNotBeCalled();
$imageUploader->upload(Argument::any())->shouldNotBeCalled();

$this
->shouldThrow(NoFileUploadedException::class)
->during('create', ['1', null, null])
;
}
}

0 comments on commit 8f8c08f

Please sign in to comment.