Pārlūkot izejas kodu

user product

master
Daniel pirms 1 gada
vecāks
revīzija
18164340ff
12 mainītis faili ar 483 papildinājumiem un 4 dzēšanām
  1. +7
    -1
      migrations/Version20240408091731.php
  2. +0
    -1
      src/ApiResource/CommentApi.php
  3. +8
    -2
      src/ApiResource/PartnerFollowApi.php
  4. +72
    -0
      src/ApiResource/UserProductApi.php
  5. +19
    -0
      src/DataFixtures/AppFixtures.php
  6. +34
    -0
      src/Entity/Product.php
  7. +34
    -0
      src/Entity/User.php
  8. +74
    -0
      src/Entity/UserProduct.php
  9. +70
    -0
      src/Factory/UserProductFactory.php
  10. +63
    -0
      src/Mapper/UserProductApiToEntityMapper.php
  11. +54
    -0
      src/Mapper/UserProductEntityToApiMapper.php
  12. +48
    -0
      src/Repository/UserProductRepository.php

migrations/Version20240404115740.php → migrations/Version20240408091731.php Parādīt failu

@@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240404115740 extends AbstractMigration
final class Version20240408091731 extends AbstractMigration
{
public function getDescription(): string
{
@@ -35,6 +35,7 @@ final class Version20240404115740 extends AbstractMigration
$this->addSql('CREATE TABLE task (id INT AUTO_INCREMENT NOT NULL, created_by_id INT NOT NULL, assigned_to_id INT NOT NULL, partner_id INT DEFAULT NULL, contact_id INT DEFAULT NULL, headline VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, due_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', prio VARCHAR(255) NOT NULL, completed TINYINT(1) NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_527EDB25B03A8386 (created_by_id), INDEX IDX_527EDB25F4BD7827 (assigned_to_id), INDEX IDX_527EDB259393F8FE (partner_id), INDEX IDX_527EDB25E7A1254A (contact_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE task_note (id INT AUTO_INCREMENT NOT NULL, owner_id INT NOT NULL, task_id INT NOT NULL, message LONGTEXT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_BC0E6E6F7E3C61F9 (owner_id), INDEX IDX_BC0E6E6F8DB60186 (task_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, image_id INT DEFAULT 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), INDEX IDX_8D93D6493DA5256D (image_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('CREATE TABLE user_product (id INT AUTO_INCREMENT NOT NULL, user_id INT NOT NULL, product_id INT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_8B471AA7A76ED395 (user_id), INDEX IDX_8B471AA74584665A (product_id), 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) ON DELETE CASCADE');
$this->addSql('ALTER TABLE contact ADD CONSTRAINT FK_4C62E6389393F8FE FOREIGN KEY (partner_id) REFERENCES partner (id) ON DELETE CASCADE');
@@ -71,6 +72,8 @@ final class Version20240404115740 extends AbstractMigration
$this->addSql('ALTER TABLE task_note ADD CONSTRAINT FK_BC0E6E6F7E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE task_note ADD CONSTRAINT FK_BC0E6E6F8DB60186 FOREIGN KEY (task_id) REFERENCES task (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE `user` ADD CONSTRAINT FK_8D93D6493DA5256D FOREIGN KEY (image_id) REFERENCES media_object (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE user_product ADD CONSTRAINT FK_8B471AA7A76ED395 FOREIGN KEY (user_id) REFERENCES `user` (id)');
$this->addSql('ALTER TABLE user_product ADD CONSTRAINT FK_8B471AA74584665A FOREIGN KEY (product_id) REFERENCES product (id)');
}

public function down(Schema $schema): void
@@ -112,6 +115,8 @@ final class Version20240404115740 extends AbstractMigration
$this->addSql('ALTER TABLE task_note DROP FOREIGN KEY FK_BC0E6E6F7E3C61F9');
$this->addSql('ALTER TABLE task_note DROP FOREIGN KEY FK_BC0E6E6F8DB60186');
$this->addSql('ALTER TABLE `user` DROP FOREIGN KEY FK_8D93D6493DA5256D');
$this->addSql('ALTER TABLE user_product DROP FOREIGN KEY FK_8B471AA7A76ED395');
$this->addSql('ALTER TABLE user_product DROP FOREIGN KEY FK_8B471AA74584665A');
$this->addSql('DROP TABLE comment');
$this->addSql('DROP TABLE contact');
$this->addSql('DROP TABLE contact_partner_product');
@@ -127,5 +132,6 @@ final class Version20240404115740 extends AbstractMigration
$this->addSql('DROP TABLE task');
$this->addSql('DROP TABLE task_note');
$this->addSql('DROP TABLE `user`');
$this->addSql('DROP TABLE user_product');
}
}

+ 0
- 1
src/ApiResource/CommentApi.php Parādīt failu

@@ -71,7 +71,6 @@ class CommentApi implements OwnerInterface

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

+ 8
- 2
src/ApiResource/PartnerFollowApi.php Parādīt failu

@@ -15,6 +15,7 @@ use ApiPlatform\Metadata\ApiResource;
use App\Entity\Partner;
use App\Entity\PartnerFollow;
use App\Entity\User;
use App\Interface\OwnerInterface;
use App\State\EntityClassDtoStateProcessor;
use App\State\EntityToDtoStateProvider;
use ApiPlatform\Metadata\Delete;
@@ -37,7 +38,7 @@ use Symfony\Component\Validator\Constraints\NotBlank;
security: 'is_granted("ROLE_USER")',
),
new Delete(
security: 'is_granted("ROLE_USER")',
security: 'is_granted("EDIT", object)',
)
],
security: 'is_granted("ROLE_USER")',
@@ -46,7 +47,7 @@ use Symfony\Component\Validator\Constraints\NotBlank;
stateOptions: new Options(entityClass: PartnerFollow::class),
)]
#[ApiFilter(SearchFilter::class, properties: ['partner' => 'exact', 'user' => 'exact'])]
class PartnerFollowApi
class PartnerFollowApi implements OwnerInterface
{
#[ApiProperty(readable: false, writable: false, identifier: true)]
public ?int $id = null;
@@ -65,4 +66,9 @@ class PartnerFollowApi

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

public function getOwner(): ?UserApi
{
return $this->user;
}
}

