Просмотр исходного кода

comments entity, dto, factory

master
Daniel 2 лет назад
Родитель
Сommit
1310e2bc4c
26 измененных файлов: 1054 добавлений и 645 удалений
  1. +469
    -483
      composer.lock
  2. +3
    -1
      config/packages/api_platform.yaml
  3. +0
    -51
      migrations/Version20240214151436.php
  4. +45
    -0
      migrations/Version20240215093709.php
  5. +65
    -0
      src/ApiResource/CommentApi.php
  6. +5
    -0
      src/ApiResource/ContactApi.php
  7. +0
    -1
      src/ApiResource/PartnerApi.php
  8. +24
    -4
      src/ApiResource/PostingApi.php
  9. +4
    -5
      src/ApiResource/UserApi.php
  10. +5
    -23
      src/DataFixtures/AppFixtures.php
  11. +95
    -0
      src/Entity/Comment.php
  12. +1
    -1
      src/Entity/Contact.php
  13. +36
    -0
      src/Entity/Posting.php
  14. +34
    -0
      src/Entity/User.php
  15. +71
    -0
      src/Factory/CommentFactory.php
  16. +3
    -1
      src/Factory/ContactFactory.php
  17. +1
    -0
      src/Factory/PartnerFactory.php
  18. +3
    -0
      src/Factory/PostingFactory.php
  19. +58
    -0
      src/Mapper/CommentApiToEntityMapper.php
  20. +55
    -0
      src/Mapper/CommentEntityToApiMapper.php
  21. +8
    -0
      src/Mapper/ContactEntityToApiMapper.php
  22. +2
    -0
      src/Mapper/PostingApiToEntityMapper.php
  23. +16
    -7
      src/Mapper/PostingEntityToApiMapper.php
  24. +3
    -2
      src/Mapper/UserEntityToApiMapper.php
  25. +48
    -0
      src/Repository/CommentRepository.php
  26. +0
    -66
      src/Serializer/MediaObjectNormalizer.php

+ 469
- 483
composer.lock
Разница между файлами не показана из-за своего большого размера
Просмотреть файл


+ 3
- 1
config/packages/api_platform.yaml Просмотреть файл

@@ -30,4 +30,6 @@ api_platform:
api_keys:
JWT:
name: Authorization
type: header
type: header
swagger_ui_extra_configuration:
persistAuthorization: true

+ 0
- 51
migrations/Version20240214151436.php Просмотреть файл

