| @@ -43,3 +43,9 @@ MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 | |||||
| ###> nelmio/cors-bundle ### | ###> nelmio/cors-bundle ### | ||||
| CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' | CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' | ||||
| ###< nelmio/cors-bundle ### | ###< 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.result.cache | ||||
| /phpunit.xml | /phpunit.xml | ||||
| ###< symfony/phpunit-bridge ### | ###< 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-bundle": "^2.11", | ||||
| "doctrine/doctrine-migrations-bundle": "^3.3", | "doctrine/doctrine-migrations-bundle": "^3.3", | ||||
| "doctrine/orm": "^2.17", | "doctrine/orm": "^2.17", | ||||
| "lexik/jwt-authentication-bundle": "^2.20", | |||||
| "nelmio/cors-bundle": "^2.4", | "nelmio/cors-bundle": "^2.4", | ||||
| "phpdocumentor/reflection-docblock": "^5.3", | "phpdocumentor/reflection-docblock": "^5.3", | ||||
| "phpstan/phpdoc-parser": "^1.24", | "phpstan/phpdoc-parser": "^1.24", | ||||
| @@ -16,4 +16,5 @@ return [ | |||||
| Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], | Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class => ['dev' => true, 'test' => true], | ||||
| Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true], | Zenstruck\Foundry\ZenstruckFoundryBundle::class => ['dev' => true, 'test' => true], | ||||
| Symfonycasts\MicroMapper\SymfonycastsMicroMapperBundle::class => ['all' => 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 | rfc_7807_compliant_errors: true | ||||
| event_listeners_backward_compatibility_layer: false | event_listeners_backward_compatibility_layer: false | ||||
| keep_legacy_inflector: 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: | 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: | dev: | ||||
| pattern: ^/(_(profiler|wdt)|css|images|js)/ | pattern: ^/(_(profiler|wdt)|css|images|js)/ | ||||
| security: false | security: false | ||||
| main: | |||||
| lazy: true | |||||
| api: | |||||
| pattern: ^/api/ | |||||
| stateless: true | |||||
| provider: app_user_provider | provider: app_user_provider | ||||
| jwt: ~ | |||||
| main: | |||||
| json_login: | 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 | 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 | # Easy way to control access for large sections of your site | ||||
| # Note: Only the *first* access control that matches will be used | # Note: Only the *first* access control that matches will be used | ||||
| @@ -3,4 +3,9 @@ controllers: | |||||
| path: ../src/Controller/ | path: ../src/Controller/ | ||||
| namespace: App\Controller | namespace: App\Controller | ||||
| type: attribute | 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, | paginationItemsPerPage: 10, | ||||
| // security: 'is_granted("ROLE_USER")', | |||||
| security: 'is_granted("ROLE_USER")', | |||||
| provider: EntityToDtoStateProvider::class, | provider: EntityToDtoStateProvider::class, | ||||
| processor: EntityClassDtoStateProcessor::class, | processor: EntityClassDtoStateProcessor::class, | ||||
| stateOptions: new Options(entityClass: Posting::class), | stateOptions: new Options(entityClass: Posting::class), | ||||
| @@ -13,7 +13,6 @@ use Symfony\Component\Security\Http\Attribute\CurrentUser; | |||||
| class SecurityController extends AbstractController | class SecurityController extends AbstractController | ||||
| { | { | ||||
| #[Route('/login', name: 'app_login', methods: ['POST'])] | #[Route('/login', name: 'app_login', methods: ['POST'])] | ||||
| #[Api] | |||||
| public function login(IriConverterInterface $iriConverter, #[CurrentUser] $user = null): Response | public function login(IriConverterInterface $iriConverter, #[CurrentUser] $user = null): Response | ||||
| { | { | ||||
| if (!$user) { | 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; | namespace App\DataFixtures; | ||||
| use App\Factory\PartnerFactory; | |||||
| use App\Factory\PostingFactory; | use App\Factory\PostingFactory; | ||||
| use App\Factory\UserFactory; | use App\Factory\UserFactory; | ||||
| use Doctrine\Bundle\FixturesBundle\Fixture; | use Doctrine\Bundle\FixturesBundle\Fixture; | ||||
| @@ -37,5 +38,7 @@ class AppFixtures extends Fixture | |||||
| 'owner' => UserFactory::random() | '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" | "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": { | "nelmio/cors-bundle": { | ||||
| "version": "2.4", | "version": "2.4", | ||||
| "recipe": { | "recipe": { | ||||