+ 72
- 0
src/ApiResource/UserProductApi.php Parādīt failu

@@ -0,0 +1,72 @@
<?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\PartnerProduct;
use App\Entity\UserProduct;
use App\Interface\OwnerInterface;
use App\State\EntityClassDtoStateProcessor;
use App\State\EntityToDtoStateProvider;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Post;
use Symfony\Component\Validator\Constraints\NotBlank;

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

#[ApiProperty(writable: false)]
public ?UserApi $user = null;

#[ApiProperty(writable: false)]
public ?string $userName = null;

#[NotBlank]
public ?ProductApi $product = null;

#[ApiProperty(writable: false)]
public ?string $productName = null;

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

public function getOwner(): ?UserApi
{
return $this->user;
}
}

+ 19
- 0
src/DataFixtures/AppFixtures.php Parādīt failu

@@ -22,6 +22,7 @@ use App\Factory\SaleFactory;
use App\Factory\TaskFactory;
use App\Factory\TaskNoteFactory;
use App\Factory\UserFactory;
use App\Factory\UserProductFactory;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
use Symfony\Component\HttpKernel\KernelInterface;
@@ -189,6 +190,24 @@ class AppFixtures extends Fixture
}
}

$users = UserFactory::all();
foreach ($users as $user) {
$productsPicked = [];
for ($i = 0; $i < 3; $i++) {
$product = $products[array_rand($products)];
$productsPicked[$product->getId()] = $product;
}

foreach ($productsPicked as $item) {
UserProductFactory::createOne(
[
'user' => $user,
'product' => $item
]
);
}
}


}
}