@@ -1,51 +0,0 @@
<?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 Version20240214151436 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 contact (id INT AUTO_INCREMENT NOT NULL, partner_id INT NOT NULL, image_id INT DEFAULT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, birthday DATE DEFAULT NULL, position VARCHAR(255) DEFAULT NULL, phone VARCHAR(255) DEFAULT NULL, email VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_4C62E6389393F8FE (partner_id), INDEX IDX_4C62E6383DA5256D (image_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE media_object (id INT AUTO_INCREMENT NOT NULL, file_path VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE partner (id INT AUTO_INCREMENT NOT NULL, logo_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, type VARCHAR(255) NOT NULL, street VARCHAR(255) DEFAULT NULL, street_no VARCHAR(255) DEFAULT NULL, zip VARCHAR(255) DEFAULT NULL, city VARCHAR(255) DEFAULT NULL, country VARCHAR(255) DEFAULT NULL, website VARCHAR(255) DEFAULT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_312B3E16F98F144A (logo_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE posting (id INT AUTO_INCREMENT NOT NULL, owner_id INT NOT NULL, partner_id INT NOT NULL, contact_id INT DEFAULT NULL, headline VARCHAR(255) DEFAULT NULL, message LONGTEXT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_BD275D737E3C61F9 (owner_id), INDEX IDX_BD275D739393F8FE (partner_id), INDEX IDX_BD275D73E7A1254A (contact_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE `user` (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(180) NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, roles JSON NOT NULL COMMENT \'(DC2Type:json)\', password VARCHAR(255) NOT NULL, active TINYINT(1) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX UNIQ_8D93D649E7927C74 (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE contact ADD CONSTRAINT FK_4C62E6389393F8FE FOREIGN KEY (partner_id) REFERENCES partner (id)');
$this->addSql('ALTER TABLE contact ADD CONSTRAINT FK_4C62E6383DA5256D FOREIGN KEY (image_id) REFERENCES media_object (id)');
$this->addSql('ALTER TABLE partner ADD CONSTRAINT FK_312B3E16F98F144A FOREIGN KEY (logo_id) REFERENCES media_object (id)');
$this->addSql('ALTER TABLE posting ADD CONSTRAINT FK_BD275D737E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id)');
$this->addSql('ALTER TABLE posting ADD CONSTRAINT FK_BD275D739393F8FE FOREIGN KEY (partner_id) REFERENCES partner (id)');
$this->addSql('ALTER TABLE posting ADD CONSTRAINT FK_BD275D73E7A1254A FOREIGN KEY (contact_id) REFERENCES contact (id)');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE contact DROP FOREIGN KEY FK_4C62E6389393F8FE');
$this->addSql('ALTER TABLE contact DROP FOREIGN KEY FK_4C62E6383DA5256D');
$this->addSql('ALTER TABLE partner DROP FOREIGN KEY FK_312B3E16F98F144A');
$this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D737E3C61F9');
$this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D739393F8FE');
$this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D73E7A1254A');
$this->addSql('DROP TABLE contact');
$this->addSql('DROP TABLE media_object');
$this->addSql('DROP TABLE partner');
$this->addSql('DROP TABLE posting');
$this->addSql('DROP TABLE `user`');
}
}

+ 45
- 0
migrations/Version20240215093709.php Просмотреть файл

@@ -0,0 +1,45 @@
<?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 Version20240215093709 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 comment (id INT AUTO_INCREMENT NOT NULL, owner_id INT NOT NULL, posting_id INT NOT NULL, message LONGTEXT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_9474526C7E3C61F9 (owner_id), INDEX IDX_9474526C9AE985F6 (posting_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE posting (id INT AUTO_INCREMENT NOT NULL, owner_id INT NOT NULL, partner_id INT NOT NULL, contact_id INT DEFAULT NULL, headline VARCHAR(255) NOT NULL, message LONGTEXT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_BD275D737E3C61F9 (owner_id), INDEX IDX_BD275D739393F8FE (partner_id), INDEX IDX_BD275D73E7A1254A (contact_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE `user` (id INT AUTO_INCREMENT NOT NULL, email VARCHAR(180) NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, roles JSON NOT NULL COMMENT \'(DC2Type:json)\', password VARCHAR(255) NOT NULL, active TINYINT(1) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX UNIQ_8D93D649E7927C74 (email), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526C7E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id)');
$this->addSql('ALTER TABLE comment ADD CONSTRAINT FK_9474526C9AE985F6 FOREIGN KEY (posting_id) REFERENCES posting (id)');
$this->addSql('ALTER TABLE posting ADD CONSTRAINT FK_BD275D737E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id)');
$this->addSql('ALTER TABLE posting ADD CONSTRAINT FK_BD275D739393F8FE FOREIGN KEY (partner_id) REFERENCES partner (id)');
$this->addSql('ALTER TABLE posting ADD CONSTRAINT FK_BD275D73E7A1254A FOREIGN KEY (contact_id) REFERENCES contact (id)');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE comment DROP FOREIGN KEY FK_9474526C7E3C61F9');
$this->addSql('ALTER TABLE comment DROP FOREIGN KEY FK_9474526C9AE985F6');
$this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D737E3C61F9');
$this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D739393F8FE');
$this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D73E7A1254A');
$this->addSql('DROP TABLE comment');
$this->addSql('DROP TABLE posting');
$this->addSql('DROP TABLE `user`');
}
}

+ 65
- 0
src/ApiResource/CommentApi.php Просмотреть файл

@@ -0,0 +1,65 @@
<?php
/**
* @author Daniel Knudsen <d.knudsen@spawntree.de>
* @date 12.12.23
*/


namespace App\ApiResource;

use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use App\Entity\Comment;
use App\State\EntityClassDtoStateProcessor;
use App\State\EntityToDtoStateProvider;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use App\Validator\IsValidOwner;
use Symfony\Component\Validator\Constraints\NotBlank;

#[ApiResource(
shortName: 'Comment',
operations: [
new Get(
security: 'is_granted("ROLE_USER")'
),
new GetCollection(),
new Post(
security: 'is_granted("ROLE_USER")',
),
new Patch(
security: 'is_granted("EDIT", object)',
),
new Delete(
security: 'is_granted("ROLE_ADMIN")',
)
],
security: 'is_granted("ROLE_USER")',
provider: EntityToDtoStateProvider::class,
processor: EntityClassDtoStateProcessor::class,
stateOptions: new Options(entityClass: Comment::class),
)]
#[ApiFilter(SearchFilter::class, properties: ['partner' => 'exact', 'contact' => 'exact'])]
class CommentApi
{
#[ApiProperty(readable: false, writable: false, identifier: true)]
public ?int $id = null;

#[NotBlank]
public ?string $message = null;

#[IsValidOwner]
public ?UserApi $owner = null;

public ?PostingApi $posting = null;

#[ApiProperty(writable: false)]
public ?\DateTimeImmutable $createdAt = null;

}

+ 5
- 0
src/ApiResource/ContactApi.php Просмотреть файл

@@ -73,5 +73,10 @@ class ContactApi

public ?string $email = null;

/**
* @var array<int, PostingApi>
*/
public array $postings = [];

public ?\DateTimeImmutable $createdAt = null;
}

+ 0
- 1
src/ApiResource/PartnerApi.php Просмотреть файл

@@ -44,7 +44,6 @@ use Symfony\Component\Validator\Constraints\NotBlank;
)
],
order: ['name' => 'ASC'],
paginationItemsPerPage: 10,
security: 'is_granted("ROLE_USER")',
provider: EntityToDtoStateProvider::class,
processor: EntityClassDtoStateProcessor::class,


+ 24
- 4
src/ApiResource/PostingApi.php Просмотреть файл

@@ -21,15 +21,18 @@ use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use App\Validator\IsValidOwner;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Validator\Constraints\NotBlank;

#[ApiResource(
shortName: 'Post',
operations: [
new Get(
security: 'is_granted("ROLE_USER")'
security: 'is_granted("ROLE_USER")',
),
new GetCollection(
security: 'is_granted("ROLE_USER")',
),
new GetCollection(),
new Post(
security: 'is_granted("ROLE_USER")',
),
@@ -40,11 +43,10 @@ use Symfony\Component\Validator\Constraints\NotBlank;
security: 'is_granted("ROLE_ADMIN")',
)
],
paginationItemsPerPage: 10,
security: 'is_granted("ROLE_USER")',
provider: EntityToDtoStateProvider::class,
processor: EntityClassDtoStateProcessor::class,
stateOptions: new Options(entityClass: Posting::class),
stateOptions: new Options(entityClass: Posting::class)
)]
#[ApiFilter(SearchFilter::class, properties: ['partner' => 'exact', 'contact' => 'exact'])]
class PostingApi
@@ -68,6 +70,24 @@ class PostingApi

