Ver código fonte

wip tasks

master
Daniel 2 anos atrás
pai
commit
8ef162ace6
13 arquivos alterados com 648 adições e 3 exclusões
  1. +11
    -1
      migrations/Version20240312084330.php
  2. +82
    -0
      src/ApiResource/TaskApi.php
  3. +2
    -0
      src/DataFixtures/AppFixtures.php
  4. +17
    -0
      src/DataFixtures/FakeValues.php
  5. +1
    -1
      src/Entity/Contact.php
  6. +159
    -0
      src/Entity/Task.php
  7. +1
    -1
      src/Entity/User.php
  8. +15
    -0
      src/Enum/PrioType.php
  9. +79
    -0
      src/Factory/TaskFactory.php
  10. +76
    -0
      src/Mapper/TaskApiToEntityMapper.php
  11. +73
    -0
      src/Mapper/TaskEntityToApiMapper.php
  12. +48
    -0
      src/Repository/TaskRepository.php
  13. +84
    -0
      tests/Functional/TaskResourceTest.php

migrations/Version20240308161707.php → migrations/Version20240312084330.php Ver arquivo

@@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240308161707 extends AbstractMigration
final class Version20240312084330 extends AbstractMigration
{
public function getDescription(): string
{
@@ -26,6 +26,7 @@ final class Version20240308161707 extends AbstractMigration
$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) 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 product (id INT AUTO_INCREMENT NOT NULL, image_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, description LONGTEXT DEFAULT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_D34A04AD3DA5256D (image_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$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 `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('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)');
@@ -36,6 +37,10 @@ final class Version20240308161707 extends AbstractMigration
$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)');
$this->addSql('ALTER TABLE product ADD CONSTRAINT FK_D34A04AD3DA5256D FOREIGN KEY (image_id) REFERENCES media_object (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE task ADD CONSTRAINT FK_527EDB25B03A8386 FOREIGN KEY (created_by_id) REFERENCES `user` (id)');
$this->addSql('ALTER TABLE task ADD CONSTRAINT FK_527EDB25F4BD7827 FOREIGN KEY (assigned_to_id) REFERENCES `user` (id)');
$this->addSql('ALTER TABLE task ADD CONSTRAINT FK_527EDB259393F8FE FOREIGN KEY (partner_id) REFERENCES partner (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE task ADD CONSTRAINT FK_527EDB25E7A1254A FOREIGN KEY (contact_id) REFERENCES contact (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE `user` ADD CONSTRAINT FK_8D93D6493DA5256D FOREIGN KEY (image_id) REFERENCES media_object (id) ON DELETE SET NULL');
}

@@ -51,6 +56,10 @@ final class Version20240308161707 extends AbstractMigration
$this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D739393F8FE');
$this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D73E7A1254A');
$this->addSql('ALTER TABLE product DROP FOREIGN KEY FK_D34A04AD3DA5256D');
$this->addSql('ALTER TABLE task DROP FOREIGN KEY FK_527EDB25B03A8386');
$this->addSql('ALTER TABLE task DROP FOREIGN KEY FK_527EDB25F4BD7827');
$this->addSql('ALTER TABLE task DROP FOREIGN KEY FK_527EDB259393F8FE');
$this->addSql('ALTER TABLE task DROP FOREIGN KEY FK_527EDB25E7A1254A');
$this->addSql('ALTER TABLE `user` DROP FOREIGN KEY FK_8D93D6493DA5256D');
$this->addSql('DROP TABLE comment');
$this->addSql('DROP TABLE contact');
@@ -58,6 +67,7 @@ final class Version20240308161707 extends AbstractMigration
$this->addSql('DROP TABLE partner');
$this->addSql('DROP TABLE posting');
$this->addSql('DROP TABLE product');
$this->addSql('DROP TABLE task');
$this->addSql('DROP TABLE `user`');
}
}

+ 82
- 0
src/ApiResource/TaskApi.php Ver arquivo

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


namespace App\ApiResource;

use ApiPlatform\Doctrine\Orm\State\Options;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Delete;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use App\Entity\Task;
use App\Enum\PrioType;
use App\State\EntityClassDtoStateProcessor;
use App\State\EntityToDtoStateProvider;
use Symfony\Component\Validator\Constraints as Assert;

#[ApiResource(
shortName: 'Task',
operations: [
new Get(
security: 'is_granted("ROLE_USER")'
),
new GetCollection(
security: 'is_granted("ROLE_USER")'
),
new Post(
security: 'is_granted("ROLE_USER")',
validationContext: ['groups' => ['Default', 'postValidation']]
),
new Patch(
security: 'is_granted("is_granted("EDIT", object)")'
),
new Delete(
security: 'is_granted("ROLE_USER")',
)
],
security: 'is_granted("ROLE_USER")',
provider: EntityToDtoStateProvider::class,
processor: EntityClassDtoStateProcessor::class,
stateOptions: new Options(entityClass: Task::class),

)]
class TaskApi
{
#[ApiProperty(readable: false, writable: false, identifier: true)]
public ?int $id = null;

#[Assert\NotBlank]
public ?string $headline = null;

#[Assert\NotBlank]
public ?string $description = null;

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

#[Assert\NotBlank]
public ?UserApi $assignedTo = null;

#[Assert\NotBlank]
public ?\DateTimeImmutable $dueAt = null;

public ?PartnerApi $partner = null;

public ?ContactApi $contact = null;

#[Assert\NotBlank]
public PrioType $prio;

public ?bool $completed = null;

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

}

+ 2
- 0
src/DataFixtures/AppFixtures.php Ver arquivo

@@ -11,6 +11,7 @@ use App\Factory\MediaObjectUserFactory;
use App\Factory\PartnerFactory;
use App\Factory\PostingFactory;
use App\Factory\ProductFactory;
use App\Factory\TaskFactory;
use App\Factory\UserFactory;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;
@@ -67,5 +68,6 @@ class AppFixtures extends Fixture
CommentFactory::createMany(300);
MediaObjectProductFactory::createMany(50);
ProductFactory::createMany(100);
TaskFactory::createMany(50);
}
}

+ 17
- 0
src/DataFixtures/FakeValues.php Ver arquivo

@@ -204,4 +204,21 @@ class FakeValues
'CryoVortex Acid', 'NanoRadiance Blend', 'QuantumFusion Serum', 'SynthoFlare-X', 'PlasmaQuell Acid', 'MolecularGlow Blend', 'Luminex Catalyst-X',
'ElectroWave Serum', 'CryoMyst Acid', 'NeuroFusion Elixir', 'NanoSizzle Blend-X', 'QuantumPulse Acid', 'RadiantFlare Serum', 'BioQuanta Catalyst',
];

const TASKS = [
'Teller abwaschen', 'Staubsaugen', 'Wäsche falten', 'Müll rausbringen',
'Fenster putzen', 'Boden wischen', 'Einkaufen gehen', 'Betten machen',
'Geschirrspüler ausräumen', 'Küche aufräumen', 'Blumen gießen', 'Bad reinigen',
'Briefkasten leeren', 'Rasen mähen', 'Regale abstauben', 'Post sortieren',
'Auto waschen', 'Kühlschrank sauber machen', 'Toilette putzen', 'Kleiderschrank aufräumen',
'Abendessen kochen', 'Mittagessen vorbereiten', 'Frühstück zubereiten', 'Tisch decken',
'Schuhe putzen', 'Bücher sortieren', 'Schreibtisch aufräumen', 'Pflanzen gießen',
'Handtücher wechseln', 'Kinderzimmer aufräumen', 'Fahrzeuge auftanken', 'Keller entrümpeln',
'Lampen abstauben', 'Kerzen anzünden', 'Bügelwäsche erledigen', 'Spiegel putzen',
'Mülleimer säubern', 'Arbeitsflächen desinfizieren', 'Kamin reinigen', 'Gardinen waschen',
'Kabel ordnen', 'Geschenke einpacken', 'Fahrrad pflegen', 'Teppiche saugen',
'Dachboden organisieren', 'Zimmer lüften', 'Küchengeräte reinigen', 'Garderobe aufräumen',
'Hausaufgaben machen', 'Papierkram sortieren',
];

}

+ 1
- 1
src/Entity/Contact.php Ver arquivo

@@ -30,7 +30,7 @@ class Contact
#[ORM\Column(type: Types::DATE_MUTABLE, nullable: true)]
private ?\DateTimeInterface $birthday = null;

#[ORM\ManyToOne(targetEntity: MediaObject::class)]
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true, onDelete: "SET NULL")]
private ?MediaObject $image = null;



+ 159
- 0
src/Entity/Task.php Ver arquivo

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

namespace App\Entity;

use App\Enum\PrioType;
use App\Repository\TaskRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;

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

#[ORM\Column(length: 255)]
private ?string $headline = null;

#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;

#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?User $createdBy = null;

#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: false)]
private ?User $assignedTo = null;

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

#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true, onDelete: "SET NULL")]
private ?Partner $partner = null;

#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true, onDelete: "SET NULL")]
private ?Contact $contact = null;

#[ORM\Column(type: 'string', enumType: PrioType::class)]
private PrioType $prio;

#[ORM\Column]
private ?bool $completed = null;

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

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

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

public function getHeadline(): ?string
{
return $this->headline;
}

public function setHeadline(?string $headline): void
{
$this->headline = $headline;
}

public function getDescription(): ?string
{
return $this->description;
}

public function setDescription(?string $description): void
{
$this->description = $description;
}

public function getCreatedBy(): ?User
{
return $this->createdBy;
}

public function setCreatedBy(?User $createdBy): void
{
$this->createdBy = $createdBy;
}

public function getAssignedTo(): ?User
{
return $this->assignedTo;
}

public function setAssignedTo(?User $assignedTo): void
{
$this->assignedTo = $assignedTo;
}

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

public function setDueAt(?\DateTimeImmutable $dueAt): void
{
$this->dueAt = $dueAt;
}

public function getPartner(): ?Partner
{
return $this->partner;
}

public function setPartner(?Partner $partner): void
{
$this->partner = $partner;
}

public function getContact(): ?Contact
{
return $this->contact;
}

public function setContact(?Contact $contact): void
{
$this->contact = $contact;
}

public function getPrio(): PrioType
{
return $this->prio;
}

public function setPrio(PrioType $prio): void
{
$this->prio = $prio;
}

public function getCompleted(): ?bool
{
return $this->completed;
}

public function setCompleted(?bool $completed): void
{
$this->completed = $completed;
}

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

}

+ 1
- 1
src/Entity/User.php Ver arquivo

@@ -27,7 +27,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Column(length: 255)]
private ?string $lastName = null;

#[ORM\ManyToOne(targetEntity: MediaObject::class)]
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true, onDelete: "SET NULL")]
private ?MediaObject $image = null;



+ 15
- 0
src/Enum/PrioType.php Ver arquivo

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


namespace App\Enum;


enum PrioType: string {
case Low = 'low';
case Medium = 'medium';
case High = 'high';
}

+ 79
- 0
src/Factory/TaskFactory.php Ver arquivo

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

namespace App\Factory;

use App\DataFixtures\FakeValues;
use App\Entity\Task;
use App\Enum\PrioType;
use App\Repository\TaskRepository;
use Zenstruck\Foundry\ModelFactory;
use Zenstruck\Foundry\Proxy;
use Zenstruck\Foundry\RepositoryProxy;

/**
* @extends ModelFactory<Task>
*
* @method Task|Proxy create(array|callable $attributes = [])
* @method static Task|Proxy createOne(array $attributes = [])
* @method static Task|Proxy find(object|array|mixed $criteria)
* @method static Task|Proxy findOrCreate(array $attributes)
* @method static Task|Proxy first(string $sortedField = 'id')
* @method static Task|Proxy last(string $sortedField = 'id')
* @method static Task|Proxy random(array $attributes = [])
* @method static Task|Proxy randomOrCreate(array $attributes = [])
* @method static TaskRepository|RepositoryProxy repository()
* @method static Task[]|Proxy[] all()
* @method static Task[]|Proxy[] createMany(int $number, array|callable $attributes = [])
* @method static Task[]|Proxy[] createSequence(iterable|callable $sequence)
* @method static Task[]|Proxy[] findBy(array $attributes)
* @method static Task[]|Proxy[] randomRange(int $min, int $max, array $attributes = [])
* @method static Task[]|Proxy[] randomSet(int $number, array $attributes = [])
*/
final class TaskFactory 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
{
$randomBoolean = ContactFactory::count() > 0 && (bool)random_int(0, 1);
return [
'headline' => self::faker()->randomElement(FakeValues::TASKS),
'description' => self::faker()->sentence(),
'createdBy' => UserFactory::new(),
'assignedTo' => UserFactory::random(),
'partner' => PartnerFactory::random(),
'contact' => $randomBoolean ? ContactFactory::random() : null,
'dueAt' => \DateTimeImmutable::createFromMutable(self::faker()->dateTime()),
'completed' => self::faker()->boolean(),
'prio' => self::faker()->randomElement(PrioType::cases()),
];
}

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

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

+ 76
- 0
src/Mapper/TaskApiToEntityMapper.php Ver arquivo

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

namespace App\Mapper;

use App\ApiResource\TaskApi;
use App\Entity\Contact;
use App\Entity\Partner;
use App\Entity\Task;
use App\Entity\User;
use App\Repository\TaskRepository;
use Symfony\Bundle\SecurityBundle\Security;
use Symfonycasts\MicroMapper\AsMapper;
use Symfonycasts\MicroMapper\MapperInterface;
use Symfonycasts\MicroMapper\MicroMapperInterface;

#[AsMapper(from: TaskApi::class, to: Task::class)]
class TaskApiToEntityMapper implements MapperInterface
{
public function __construct(
private TaskRepository $repository,
private Security $security,
private MicroMapperInterface $microMapper,
)
{

}

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

$assignedTo = $this->microMapper->map($dto->assignedTo, User::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]);

if ($dto->id) {
$entity = $this->repository->find($dto->id);
if (!$entity) {
throw new \Exception('Task not found');
}
$entity->setAssignedTo($assignedTo);
} else {
$user = $this->security->getUser();
assert($user instanceof User);
assert($assignedTo instanceof User);
$entity = new Task($user, $assignedTo);
}

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

return $entity;
}

public function populate(object $from, object $to, array $context): object
{
$dto = $from;
assert($dto instanceof TaskApi);
$entity = $to;
assert($entity instanceof Task);
$entity->setHeadline($dto->headline);
$entity->setDescription($dto->description);
$entity->setDueAt($dto->dueAt);
$entity->setPartner($this->microMapper->map($dto->partner, Partner::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]));
$entity->setContact($this->microMapper->map($dto->contact, Contact::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]));
$entity->setPrio($dto->prio);
$entity->setCompleted($dto->completed);
return $entity;
}
}

+ 73
- 0
src/Mapper/TaskEntityToApiMapper.php Ver arquivo

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

namespace App\Mapper;

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

#[AsMapper(from: Task::class, to: TaskApi::class)]
class TaskEntityToApiMapper implements MapperInterface
{
public function __construct(
private MicroMapperInterface $microMapper
)
{
}

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

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

return $dto;
}

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

$dto->headline = $entity->getHeadline();
$dto->description = $entity->getDescription();
$dto->createdBy = $this->microMapper->map($entity->getCreatedBy(), UserApi::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]);
$dto->assignedTo = $this->microMapper->map($entity->getAssignedTo(), UserApi::class, [
MicroMapperInterface::MAX_DEPTH => 1,
]);
$dto->dueAt = $entity->getDueAt();

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

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

$dto->prio = $entity->getPrio();
$dto->completed = $entity->getCompleted();
$dto->createdAt = $entity->getCreatedAt();

return $dto;
}
}

+ 48
- 0
src/Repository/TaskRepository.php Ver arquivo

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

namespace App\Repository;

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

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

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

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

+ 84
- 0
tests/Functional/TaskResourceTest.php Ver arquivo

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


namespace App\Tests\Functional;

use App\Enum\PartnerType;
use App\Factory\CommentFactory;
use App\Factory\ContactFactory;
use App\Factory\MediaObjectLogoFactory;
use App\Factory\MediaObjectContactFactory;
use App\Factory\PartnerFactory;
use App\Factory\PostingFactory;
use App\Factory\UserFactory;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Zenstruck\Browser\Test\HasBrowser;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;

class TaskResourceTest extends KernelTestCase
{
use HasBrowser;
use ResetDatabase;
use Factories;

private JWTTokenManagerInterface $JWTManager;

protected function setUp(): void
{
parent::setUp();
$this->JWTManager = self::getContainer()->get('lexik_jwt_authentication.jwt_manager');
}

public function testPostTask(): void
{
$user = UserFactory::createOne(
[
'firstName' => 'Peter',
'lastName' => 'Test',
'password' => 'test',
'email' => 'peter@test.de',
]
);
$partner = PartnerFactory::createOne();
$contact = ContactFactory::createOne();

$token = $this->JWTManager->create($user->object());

$this->browser()
->post('/api/tasks' , [
'json' => [
'headline' => 'new task',
'description' => 'this is what is to do...',
'assignedTo' => '/api/users/' . $user->getId(),
'dueAt'=> "2024-03-12T08:57:39.892Z",
'partner'=> "/api/partners/" . $partner->getId(),
'contact'=> "/api/contacts/" . $contact->getId(),
'prio'=> "low",
'completed'=> false,
],
'headers' => [
'Authorization' => 'Bearer ' . $token,
]
])
->assertSuccessful()
;

$this->browser()
->get('/api/tasks', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
],
])
->assertSuccessful()
->assertJsonMatches('"hydra:totalItems"', 1)
->assertJsonMatches('"hydra:member"[0].headline', 'new task')
;

}
}

Carregando…
Cancelar
Salvar