+ 34
- 0
src/Entity/Product.php Parādīt failu

@@ -45,6 +45,9 @@ class Product
#[ORM\OneToMany(mappedBy: 'product', targetEntity: PartnerProduct::class)]
private Collection $partnerProducts;

#[ORM\OneToMany(mappedBy: 'product', targetEntity: UserProduct::class)]
private Collection $userProducts;

public function __construct(User $createdBy)
{
$this->createdBy = $createdBy;
@@ -53,6 +56,7 @@ class Product
$this->documentObjects = new ArrayCollection();
$this->postings = new ArrayCollection();
$this->partnerProducts = new ArrayCollection();
$this->userProducts = new ArrayCollection();
}

public function getId(): ?int
@@ -225,4 +229,34 @@ class Product

return $this;
}

/**
* @return Collection<int, UserProduct>
*/
public function getUserProducts(): Collection
{
return $this->userProducts;
}

public function addUserProduct(UserProduct $userProduct): static
{
if (!$this->userProducts->contains($userProduct)) {
$this->userProducts->add($userProduct);
$userProduct->setProduct($this);
}

return $this;
}

public function removeUserProduct(UserProduct $userProduct): static
{
if ($this->userProducts->removeElement($userProduct)) {
// set the owning side to null (unless already changed)
if ($userProduct->getProduct() === $this) {
$userProduct->setProduct(null);
}
}

return $this;
}
}

+ 34
- 0
src/Entity/User.php Parādīt failu

@@ -61,6 +61,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\OneToMany(mappedBy: 'createdBy', targetEntity: Document::class)]
private Collection $documentObjects;

#[ORM\OneToMany(mappedBy: 'user', targetEntity: UserProduct::class)]
private Collection $userProducts;


public function __construct()
{
@@ -71,6 +74,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
$this->sales = new ArrayCollection();
$this->partnerFollows = new ArrayCollection();
$this->documentObjects = new ArrayCollection();
$this->userProducts = new ArrayCollection();
}

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

return $this;
}

/**
* @return Collection<int, UserProduct>
*/
public function getUserProducts(): Collection
{
return $this->userProducts;
}

public function addUserProduct(UserProduct $userProduct): static
{
if (!$this->userProducts->contains($userProduct)) {
$this->userProducts->add($userProduct);
$userProduct->setUser($this);
}

return $this;
}

public function removeUserProduct(UserProduct $userProduct): static
{
if ($this->userProducts->removeElement($userProduct)) {
// set the owning side to null (unless already changed)
if ($userProduct->getUser() === $this) {
$userProduct->setUser(null);
}
}

return $this;
}
}

+ 74
- 0
src/Entity/UserProduct.php Parādīt failu

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

namespace App\Entity;

use App\Repository\UserProductRepository;
use Doctrine\ORM\Mapping as ORM;

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

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

#[ORM\ManyToOne(inversedBy: 'userProducts')]
#[ORM\JoinColumn(nullable: false)]
private ?Product $product = null;

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

public function __construct(User $user, Product $product)
{
$this->user = $user;
$this->product = $product;
$this->createdAt = new \DateTimeImmutable();
}

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

public function getUser(): ?User
{
return $this->user;
}

public function setUser(?User $user): static
{
$this->user = $user;

return $this;
}

public function getProduct(): ?Product
{
return $this->product;
}

public function setProduct(?Product $product): static
{
$this->product = $product;

return $this;
}

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

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

return $this;
}
}

+ 70
- 0
src/Factory/UserProductFactory.php Parādīt failu

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

namespace App\Factory;

use App\Entity\UserProduct;
use App\Repository\UserProductRepository;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Proxy;
use Zenstruck\Foundry\RepositoryProxy;