public ?ContactApi $contact = null;

/**
* @var array<int, CommentApi>
*/
#[ApiProperty(
readableLink: true,
writableLink: true,
fetchEager: true,
builtinTypes: [
new Type(
'object',
collection: true,
collectionKeyType: [new Type('int')],
collectionValueType: new Type('object', class: CommentApi::class)
)
]
)]
public array $comments = [];

#[ApiProperty(writable: false)]
public ?\DateTimeImmutable $createdAt = null;


+ 4
- 5
src/ApiResource/UserApi.php Просмотреть файл

@@ -36,7 +36,6 @@ use Symfony\Component\Validator\Constraints as Assert;
security: 'is_granted("ROLE_USER")'
),
],
paginationItemsPerPage: 10,
security: 'is_granted("ROLE_USER")',
provider: EntityToDtoStateProvider::class,
processor: EntityClassDtoStateProcessor::class,
@@ -72,11 +71,11 @@ class UserApi
#[ApiProperty(security: 'object === null or is_granted("EDIT", object)')]
public bool $active;

#[ApiProperty(writable: false)]
public ?\DateTimeImmutable $createdAt = null;

/**
* @var array<int, PostingApi>
*/
public array $postings = [];
}

#[ApiProperty(writable: false)]
public ?\DateTimeImmutable $createdAt = null;
}

+ 5
- 23
src/DataFixtures/AppFixtures.php Просмотреть файл

@@ -2,6 +2,7 @@

namespace App\DataFixtures;

use App\Factory\CommentFactory;
use App\Factory\ContactFactory;
use App\Factory\MediaObjectLogoFactory;
use App\Factory\MediaObjectProfileFactory;
@@ -54,30 +55,11 @@ class AppFixtures extends Fixture
$adminF->setRoles(['ROLE_ADMIN']);

