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 关注
- 96 浏览
添加回答
举报