| @@ -43,3 +43,9 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 | |||
| ###> nelmio/cors-bundle ### | |||
| CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' | |||
| ###< nelmio/cors-bundle ### | |||
| ###> lexik/jwt-authentication-bundle ### | |||
| JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem | |||
| JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem | |||
| JWT_PASSPHRASE=dd92770a0c99773cc99cf1bdc4bd425986dacbcde1bc753e9934614aa6f364b6 | |||
| ###< lexik/jwt-authentication-bundle ### | |||
| @@ -18,4 +18,7 @@ | |||
| .phpunit.result.cache | |||
| /phpunit.xml | |||
| ###< symfony/phpunit-bridge ### | |||
| /.idea | |||
| /.idea | |||
| ###> lexik/jwt-authentication-bundle ### | |||
| /config/jwt/*.pem | |||
| ###< lexik/jwt-authentication-bundle ### | |||
| @@ -11,6 +11,7 @@ | |||
| "doctrine/doctrine-bundle": "^2.11", | |||
| "doctrine/doctrine-migrations-bundle": "^3.3", | |||
| "doctrine/orm": "^2.17", | |||
| "lexik/jwt-authentication-bundle": "^2.20", | |||
| "nelmio/cors-bundle": "^2.4", | |||
| "phpdocumentor/reflection-docblock": "^5.3", | |||
| "phpstan/phpdoc-parser": "^1.24", | |||
| @@ -16,4 +16,5 @@ return [ | |||
| Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], | |||
| Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true], | |||
| Symfonycasts\MicroMapper\SymfonycastsMicroMapperBundle::class => ['all' => true], | |||
| Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true], | |||
| ]; | |||
| @@ -19,3 +19,9 @@ api_platform: | |||
| rfc_7807_compliant_errors: true | |||
| event_listeners_backward_compatibility_layer: false | |||
| keep_legacy_inflector: false | |||
| swagger: | |||
| api_keys: | |||
| JWT: | |||
| name: Authorization | |||
| type: header | |||
| @@ -0,0 +1,5 @@ | |||
| lexik_jwt_authentication: | |||
| secret_key: '%env(resolve:JWT_SECRET_KEY)%' | |||
| public_key: '%env(resolve:JWT_PUBLIC_KEY)%' | |||
| pass_phrase: '%env(JWT_PASSPHRASE)%' | |||
| token_ttl: 3600 | |||
| @@ -1,19 +1,35 @@ | |||
| nelmio_cors: | |||
| defaults: | |||
| origin_regex: true | |||
| # allow_origin: ['%env(CORS_ALLOW_ORIGIN)%'] | |||
| # allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE'] | |||
| # allow_headers: ['Content-Type', 'Authorization'] | |||
| # expose_headers: ['Link'] | |||
| expose_headers: ['*'] | |||
| allow_origin: [ '*' ] | |||
| allow_headers: [ '*' ] | |||
| allow_methods: ['GET', 'OPTIONS', 'POST', 'PATCH', 'DELETE'] | |||
| max_age: 3600 | |||
| paths: | |||
| '^/': null | |||
| # '^/api/': | |||
| # allow_origin: [ '*' ] | |||
| # allow_headers: [ '*' ] | |||
| # allow_methods: [ '*' ] | |||
| # max_age: 3600 | |||
| defaults: | |||
| allow_credentials: true | |||
| allow_origin: ['*'] | |||
| allow_headers: ['*'] | |||
| allow_methods: ['POST', 'PATCH', 'GET', 'DELETE', 'OPTIONS'] | |||
| expose_headers: [] | |||
| max_age: 3600 | |||
| hosts: [] | |||
| origin_regex: true | |||
| paths: | |||
| # Important api settings : | |||
| # Access-Control-Request-Method | |||
| '^/': ~ | |||
| #nelmio_cors: | |||
| # defaults: | |||
| # allow_credentials: true | |||
| # origin_regex: false | |||
| ## allow_origin: ['%env(CORS_ALLOW_ORIGIN)%'] | |||
| ## allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE'] | |||
| ## allow_headers: ['Content-Type', 'Authorization'] | |||
| ## expose_headers: ['Link'] | |||
| # allow_origin: [ '*' ] | |||
| # allow_methods: ['*'] | |||
| ## expose_headers: ['*'] | |||
| # allow_headers: [ '*' ] | |||
| # max_age: 3600 | |||
| # paths: | |||
| # '^/': null | |||
| ## '^/api/': | |||
| ## allow_origin: [ '*' ] | |||
| ## allow_headers: [ '*' ] | |||
| ## allow_methods: [ '*' ] | |||
| ## max_age: 3600 | |||
| @@ -13,19 +13,18 @@ security: | |||
| dev: | |||
| pattern: ^/(_(profiler|wdt)|css|images|js)/ | |||
| security: false | |||
| main: | |||
| lazy: true | |||
| api: | |||
| pattern: ^/api/ | |||
| stateless: true | |||
| provider: app_user_provider | |||
| jwt: ~ | |||
| main: | |||
| json_login: | |||
| check_path: app_login | |||
| username_path: username | |||
| check_path: auth # The name in routes.yaml is enough for mapping | |||
| username_path: email | |||
| password_path: password | |||
| # activate different ways to authenticate | |||
| # https://symfony.com/doc/current/security.html#the-firewall | |||
| # https://symfony.com/doc/current/security/impersonating_user.html | |||
| # switch_user: true | |||
| success_handler: lexik_jwt_authentication.handler.authentication_success | |||
| failure_handler: lexik_jwt_authentication.handler.authentication_failure | |||
| # Easy way to control access for large sections of your site | |||
| # Note: Only the *first* access control that matches will be used | |||
| @@ -3,4 +3,9 @@ controllers: | |||
| path: ../src/Controller/ | |||
| namespace: App\Controller | |||
| type: attribute | |||
| stateless: false | |||
| stateless: true | |||
| # api/config/routes.yaml | |||
| auth: | |||
| path: /auth | |||
| methods: ['POST'] | |||
| @@ -1,35 +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 Version20231214140601 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 posting (id INT AUTO_INCREMENT NOT NULL, owner_id INT NOT NULL, message LONGTEXT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_BD275D737E3C61F9 (owner_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 posting ADD CONSTRAINT FK_BD275D737E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id)'); | |||
| } | |||
| public function down(Schema $schema): void | |||
| { | |||
| // this down() migration is auto-generated, please modify it to your needs | |||
| $this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D737E3C61F9'); | |||
| $this->addSql('DROP TABLE posting'); | |||
| $this->addSql('DROP TABLE `user`'); | |||
| } | |||
| } | |||
| @@ -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 Version20231221143009 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 api_token (id INT AUTO_INCREMENT NOT NULL, owned_by_id INT NOT NULL, expires_at DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', token VARCHAR(68) NOT NULL, scopes JSON NOT NULL COMMENT \'(DC2Type:json)\', INDEX IDX_7BA2F5EB5E70BCD7 (owned_by_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); | |||
| $this->addSql('CREATE TABLE partner (id INT AUTO_INCREMENT NOT 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)\', logo VARCHAR(255) DEFAULT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); | |||
| $this->addSql('CREATE TABLE partner_contact (id INT AUTO_INCREMENT NOT NULL, partner_id INT NOT NULL, first_name VARCHAR(255) NOT NULL, last_name VARCHAR(255) NOT NULL, birthday DATE DEFAULT NULL, picture VARCHAR(255) 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_8B8885259393F8FE (partner_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, message LONGTEXT NOT NULL, created_at DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', INDEX IDX_BD275D737E3C61F9 (owner_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 api_token ADD CONSTRAINT FK_7BA2F5EB5E70BCD7 FOREIGN KEY (owned_by_id) REFERENCES `user` (id)'); | |||
| $this->addSql('ALTER TABLE partner_contact ADD CONSTRAINT FK_8B8885259393F8FE FOREIGN KEY (partner_id) REFERENCES partner (id)'); | |||
| $this->addSql('ALTER TABLE posting ADD CONSTRAINT FK_BD275D737E3C61F9 FOREIGN KEY (owner_id) REFERENCES `user` (id)'); | |||
| } | |||
| public function down(Schema $schema): void | |||
| { | |||
| // this down() migration is auto-generated, please modify it to your needs | |||
| $this->addSql('ALTER TABLE api_token DROP FOREIGN KEY FK_7BA2F5EB5E70BCD7'); | |||
| $this->addSql('ALTER TABLE partner_contact DROP FOREIGN KEY FK_8B8885259393F8FE'); | |||
| $this->addSql('ALTER TABLE posting DROP FOREIGN KEY FK_BD275D737E3C61F9'); | |||
| $this->addSql('DROP TABLE api_token'); | |||
| $this->addSql('DROP TABLE partner'); | |||
| $this->addSql('DROP TABLE partner_contact'); | |||
| $this->addSql('DROP TABLE posting'); | |||
| $this->addSql('DROP TABLE `user`'); | |||
| } | |||
| } | |||
| @@ -39,7 +39,7 @@ use Symfony\Component\Validator\Constraints\NotBlank; | |||
| ) | |||
| ], | |||
| paginationItemsPerPage: 10, | |||
| // security: 'is_granted("ROLE_USER")', | |||
| security: 'is_granted("ROLE_USER")', | |||
| provider: EntityToDtoStateProvider::class, | |||
| processor: EntityClassDtoStateProcessor::class, | |||
| stateOptions: new Options(entityClass: Posting::class), | |||
| @@ -13,7 +13,6 @@ use Symfony\Component\Security\Http\Attribute\CurrentUser; | |||
| class SecurityController extends AbstractController | |||
| { | |||
| #[Route('/login', name: 'app_login', methods: ['POST'])] | |||
| #[Api] | |||
| public function login(IriConverterInterface $iriConverter, #[CurrentUser] $user = null): Response | |||
| { | |||
| if (!$user) { | |||
| @@ -0,0 +1,28 @@ | |||
| <?php | |||
| /** | |||
| * @author Daniel Knudsen <d.knudsen@spawntree.de> | |||
| * @date 22.12.23 | |||
| */ | |||
| namespace App\Controller; | |||
| use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; | |||
| use Symfony\Component\HttpFoundation\JsonResponse; | |||
| use Symfony\Component\Routing\Attribute\Route; | |||
| use Symfony\Component\Security\Http\Attribute\IsGranted; | |||
| class TesController extends AbstractController | |||
| { | |||
| #[Route('/test')] | |||
| #[IsGranted('ROLE_USER')] | |||
| public function test() { | |||
| return new JsonResponse('jo'); | |||
| } | |||
| #[Route('/foo')] | |||
| public function test2() { | |||
| return new JsonResponse('nenene'); | |||
| } | |||
| } | |||
| @@ -2,6 +2,7 @@ | |||
| namespace App\DataFixtures; | |||
| use App\Factory\PartnerFactory; | |||
| use App\Factory\PostingFactory; | |||
| use App\Factory\UserFactory; | |||
| use Doctrine\Bundle\FixturesBundle\Fixture; | |||
| @@ -37,5 +38,7 @@ class AppFixtures extends Fixture | |||
| 'owner' => UserFactory::random() | |||
| ]; | |||
| }); | |||
| //PartnerFactory::createMany(50); | |||
| } | |||
| } | |||
| @@ -0,0 +1,93 @@ | |||
| <?php | |||
| namespace App\Entity; | |||
| use App\Repository\ApiTokenRepository; | |||
| use Doctrine\ORM\Mapping as ORM; | |||
| #[ORM\Entity(repositoryClass: ApiTokenRepository::class)] | |||
| class ApiToken | |||
| { | |||
| private const PERSONAL_ACCESS_TOKEN_PREFIX = 'spt_'; | |||
| #[ORM\Id] | |||
| #[ORM\GeneratedValue] | |||
| #[ORM\Column] | |||
| private ?int $id = null; | |||
| #[ORM\ManyToOne(inversedBy: 'apiTokens')] | |||
| #[ORM\JoinColumn(nullable: false)] | |||
| private ?User $ownedBy = null; | |||
| #[ORM\Column(nullable: true)] | |||
| private ?\DateTimeImmutable $expiresAt = null; | |||
| #[ORM\Column(length: 68)] | |||
| private string $token; | |||
| #[ORM\Column] | |||
| private array $scopes = []; | |||
| public function __construct(string $tokenType = self::PERSONAL_ACCESS_TOKEN_PREFIX) | |||
| { | |||
| $this->token = $tokenType.bin2hex(random_bytes(32)); | |||
| } | |||
| public function getId(): ?int | |||
| { | |||
| return $this->id; | |||
| } | |||
| public function getOwnedBy(): ?User | |||
| { | |||
| return $this->ownedBy; | |||
| } | |||
| public function setOwnedBy(?User $ownedBy): self | |||
| { | |||
| $this->ownedBy = $ownedBy; | |||
| return $this; | |||
| } | |||
| public function getExpiresAt(): ?\DateTimeImmutable | |||
| { | |||
| return $this->expiresAt; | |||
| } | |||
| public function setExpiresAt(?\DateTimeImmutable $expiresAt): self | |||
| { | |||
| $this->expiresAt = $expiresAt; | |||
| return $this; | |||
| } | |||
| public function getToken(): ?string | |||
| { | |||
| return $this->token; | |||
| } | |||
| public function setToken(string $token): self | |||
| { | |||
| $this->token = $token; | |||
| return $this; | |||
| } | |||
| public function getScopes(): array | |||
| { | |||
| return $this->scopes; | |||
| } | |||
| public function setScopes(array $scopes): self | |||
| { | |||
| $this->scopes = $scopes; | |||
| return $this; | |||
| } | |||
| public function isValid(): bool | |||
| { | |||
| return $this->expiresAt === null || $this->expiresAt > new \DateTimeImmutable(); | |||
| } | |||
| } | |||
| @@ -0,0 +1,206 @@ | |||
| <?php | |||
| namespace App\Entity; | |||
| use App\Enum\PartnerType; | |||
| use App\Repository\PartnerRepository; | |||
| use Doctrine\Common\Collections\ArrayCollection; | |||
| use Doctrine\Common\Collections\Collection; | |||
| use Doctrine\ORM\Mapping as ORM; | |||
| #[ORM\Entity(repositoryClass: PartnerRepository::class)] | |||
| class Partner | |||
| { | |||
| #[ORM\Id] | |||
| #[ORM\GeneratedValue] | |||
| #[ORM\Column] | |||
| private ?int $id = null; | |||
| #[ORM\Column(length: 255)] | |||
| private ?string $name = null; | |||
| #[ORM\Column(type: 'string', enumType: PartnerType::class)] | |||
| private ?string $type = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $street = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $streetNo = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $zip = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $city = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $country = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $website = null; | |||
| #[ORM\Column] | |||
| private ?\DateTimeImmutable $createdAt = null; | |||
| #[ORM\OneToMany(mappedBy: 'partner', targetEntity: PartnerContact::class, orphanRemoval: true)] | |||
| private Collection $partnerContacts; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $logo = null; | |||
| public function __construct() | |||
| { | |||
| $this->createdAt = new \DateTimeImmutable(); | |||
| $this->partnerContacts = new ArrayCollection(); | |||
| } | |||
| public function getId(): ?int | |||
| { | |||
| return $this->id; | |||
| } | |||
| public function getName(): ?string | |||
| { | |||
| return $this->name; | |||
| } | |||
| public function setName(string $name): static | |||
| { | |||
| $this->name = $name; | |||
| return $this; | |||
| } | |||
| public function getType(): ?string | |||
| { | |||
| return $this->type; | |||
| } | |||
| public function setType(string $type): static | |||
| { | |||
| $this->type = $type; | |||
| return $this; | |||
| } | |||
| public function getStreet(): ?string | |||
| { | |||
| return $this->street; | |||
| } | |||
| public function setStreet(?string $street): static | |||
| { | |||
| $this->street = $street; | |||
| return $this; | |||
| } | |||
| public function getStreetNo(): ?string | |||
| { | |||
| return $this->streetNo; | |||
| } | |||
| public function setStreetNo(?string $streetNo): static | |||
| { | |||
| $this->streetNo = $streetNo; | |||
| return $this; | |||
| } | |||
| public function getZip(): ?string | |||
| { | |||
| return $this->zip; | |||
| } | |||
| public function setZip(?string $zip): static | |||
| { | |||
| $this->zip = $zip; | |||
| return $this; | |||
| } | |||
| public function getCity(): ?string | |||
| { | |||
| return $this->city; | |||
| } | |||
| public function setCity(?string $city): static | |||
| { | |||
| $this->city = $city; | |||
| return $this; | |||
| } | |||
| public function getCountry(): ?string | |||
| { | |||
| return $this->country; | |||
| } | |||
| public function setCountry(?string $country): static | |||
| { | |||
| $this->country = $country; | |||
| return $this; | |||
| } | |||
| public function getWebsite(): ?string | |||
| { | |||
| return $this->website; | |||
| } | |||
| public function setWebsite(?string $website): static | |||
| { | |||
| $this->website = $website; | |||
| return $this; | |||
| } | |||
| public function getCreatedAt(): ?\DateTimeImmutable | |||
| { | |||
| return $this->createdAt; | |||
| } | |||
| /** | |||
| * @return Collection<int, PartnerContact> | |||
| */ | |||
| public function getPartnerContacts(): Collection | |||
| { | |||
| return $this->partnerContacts; | |||
| } | |||
| public function addPartnerContact(PartnerContact $partnerContact): static | |||
| { | |||
| if (!$this->partnerContacts->contains($partnerContact)) { | |||
| $this->partnerContacts->add($partnerContact); | |||
| $partnerContact->setPartner($this); | |||
| } | |||
| return $this; | |||
| } | |||
| public function removePartnerContact(PartnerContact $partnerContact): static | |||
| { | |||
| if ($this->partnerContacts->removeElement($partnerContact)) { | |||
| // set the owning side to null (unless already changed) | |||
| if ($partnerContact->getPartner() === $this) { | |||
| $partnerContact->setPartner(null); | |||
| } | |||
| } | |||
| return $this; | |||
| } | |||
| public function getLogo(): ?string | |||
| { | |||
| return $this->logo; | |||
| } | |||
| public function setLogo(?string $logo): static | |||
| { | |||
| $this->logo = $logo; | |||
| return $this; | |||
| } | |||
| } | |||
| @@ -0,0 +1,162 @@ | |||
| <?php | |||
| namespace App\Entity; | |||
| use App\Repository\PartnerContactRepository; | |||
| use Doctrine\DBAL\Types\Types; | |||
| use Doctrine\ORM\Mapping as ORM; | |||
| #[ORM\Entity(repositoryClass: PartnerContactRepository::class)] | |||
| class PartnerContact | |||
| { | |||
| #[ORM\Id] | |||
| #[ORM\GeneratedValue] | |||
| #[ORM\Column] | |||
| private ?int $id = null; | |||
| #[ORM\Column(length: 255)] | |||
| private ?string $firstName = null; | |||
| #[ORM\Column(length: 255)] | |||
| private ?string $lastName = null; | |||
| #[ORM\ManyToOne(inversedBy: 'partnerContacts')] | |||
| #[ORM\JoinColumn(nullable: false)] | |||
| private ?Partner $partner = null; | |||
| #[ORM\Column(type: Types::DATE_MUTABLE, nullable: true)] | |||
| private ?\DateTimeInterface $birthday = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $picture = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $position = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $phone = null; | |||
| #[ORM\Column(length: 255, nullable: true)] | |||
| private ?string $email = null; | |||
| #[ORM\Column] | |||
| private ?\DateTimeImmutable $createdAt = null; | |||
| public function __construct() | |||
| { | |||
| $this->createdAt = new \DateTimeImmutable(); | |||
| } | |||
| public function getId(): ?int | |||
| { | |||
| return $this->id; | |||
| } | |||
| public function getFirstName(): ?string | |||
| { | |||
| return $this->firstName; | |||
| } | |||
| public function setFirstName(string $firstName): static | |||
| { | |||
| $this->firstName = $firstName; | |||
| return $this; | |||
| } | |||
| public function getLastName(): ?string | |||
| { | |||
| return $this->lastName; | |||
| } | |||
| public function setLastName(string $lastName): static | |||
| { | |||
| $this->lastName = $lastName; | |||
| return $this; | |||
| } | |||
| public function getPartner(): ?Partner | |||
| { | |||
| return $this->partner; | |||
| } | |||
| public function setPartner(?Partner $partner): static | |||
| { | |||
| $this->partner = $partner; | |||
| return $this; | |||
| } | |||
| public function getBirthday(): ?\DateTimeInterface | |||
| { | |||
| return $this->birthday; | |||
| } | |||
| public function setBirthday(?\DateTimeInterface $birthday): static | |||
| { | |||
| $this->birthday = $birthday; | |||
| return $this; | |||
| } | |||
| public function getPicture(): ?string | |||
| { | |||
| return $this->picture; | |||
| } | |||
| public function setPicture(?string $picture): static | |||
| { | |||
| $this->picture = $picture; | |||
| return $this; | |||
| } | |||
| public function getPosition(): ?string | |||
| { | |||
| return $this->position; | |||
| } | |||
| public function setPosition(?string $position): static | |||
| { | |||
| $this->position = $position; | |||
| return $this; | |||
| } | |||
| public function getPhone(): ?string | |||
| { | |||
| return $this->phone; | |||
| } | |||
| public function setPhone(?string $phone): static | |||
| { | |||
| $this->phone = $phone; | |||
| return $this; | |||
| } | |||
| public function getEmail(): ?string | |||
| { | |||
| return $this->email; | |||
| } | |||
| public function setEmail(?string $email): static | |||
| { | |||
| $this->email = $email; | |||
| return $this; | |||
| } | |||
| public function getCreatedAt(): ?\DateTimeImmutable | |||
| { | |||
| return $this->createdAt; | |||
| } | |||
| public function setCreatedAt(\DateTimeImmutable $createdAt): static | |||
| { | |||
| $this->createdAt = $createdAt; | |||
| return $this; | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| <?php | |||
| /** | |||
| * @author Daniel Knudsen <d.knudsen@spawntree.de> | |||
| * @date 20.12.23 | |||
| */ | |||
| namespace App\Enum; | |||
| enum PartnerType: string { | |||
| case Customer = 'customer'; | |||
| case Supplier = 'supplier'; | |||
| case Service = 'service'; | |||
| } | |||
| @@ -0,0 +1,76 @@ | |||
| <?php | |||
| namespace App\Factory; | |||
| use App\Entity\Partner; | |||
| use App\Enum\PartnerType; | |||
| use App\Repository\PartnerRepository; | |||
| use Zenstruck\Foundry\ModelFactory; | |||
| use Zenstruck\Foundry\Proxy; | |||
| use Zenstruck\Foundry\RepositoryProxy; | |||
| /** | |||
| * @extends ModelFactory<Partner> | |||
| * | |||
| * @method Partner|Proxy create(array|callable $attributes = []) | |||
| * @method static Partner|Proxy createOne(array $attributes = []) | |||
| * @method static Partner|Proxy find(object|array|mixed $criteria) | |||
| * @method static Partner|Proxy findOrCreate(array $attributes) | |||
| * @method static Partner|Proxy first(string $sortedField = 'id') | |||
| * @method static Partner|Proxy last(string $sortedField = 'id') | |||
| * @method static Partner|Proxy random(array $attributes = []) | |||
| * @method static Partner|Proxy randomOrCreate(array $attributes = []) | |||
| * @method static PartnerRepository|RepositoryProxy repository() | |||
| * @method static Partner[]|Proxy[] all() | |||
| * @method static Partner[]|Proxy[] createMany(int $number, array|callable $attributes = []) | |||
| * @method static Partner[]|Proxy[] createSequence(iterable|callable $sequence) | |||
| * @method static Partner[]|Proxy[] findBy(array $attributes) | |||
| * @method static Partner[]|Proxy[] randomRange(int $min, int $max, array $attributes = []) | |||
| * @method static Partner[]|Proxy[] randomSet(int $number, array $attributes = []) | |||
| */ | |||
| final class PartnerFactory 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 [ | |||
| 'name' => self::faker()->text(255), | |||
| 'type' => self::faker()->randomElement(PartnerType::cases()), | |||
| 'street' => self::faker()->text(255), | |||
| 'streetNo' => self::faker()->text(255), | |||
| 'zip' => self::faker()->text(255), | |||
| 'city' => self::faker()->text(255), | |||
| 'country' => self::faker()->text(255), | |||
| 'website' => self::faker()->text(255), | |||
| ]; | |||
| } | |||
| /** | |||
| * @see https://symfony.com/bundles/ZenstruckFoundryBundle/current/index.html#initialization | |||
| */ | |||
| protected function initialize(): self | |||
| { | |||
| return $this | |||
| // ->afterInstantiate(function(Partner $partner): void {}) | |||
| ; | |||
| } | |||
| protected static function getClass(): string | |||
| { | |||
| return Partner::class; | |||
| } | |||
| } | |||
| @@ -0,0 +1,66 @@ | |||
| <?php | |||
| namespace App\Repository; | |||
| use App\Entity\ApiToken; | |||
| use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; | |||
| use Doctrine\Persistence\ManagerRegistry; | |||
| /** | |||
| * @extends ServiceEntityRepository<ApiToken> | |||
| * | |||
| * @method ApiToken|null find($id, $lockMode = null, $lockVersion = null) | |||
| * @method ApiToken|null findOneBy(array $criteria, array $orderBy = null) | |||
| * @method ApiToken[] findAll() | |||
| * @method ApiToken[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) | |||
| */ | |||
| class ApiTokenRepository extends ServiceEntityRepository | |||
| { | |||
| public function __construct(ManagerRegistry $registry) | |||
| { | |||
| parent::__construct($registry, ApiToken::class); | |||
| } | |||
| public function save(ApiToken $entity, bool $flush = false): void | |||
| { | |||
| $this->getEntityManager()->persist($entity); | |||
| if ($flush) { | |||
| $this->getEntityManager()->flush(); | |||
| } | |||
| } | |||
| public function remove(ApiToken $entity, bool $flush = false): void | |||
| { | |||
| $this->getEntityManager()->remove($entity); | |||
| if ($flush) { | |||
| $this->getEntityManager()->flush(); | |||
| } | |||
| } | |||
| // /** | |||
| // * @return ApiToken[] Returns an array of ApiToken objects | |||
| // */ | |||
| // public function findByExampleField($value): array | |||
| // { | |||
| // return $this->createQueryBuilder('a') | |||
| // ->andWhere('a.exampleField = :val') | |||
| // ->setParameter('val', $value) | |||
| // ->orderBy('a.id', 'ASC') | |||
| // ->setMaxResults(10) | |||
| // ->getQuery() | |||
| // ->getResult() | |||
| // ; | |||
| // } | |||
| // public function findOneBySomeField($value): ?ApiToken | |||
| // { | |||
| // return $this->createQueryBuilder('a') | |||
| // ->andWhere('a.exampleField = :val') | |||
| // ->setParameter('val', $value) | |||
| // ->getQuery() | |||
| // ->getOneOrNullResult() | |||
| // ; | |||
| // } | |||
| } | |||
| @@ -0,0 +1,48 @@ | |||
| <?php | |||
| namespace App\Repository; | |||
| use App\Entity\PartnerContact; | |||
| use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; | |||
| use Doctrine\Persistence\ManagerRegistry; | |||
| /** | |||
| * @extends ServiceEntityRepository<PartnerContact> | |||
| * | |||
| * @method PartnerContact|null find($id, $lockMode = null, $lockVersion = null) | |||
| * @method PartnerContact|null findOneBy(array $criteria, array $orderBy = null) | |||
| * @method PartnerContact[] findAll() | |||
| * @method PartnerContact[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) | |||
| */ | |||
| class PartnerContactRepository extends ServiceEntityRepository | |||
| { | |||
| public function __construct(ManagerRegistry $registry) | |||
| { | |||
| parent::__construct($registry, PartnerContact::class); | |||
| } | |||
| // /** | |||
| // * @return PartnerContact[] Returns an array of PartnerContact objects | |||
| // */ | |||
| // public function findByExampleField($value): array | |||
| // { | |||
| // return $this->createQueryBuilder('p') | |||
| // ->andWhere('p.exampleField = :val') | |||
| // ->setParameter('val', $value) | |||
| // ->orderBy('p.id', 'ASC') | |||
| // ->setMaxResults(10) | |||
| // ->getQuery() | |||
| // ->getResult() | |||
| // ; | |||
| // } | |||
| // public function findOneBySomeField($value): ?PartnerContact | |||
| // { | |||
| // return $this->createQueryBuilder('p') | |||
| // ->andWhere('p.exampleField = :val') | |||
| // ->setParameter('val', $value) | |||
| // ->getQuery() | |||
| // ->getOneOrNullResult() | |||
| // ; | |||
| // } | |||
| } | |||
| @@ -0,0 +1,48 @@ | |||
| <?php | |||
| namespace App\Repository; | |||
| use App\Entity\Partner; | |||
| use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository; | |||
| use Doctrine\Persistence\ManagerRegistry; | |||
| /** | |||
| * @extends ServiceEntityRepository<Partner> | |||
| * | |||
| * @method Partner|null find($id, $lockMode = null, $lockVersion = null) | |||
| * @method Partner|null findOneBy(array $criteria, array $orderBy = null) | |||
| * @method Partner[] findAll() | |||
| * @method Partner[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) | |||
| */ | |||
| class PartnerRepository extends ServiceEntityRepository | |||
| { | |||
| public function __construct(ManagerRegistry $registry) | |||
| { | |||
| parent::__construct($registry, Partner::class); | |||
| } | |||
| // /** | |||
| // * @return Partner[] Returns an array of Partner objects | |||
| // */ | |||
| // public function findByExampleField($value): array | |||
| // { | |||
| // return $this->createQueryBuilder('p') | |||
| // ->andWhere('p.exampleField = :val') | |||
| // ->setParameter('val', $value) | |||
| // ->orderBy('p.id', 'ASC') | |||
| // ->setMaxResults(10) | |||
| // ->getQuery() | |||
| // ->getResult() | |||
| // ; | |||
| // } | |||
| // public function findOneBySomeField($value): ?Partner | |||
| // { | |||
| // return $this->createQueryBuilder('p') | |||
| // ->andWhere('p.exampleField = :val') | |||
| // ->setParameter('val', $value) | |||
| // ->getQuery() | |||
| // ->getOneOrNullResult() | |||
| // ; | |||
| // } | |||
| } | |||
| @@ -52,6 +52,18 @@ | |||
| "migrations/.gitignore" | |||
| ] | |||
| }, | |||
| "lexik/jwt-authentication-bundle": { | |||
| "version": "2.20", | |||
| "recipe": { | |||
| "repo": "github.com/symfony/recipes", | |||
| "branch": "main", | |||
| "version": "2.5", | |||
| "ref": "e9481b233a11ef7e15fe055a2b21fd3ac1aa2bb7" | |||
| }, | |||
| "files": [ | |||
| "config/packages/lexik_jwt_authentication.yaml" | |||
| ] | |||
| }, | |||
| "nelmio/cors-bundle": { | |||
| "version": "2.4", | |||
| "recipe": { | |||