UserFactory::createMany(10);

MediaObjectLogoFactory::createMany(50);
PartnerFactory::createMany(100, function() {
return [
'logo' => MediaObjectLogoFactory::random()
];
});

PartnerFactory::createMany(100);
MediaObjectProfileFactory::createMany(50);
ContactFactory::createMany(200, function() {
return [
'partner' => PartnerFactory::random(),
'image' => MediaObjectProfileFactory::random()
];
});

PostingFactory::createMany(200, function() {
$randomBoolean = (bool)random_int(0, 1);
return [
'owner' => UserFactory::random(),
'partner' => PartnerFactory::random(),
'contact' => $randomBoolean ? ContactFactory::random() : null
];
});

ContactFactory::createMany(200);
PostingFactory::createMany(200);
CommentFactory::createMany(300);
}
}

+ 95
- 0
src/Entity/Comment.php Просмотреть файл

@@ -0,0 +1,95 @@
<?php

namespace App\Entity;

use App\Repository\CommentRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(repositoryClass: CommentRepository::class)]
class Comment
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;

#[ORM\Column(type: Types::TEXT)]
private ?string $message = null;

#[ORM\ManyToOne(inversedBy: 'comments')]
#[ORM\JoinColumn(nullable: false)]
private ?User $owner = null;

#[ORM\ManyToOne(inversedBy: 'comments')]
#[ORM\JoinColumn(nullable: false)]
private ?Posting $posting = null;

#[ORM\Column]
private ?\DateTimeImmutable $createdAt = null;

public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
}

public function getId(): ?int
{
return $this->id;
}

public function setId(int $id): static
{
$this->id = $id;

return $this;
}

public function getMessage(): ?string
{
return $this->message;
}

public function setMessage(string $message): static
{
$this->message = $message;

return $this;
}

public function getOwner(): ?User
{
return $this->owner;
}

public function setOwner(?User $owner): static
{
$this->owner = $owner;

return $this;
}

public function getPosting(): ?Posting
{
return $this->posting;
}

public function setPosting(?Posting $posting): static
{
$this->posting = $posting;

return $this;
}

public function getCreatedAt(): ?\DateTimeImmutable
{
return $this->createdAt;
}

public function setCreatedAt(\DateTimeImmutable $createdAt): static
{
$this->createdAt = $createdAt;

return $this;
}
}

+ 1
- 1
src/Entity/Contact.php Просмотреть файл

@@ -45,7 +45,7 @@ class Contact
#[ORM\Column]
private ?\DateTimeImmutable $createdAt = null;

#[ORM\OneToMany(mappedBy: 'contact', targetEntity: Posting::class)]
#[ORM\OneToMany(mappedBy: 'contact', targetEntity: Posting::class, orphanRemoval: true)]
private Collection $postings;

public function __construct()


+ 36
- 0
src/Entity/Posting.php Просмотреть файл

@@ -3,6 +3,8 @@
namespace App\Entity;

use App\Repository\PostingRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

@@ -34,9 +36,13 @@ class Posting
#[ORM\Column]
private ?\DateTimeImmutable $createdAt = null;

#[ORM\OneToMany(mappedBy: 'posting', targetEntity: Comment::class, orphanRemoval: true)]
private Collection $comments;

public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
$this->comments = new ArrayCollection();
}

public function getId(): ?int
@@ -108,4 +114,34 @@ class Posting

return $this;
}

/**
* @return Collection<int, Comment>
*/
public function getComments(): Collection
{
return $this->comments;
}

public function addComment(Comment $comment): static
{
if (!$this->comments->contains($comment)) {
$this->comments->add($comment);
$comment->setPosting($this);
}

return $this;
}

public function removeComment(Comment $comment): static
{
if ($this->comments->removeElement($comment)) {
// set the owning side to null (unless already changed)
if ($comment->getPosting() === $this) {
$comment->setPosting(null);
}
}

return $this;
}
}

+ 34
- 0
src/Entity/User.php Просмотреть файл

@@ -45,12 +45,16 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\OneToMany(mappedBy: 'owner', targetEntity: Posting::class, orphanRemoval: true)]
private Collection $postings;

#[ORM\OneToMany(mappedBy: 'owner', targetEntity: Comment::class, orphanRemoval: true)]
private Collection $comments;