/**
* @extends ModelFactory<UserProduct>
*
* @method UserProduct|Proxy create(array|callable $attributes = [])
* @method static UserProduct|Proxy createOne(array $attributes = [])
* @method static UserProduct|Proxy find(object|array|mixed $criteria)
* @method static UserProduct|Proxy findOrCreate(array $attributes)
* @method static UserProduct|Proxy first(string $sortedField = 'id')
* @method static UserProduct|Proxy last(string $sortedField = 'id')
* @method static UserProduct|Proxy random(array $attributes = [])
* @method static UserProduct|Proxy randomOrCreate(array $attributes = [])
* @method static UserProductRepository|RepositoryProxy repository()
* @method static UserProduct[]|Proxy[] all()
* @method static UserProduct[]|Proxy[] createMany(int $number, array|callable $attributes = [])
* @method static UserProduct[]|Proxy[] createSequence(iterable|callable $sequence)
* @method static UserProduct[]|Proxy[] findBy(array $attributes)
* @method static UserProduct[]|Proxy[] randomRange(int $min, int $max, array $attributes = [])
* @method static UserProduct[]|Proxy[] randomSet(int $number, array $attributes = [])
*/
final class UserProductFactory 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()),
'user' => UserFactory::new(),
'product' => ProductFactory::new(),
];
}

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

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

+ 63
- 0
src/Mapper/UserProductApiToEntityMapper.php Parādīt failu

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

namespace App\Mapper;

use App\ApiResource\UserProductApi;
use App\Entity\Product;
use App\Entity\User;
use App\Entity\UserProduct;
use App\Repository\UserProductRepository;
use Symfony\Bundle\SecurityBundle\Security;
use Symfonycasts\MicroMapper\AsMapper;
use Symfonycasts\MicroMapper\MapperInterface;
use Symfonycasts\MicroMapper\MicroMapperInterface;

#[AsMapper(from: UserProductApi::class, to: UserProduct::class)]
class UserProductApiToEntityMapper implements MapperInterface
{
public function __construct(
private UserProductRepository $repository,
private Security $security,
private MicroMapperInterface $microMapper,
)
{

}

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

if ($dto->id) {
$entity = $this->repository->find($dto->id);
} else {
$user = $this->security->getUser();
assert($user instanceof User);

if ($dto->product === null) {
throw new \Exception('Product missing');
}
$product = $this->microMapper->map($dto->product, Product::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]);
assert($product instanceof Product);
$entity = new UserProduct($user, $product);
}

if (!$entity) {
throw new \Exception('UserProduct not found');
}

return $entity;
}

public function populate(object $from, object $to, array $context): object
{
$dto = $from;
assert($dto instanceof UserProductApi);
$entity = $to;
assert($entity instanceof UserProduct);
return $entity;
}
}

+ 54
- 0
src/Mapper/UserProductEntityToApiMapper.php Parādīt failu

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

namespace App\Mapper;

use App\ApiResource\ProductApi;
use App\ApiResource\UserApi;
use App\ApiResource\UserProductApi;
use App\Entity\UserProduct;
use Symfonycasts\MicroMapper\AsMapper;
use Symfonycasts\MicroMapper\MapperInterface;
use Symfonycasts\MicroMapper\MicroMapperInterface;

#[AsMapper(from: UserProduct::class, to: UserProductApi::class)]
class UserProductEntityToApiMapper implements MapperInterface
{
public function __construct(
private MicroMapperInterface $microMapper
)
{
}

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

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

return $dto;
}

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

$dto->user = $this->microMapper->map($entity->getUser(), UserApi::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]);
$dto->userName = $entity->getUser()?->getFirstName()." ".$entity->getUser()?->getLastName();

$dto->product = $this->microMapper->map($entity->getProduct(), ProductApi::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]);
$dto->productName = $entity->getProduct()?->getName();

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

return $dto;
}
}

+ 48
- 0
src/Repository/UserProductRepository.php Parādīt failu

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

namespace App\Repository;

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

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

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

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

Notiek ielāde…
Atcelt
Saglabāt