2 回答

TA貢獻1821條經驗 獲得超6個贊
VichUploaderBundle 使用 prePersist 和 preUpdate 掛鉤在學說事件監聽器中進行上傳處理。你的情況的問題是,從學說的角度來看,持久性財產沒有改變。由于沒有更改,因此不會調用上傳偵聽器。
一個簡單的解決方法是在上傳文件時始終更改持久屬性。我向您的實體添加了將和所需的更改保持在一起updatedAt的方法。updateLogologoFileupdatedAt
final class Organization
{
(...)
/**
* @ApiProperty(iri="http://schema.org/logo")
* @Groups({"organization:collection:get", "logo:post"})
* @ORM\Column(nullable=true)
*/
public ?string $logoPath = null;
/**
* @ORM\Column(type="datetime")
*/
private ?DateTime $updatedAt = null;
/**
* @var File|null
*
* @Assert\NotNull(groups={"logo_create"})
* @Vich\UploadableField(mapping="logo", fileNameProperty="logoPath")
*/
private ?File $logoFile = null;
(...)
public function updateLogo(File $logo): void
{
$this->logoFile = $logo;
$this->updatedAt = new DateTime();
}
}
final class CreateOrganizationLogoAction extends AbstractController
{
(...)
/**
* @param Request $request
*
* @return EntityOrganization
*/
public function __invoke(Request $request): EntityOrganization
{
$uploadedFile = $request->files->get('logoFile');
if (!$uploadedFile) {
throw new BadRequestHttpException('"file" is required');
}
$organization = $this->repository->find(Uuid::fromString($request->attributes->get('id')));
$organization->updateLogo($uploadedFile);
return $organization;
}
}

TA貢獻2080條經驗 獲得超4個贊
我目前正在開發一個允許用戶上傳媒體文件的項目。
我已經丟棄了 Vich 包。Api平臺是面向application/ld+json的。
相反,我讓用戶提供一個 base64 編碼的內容文件(即僅包含可讀字符的字符串表示形式)。
我得到的唯一對應結果是,在 http 傳輸期間文件大小增加了約 30%。老實說,沒關系。
我建議你做類似下面代碼的事情。
OrganizationController --use-->組織1 <>---> 0..1 ImageObject
徽標(請注意$encodingFormat屬性上的斷言):
<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
/**
* An image file.
*
* @see http://schema.org/ImageObject Documentation on Schema.org
*
* @ORM\Entity
* @ApiResource(
* iri="http://schema.org/ImageObject",
* normalizationContext={"groups" = {"imageobject:get"}}
* collectionOperations={"get"},
* itemOperations={"get"}
* )
*/
class ImageObject
{
/**
* @var int|null
*
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
* @Groups({"imageobject:get"})
*/
private $id;
/**
* @var string|null the name of the item
*
* @ORM\Column(type="text", nullable=true)
* @ApiProperty(iri="http://schema.org/name")
* @Groups({"imageobject:get"})
*/
private $name;
/**
* @var string|null actual bytes of the media object, for example the image file or video file
*
* @ORM\Column(type="text", nullable=true)
* @ApiProperty(iri="http://schema.org/contentUrl")
* @Groups({"imageobject:get"})
*/
private $contentUrl;
/**
* @var string|null mp3, mpeg4, etc
*
* @Assert\Regex("#^image/.*$#", message="This is not an image, this is a {{ value }} file.")
* @ORM\Column(type="text", nullable=true)
* @ApiProperty(iri="http://schema.org/encodingFormat")
* @Groups({"imageobject:get"})
*/
private $encodingFormat;
// getters and setters, nothing specific here
您剝離的Organization類,聲明OrganizationController:
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use App\Repository\OrganizationRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Groups;
use Symfony\Component\Validator\Constraints as Assert;
use App\Controller\OrganizationController;
/**
* @ApiResource(
* normalizationContext={
"groups" = {"organization:get"}
* },
* denormalizationContext={
"groups" = {"organization:post"}
* },
* collectionOperations={
"get",
* "post" = {
* "controller" = OrganizationController::class
* }
* }
* )
* @ORM\Entity(repositoryClass=OrganizationRepository::class)
*/
class Organization
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
* @Groups({"organization:get"})
*/
private $id;
/**
* @var string
* @ORM\Column(type="string", length=100, unique=true)
* @Groups({"organization:get", "organization:post"})
*/
private $slug;
/**
* @var null|ImageObject
* @Assert\Valid()
* @ORM\OneToOne(targetEntity=ImageObject::class, cascade={"persist", "remove"})
* @Groups({"organization:get"})
*/
private $logo;
/**
* @var string the logo BLOB, base64-encoded, without line separators.
* @Groups({"organization:post"})
*/
private $b64LogoContent;
// getters and setters, nothing specific here...
}
請注意$logo和$b64LogoContent屬性的序列化組。
然后是控制器(動作類),以解碼、分配和寫入標識內容。
<?php
namespace App\Controller;
use App\Entity\ImageObject;
use App\Entity\Organization;
use finfo;
/**
* Handle the base64-encoded logo content.
*/
class OrganizationController
{
public function __invoke(Organization $data)
{
$b64LogoContent = $data->getB64LogoContent();
if (! empty($b64LogoContent)) {
$logo = $this->buildAndWriteLogo($b64LogoContent);
$data->setLogo($logo);
}
return $data;
}
private function buildAndWriteLogo(string $b64LogoContent): ImageObject
{
$logo = new ImageObject();
$content = str_replace("\n", "", base64_decode($b64LogoContent));
$mimeType = (new finfo())->buffer($content, FILEINFO_MIME_TYPE);
$autoGeneratedId = $this->createFileName($content, $mimeType); // Or anything to generate an ID, like md5sum
$logo->setName($autoGeneratedId);
$logo->setContentUrl("/public/images/logo/$autoGeneratedId");
$logo->setEncodingFormat($mimeType);
// check the directory permissions!
// writing the file should be done after data validation
file_put_contents("images/logo/$autoGeneratedId", $content);
return $logo;
}
private function createFileName(string $content, string $mimeType): string
{
if (strpos($mimeType, "image/") === 0) {
$extension = explode('/', $mimeType)[1];
} else {
$extension = "txt";
}
return time() . ".$extension";
}
}
它檢查提供的徽標是否是帶有ImageObject 類的@Assert注釋(encodingFormat、寬度、高度等)的“小圖像”,它們由Organization::$logo屬性的@Assert\Valid注釋觸發。
這樣,您可以通過發送單個HTTP POST /organizations請求來創建帶有其徽標的組織。
- 2 回答
- 0 關注
- 129 瀏覽
添加回答
舉報