public function __construct()
{
$this->createdAt = new \DateTimeImmutable();
$this->postings = new ArrayCollection();
$this->active = true;
$this->comments = new ArrayCollection();
}

public function getId(): ?int
@@ -198,4 +202,34 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface

return $this;
}

/**
* @return Collection<int, Comment>
*/
public function getComments(): Collection
{
return $this->comments;
}

public function addComment(Comment $comment): static
{
if (!$this->comments->contains($comment)) {
$this->comments->add($comment);
$comment->setOwner($this);
}

return $this;
}

public function removeComment(Comment $comment): static
{
if ($this->comments->removeElement($comment)) {
// set the owning side to null (unless already changed)
if ($comment->getOwner() === $this) {
$comment->setOwner(null);
}
}

return $this;
}
}

+ 71
- 0
src/Factory/CommentFactory.php Просмотреть файл

@@ -0,0 +1,71 @@
<?php

namespace App\Factory;

use App\Entity\Comment;
use App\Repository\CommentRepository;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Proxy;
use Zenstruck\Foundry\RepositoryProxy;

/**
* @extends ModelFactory<Comment>
*
* @method Comment|Proxy create(array|callable $attributes = [])
* @method static Comment|Proxy createOne(array $attributes = [])
* @method static Comment|Proxy find(object|array|mixed $criteria)
* @method static Comment|Proxy findOrCreate(array $attributes)
* @method static Comment|Proxy first(string $sortedField = 'id')
* @method static Comment|Proxy last(string $sortedField = 'id')
* @method static Comment|Proxy random(array $attributes = [])
* @method static Comment|Proxy randomOrCreate(array $attributes = [])
* @method static CommentRepository|RepositoryProxy repository()
* @method static Comment[]|Proxy[] all()
* @method static Comment[]|Proxy[] createMany(int $number, array|callable $attributes = [])
* @method static Comment[]|Proxy[] createSequence(iterable|callable $sequence)
* @method static Comment[]|Proxy[] findBy(array $attributes)
* @method static Comment[]|Proxy[] randomRange(int $min, int $max, array $attributes = [])
* @method static Comment[]|Proxy[] randomSet(int $number, array $attributes = [])
*/
final class CommentFactory extends ModelFactory
{
/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#factories-as-services
*
* @todo inject services if required
*/
public function __construct()
{
parent::__construct();
}

/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#model-factories
*
* @todo add your default values here
*/
protected function getDefaults(): array
{
return [
'createdAt' => \DateTimeImmutable::createFromMutable(self::faker()->dateTime()),
'message' => self::faker()->text(),
'owner' => UserFactory::random(),
'posting' => PostingFactory::random(),
];
}

/**
* @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization
*/
protected function initialize(): self
{
return $this
// ->afterInstantiate(function(Comment $comment): void {})
;
}

protected static function getClass(): string
{
return Comment::class;
}
}

+ 3
- 1
src/Factory/ContactFactory.php Просмотреть файл

@@ -53,7 +53,9 @@ final class ContactFactory extends ModelFactory
'birthday' => \DateTime::createFromFormat('Y-m-d', self::faker()->date()),
'position' => self::faker()->randomElement(FakeValues::POSITIONS),
'phone' => self::faker()->phoneNumber(),
'email' => self::faker()->email()
'email' => self::faker()->email(),
'partner' => PartnerFactory::random(),
'image' => MediaObjectProfileFactory::random()
];
}



+ 1
- 0
src/Factory/PartnerFactory.php Просмотреть файл

@@ -57,6 +57,7 @@ final class PartnerFactory extends ModelFactory
'zip' => self::faker()->numberBetween(1000,10000),
'city' => self::faker()->randomElement(FakeValues::CITIES),
'country' => self::faker()->randomElement(FakeValues::COUNTRIES),
'logo' => MediaObjectLogoFactory::random(),
'website' => 'https://spawntree.de/',
];
}


+ 3
- 0
src/Factory/PostingFactory.php Просмотреть файл

@@ -50,6 +50,9 @@ final class PostingFactory extends ModelFactory
return [
'headline' => self::faker()->words(random_int(1, 5), true),
'message' => $randomBoolean ? self::faker()->sentence() : self::faker()->sentences(random_int(1, 3), true),
'owner' => UserFactory::random(),
'partner' => PartnerFactory::random(),
'contact' => $randomBoolean ? ContactFactory::random() : null,
];
}



+ 58
- 0
src/Mapper/CommentApiToEntityMapper.php Просмотреть файл

@@ -0,0 +1,58 @@
<?php

namespace App\Mapper;

use App\ApiResource\CommentApi;
use App\Entity\Comment;
use App\Entity\User;
use App\Repository\CommentRepository;
use Symfony\Bundle\SecurityBundle\Security;
use Symfonycasts\MicroMapper\AsMapper;
use Symfonycasts\MicroMapper\MapperInterface;
use Symfonycasts\MicroMapper\MicroMapperInterface;

#[AsMapper(from: CommentApi::class, to: Comment::class)]
class CommentApiToEntityMapper implements MapperInterface
{
public function __construct(
private CommentRepository $repository,
private Security $security,
private MicroMapperInterface $microMapper,
)
{

}

public function load(object $from, string $toClass, array $context): object
{
$dto = $from;
assert($dto instanceof CommentApi);

$entity = $dto->id ? $this->repository->find($dto->id) : new Comment();
if (!$entity) {
throw new \Exception('Comment not found');
}

return $entity;
}

public function populate(object $from, object $to, array $context): object
{
$dto = $from;
assert($dto instanceof CommentApi);
$entity = $to;
assert($entity instanceof Comment);

if ($dto->owner) {
$entity->setOwner($this->microMapper->map($dto->owner, User::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]));
} else {
$entity->setOwner($this->security->getUser());
}
$entity->setPosting($dto->posting);
$entity->setMessage($dto->message);

return $entity;
}
}

+ 55
- 0
src/Mapper/CommentEntityToApiMapper.php Просмотреть файл

@@ -0,0 +1,55 @@
<?php

namespace App\Mapper;

use App\ApiResource\CommentApi;
use App\ApiResource\UserApi;
use App\ApiResource\PostingApi;
use App\Entity\Comment;
use Symfony\Bundle\SecurityBundle\Security;
use Symfonycasts\MicroMapper\AsMapper;
use Symfonycasts\MicroMapper\MapperInterface;
use Symfonycasts\MicroMapper\MicroMapperInterface;

#[AsMapper(from: Comment::class, to: CommentApi::class)]
class CommentEntityToApiMapper implements MapperInterface
{
public function __construct(
private MicroMapperInterface $microMapper,
private Security $security,
)
{
}

public function load(object $from, string $toClass, array $context): object
{
$entity = $from;
assert($entity instanceof Comment);

$dto = new CommentApi();
$dto->id = $entity->getId();

return $dto;
}

public function populate(object $from, object $to, array $context): object
{
$entity = $from;
$dto = $to;
assert($entity instanceof Comment);
assert($dto instanceof CommentApi);

$dto->message = $entity->getMessage();
$dto->owner = $this->microMapper->map($entity->getOwner(), UserApi::class, [
MicroMapperInterface::MAX_DEPTH => 0,
]);

$dto->posting = $this->microMapper->map($entity->getPosting(), PostingApi::class, [
MicroMapperInterface::MAX_DEPTH => 0,
]);

$dto->createdAt = $entity->getCreatedAt();

return $dto;
}
}

+ 8
- 0
src/Mapper/ContactEntityToApiMapper.php Просмотреть файл

@@ -4,8 +4,10 @@ namespace App\Mapper;

use App\ApiResource\ContactApi;
use App\ApiResource\PartnerApi;
use App\ApiResource\PostingApi;
use App\Entity\Contact;
use App\Entity\Partner;
use App\Entity\Posting;
use Symfonycasts\MicroMapper\AsMapper;
use Symfonycasts\MicroMapper\MapperInterface;
use Symfonycasts\MicroMapper\MicroMapperInterface;
@@ -54,6 +56,12 @@ class ContactEntityToApiMapper implements MapperInterface
$dto->email = $entity->getEmail();
$dto->createdAt = $entity->getCreatedAt();

$dto->postings = array_map(function(Posting $posting) {
return $this->microMapper->map($posting, PostingApi::class, [
MicroMapperInterface::MAX_DEPTH => 0,
]);
}, $entity->getPostings()->getValues());

return $dto;
}
}

+ 2
- 0
src/Mapper/PostingApiToEntityMapper.php Просмотреть файл

@@ -54,6 +54,8 @@ class PostingApiToEntityMapper implements MapperInterface
$entity->setOwner($this->security->getUser());
}

$entity->setPartner($dto->partner);
$entity->setContact($dto->contact);
$entity->setMessage($dto->message);

return $entity;


+ 16
- 7
src/Mapper/PostingEntityToApiMapper.php Просмотреть файл

@@ -2,12 +2,13 @@

namespace App\Mapper;

use App\ApiResource\CommentApi;
use App\ApiResource\ContactApi;
use App\ApiResource\PartnerApi;
use App\ApiResource\UserApi;
use App\ApiResource\PostingApi;
use App\Entity\Comment;
use App\Entity\Posting;
use Symfony\Bundle\SecurityBundle\Security;
use Symfonycasts\MicroMapper\AsMapper;
use Symfonycasts\MicroMapper\MapperInterface;
use Symfonycasts\MicroMapper\MicroMapperInterface;
@@ -17,7 +18,6 @@ class PostingEntityToApiMapper implements MapperInterface
{
public function __construct(
private MicroMapperInterface $microMapper,
private Security $security,
)
{
}
@@ -43,18 +43,27 @@ class PostingEntityToApiMapper implements MapperInterface
$dto->headline = $entity->getHeadline();
$dto->message = $entity->getMessage();
$dto->owner = $this->microMapper->map($entity->getOwner(), UserApi::class, [
MicroMapperInterface::MAX_DEPTH => 0,
MicroMapperInterface::MAX_DEPTH => 1,
]);
$dto->ownerName = $entity->getOwner()?->getFirstName()." ".$entity->getOwner()?->getLastName();

$dto->partner = $this->microMapper->map($entity->getPartner(), PartnerApi::class, [
MicroMapperInterface::MAX_DEPTH => 0,
MicroMapperInterface::MAX_DEPTH => 1,
]);

$dto->contact = $this->microMapper->map($entity->getContact(), ContactApi::class, [
MicroMapperInterface::MAX_DEPTH => 0,
]);
$dto->contact = null;
if ($entity->getContact() !== null) {
$dto->contact = $this->microMapper->map($entity->getContact(), ContactApi::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]);
}

$dto->comments = array_map(function(Comment $comment) {
return $this->microMapper->map($comment, CommentApi::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]);
}, $entity->getComments()->getValues());
//dd($dto);
$dto->createdAt = $entity->getCreatedAt();

return $dto;


+ 3
- 2
src/Mapper/UserEntityToApiMapper.php Просмотреть файл

@@ -40,8 +40,9 @@ class UserEntityToApiMapper implements MapperInterface
$dto->email = $entity->getEmail();
$dto->firstName = $entity->getFirstName();
$dto->lastName = $entity->getLastName();
$dto->postings = array_map(function(Posting $userPost) {
return $this->microMapper->map($userPost, PostingApi::class, [

$dto->postings = array_map(function(Posting $posting) {
return $this->microMapper->map($posting, PostingApi::class, [
MicroMapperInterface::MAX_DEPTH => 0,
]);
}, $entity->getPostings()->getValues());


+ 48
- 0
src/Repository/CommentRepository.php Просмотреть файл

@@ -0,0 +1,48 @@
<?php

namespace App\Repository;

use App\Entity\Comment;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;

/**
* @extends ServiceEntityRepository<Comment>
*
* @method Comment|null find($id, $lockMode = null, $lockVersion = null)
* @method Comment|null findOneBy(array $criteria, array $orderBy = null)
* @method Comment[] findAll()
* @method Comment[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class CommentRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Comment::class);
}

// /**
// * @return Comment[] Returns an array of Comment objects
// */
// public function findByExampleField($value): array
// {
// return $this->createQueryBuilder('c')
// ->andWhere('c.exampleField = :val')
// ->setParameter('val', $value)
// ->orderBy('c.id', 'ASC')
// ->setMaxResults(10)
// ->getQuery()
// ->getResult()
// ;
// }

// public function findOneBySomeField($value): ?Comment
// {
// return $this->createQueryBuilder('c')
// ->andWhere('c.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

+ 0
- 66
src/Serializer/MediaObjectNormalizer.php Просмотреть файл

@@ -1,66 +0,0 @@
<?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;

if ($object instanceof MediaObject) {
// Nur für MediaObject die URI generieren
$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 $this->normalizer->supportsNormalization($data, $format, $context);
}

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] : [];
}
}

Загрузка…
Отмена
Сохранить