diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml new file mode 100644 index 00000000..8fa0c48a --- /dev/null +++ b/.github/workflows/static-analysis.yml @@ -0,0 +1,46 @@ +on: + # - pull_request + - push + +name: static analysis + +jobs: + mutation: + name: PHP ${{ matrix.php }}-${{ matrix.os }} + + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: + - ubuntu-latest + + php: + - "7.4" + + steps: + - name: Checkout + uses: actions/checkout@v2.3.4 + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: "${{ matrix.php }}" + tools: composer:v2, cs2pr + coverage: none + + - name: Determine composer cache directory + run: echo "COMPOSER_CACHE_DIR=$(composer config cache-dir)" >> $GITHUB_ENV + + - name: Cache dependencies installed with composer + uses: actions/cache@v2 + with: + path: ${{ env.COMPOSER_CACHE_DIR }} + key: php${{ matrix.php }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: | + php${{ matrix.php }}-composer- + - name: Install dependencies with composer + run: composer update --prefer-dist --no-interaction --no-progress --optimize-autoloader --ansi + + - name: Static analysis + run: vendor/bin/psalm --no-cache --output-format=github --show-info=false --threads=4 diff --git a/bin/doctrine b/bin/doctrine index e67edec7..33b919c9 100644 --- a/bin/doctrine +++ b/bin/doctrine @@ -1,3 +1,4 @@ +#!/usr/bin/env php addSql('CREATE TABLE contact_message (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', email VARCHAR(150) NOT NULL, name VARCHAR(150) NOT NULL, subject LONGTEXT NOT NULL, message LONGTEXT NOT NULL, platform LONGTEXT NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', identity VARCHAR(191) NOT NULL, password VARCHAR(191) NOT NULL, status ENUM(\'pending\', \'active\'), isDeleted TINYINT(1) NOT NULL, hash VARCHAR(64) NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX UNIQ_8D93D6496A95E9C4 (identity), UNIQUE INDEX UNIQ_8D93D649D1B862B8 (hash), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user_roles (userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', roleUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', INDEX IDX_54FCD59FD73087E9 (userUuid), INDEX IDX_54FCD59F88446210 (roleUuid), PRIMARY KEY(userUuid, roleUuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user_avatar (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', name VARCHAR(191) NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', UNIQUE INDEX UNIQ_73256912D73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user_detail (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', firstName VARCHAR(191) DEFAULT NULL, lastName VARCHAR(191) DEFAULT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', UNIQUE INDEX UNIQ_4B5464AED73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user_remember_me (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', rememberMeToken VARCHAR(100) NOT NULL, userAgent VARCHAR(100) NOT NULL, expireDate DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', UNIQUE INDEX UNIQ_D3E96EBD1BBB86A0 (rememberMeToken), UNIQUE INDEX UNIQ_D3E96EBDD73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user_reset_password (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', expires DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', hash VARCHAR(64) NOT NULL, status VARCHAR(20) NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', userUuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', UNIQUE INDEX UNIQ_D21DE3BCD1B862B8 (hash), INDEX IDX_D21DE3BCD73087E9 (userUuid), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('CREATE TABLE user_role (uuid BINARY(16) NOT NULL COMMENT \'(DC2Type:uuid_binary_ordered_time)\', name VARCHAR(30) NOT NULL, created DATETIME NOT NULL COMMENT \'(DC2Type:datetime_immutable)\', updated DATETIME DEFAULT NULL COMMENT \'(DC2Type:datetime_immutable)\', UNIQUE INDEX UNIQ_2DE8C6A35E237E06 (name), PRIMARY KEY(uuid)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); + $this->addSql('ALTER TABLE user_roles ADD CONSTRAINT FK_54FCD59FD73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + $this->addSql('ALTER TABLE user_roles ADD CONSTRAINT FK_54FCD59F88446210 FOREIGN KEY (roleUuid) REFERENCES user_role (uuid)'); + $this->addSql('ALTER TABLE user_avatar ADD CONSTRAINT FK_73256912D73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + $this->addSql('ALTER TABLE user_detail ADD CONSTRAINT FK_4B5464AED73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + $this->addSql('ALTER TABLE user_remember_me ADD CONSTRAINT FK_D3E96EBDD73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + $this->addSql('ALTER TABLE user_reset_password ADD CONSTRAINT FK_D21DE3BCD73087E9 FOREIGN KEY (userUuid) REFERENCES user (uuid)'); + } + + public function down(Schema $schema): void + { + // this down() migration is auto-generated, please modify it to your needs + $this->addSql('ALTER TABLE user_roles DROP FOREIGN KEY FK_54FCD59FD73087E9'); + $this->addSql('ALTER TABLE user_roles DROP FOREIGN KEY FK_54FCD59F88446210'); + $this->addSql('ALTER TABLE user_avatar DROP FOREIGN KEY FK_73256912D73087E9'); + $this->addSql('ALTER TABLE user_detail DROP FOREIGN KEY FK_4B5464AED73087E9'); + $this->addSql('ALTER TABLE user_remember_me DROP FOREIGN KEY FK_D3E96EBDD73087E9'); + $this->addSql('ALTER TABLE user_reset_password DROP FOREIGN KEY FK_D21DE3BCD73087E9'); + $this->addSql('DROP TABLE contact_message'); + $this->addSql('DROP TABLE user'); + $this->addSql('DROP TABLE user_roles'); + $this->addSql('DROP TABLE user_avatar'); + $this->addSql('DROP TABLE user_detail'); + $this->addSql('DROP TABLE user_remember_me'); + $this->addSql('DROP TABLE user_reset_password'); + $this->addSql('DROP TABLE user_role'); + } +} diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 00000000..3e4e3d08 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/src/App/src/Common/Pagination.php b/src/App/src/Common/Pagination.php index 9df396b9..7b2843f2 100644 --- a/src/App/src/Common/Pagination.php +++ b/src/App/src/Common/Pagination.php @@ -30,8 +30,8 @@ public static function getOffsetAndLimit(array $filters = []) } return [ - 'offset' => (int)$offset, - 'limit' => (int)$limit + 'offset' => $offset, + 'limit' => $limit ]; } } diff --git a/src/App/src/Common/UuidOrderedTimeGenerator.php b/src/App/src/Common/UuidOrderedTimeGenerator.php index f58728af..780f6fa5 100644 --- a/src/App/src/Common/UuidOrderedTimeGenerator.php +++ b/src/App/src/Common/UuidOrderedTimeGenerator.php @@ -4,11 +4,11 @@ namespace Frontend\App\Common; -use Exception; use Ramsey\Uuid\Codec\OrderedTimeCodec; -use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidFactory; +use Ramsey\Uuid\UuidFactoryInterface; use Ramsey\Uuid\UuidInterface; +use Ramsey\Uuid\Uuid; /** * Class UuidOrderedTimeGenerator @@ -16,35 +16,19 @@ */ final class UuidOrderedTimeGenerator { - /** @var UuidFactory $factory */ - private static $factory; + private static UuidFactoryInterface $factory; - /** - * @return UuidInterface - */ public static function generateUuid(): UuidInterface { - try { - return self::getFactory()->uuid1(); - } catch (Exception $exception) { - return null; - } + return self::getFactory()->uuid1(); } - /** - * @return UuidFactory - */ - private static function getFactory(): UuidFactory + /** @psalm-suppress UndefinedInterfaceMethod */ + private static function getFactory(): UuidFactoryInterface { - if (!self::$factory) { - self::$factory = clone Uuid::getFactory(); - - $codec = new OrderedTimeCodec( - self::$factory->getUuidBuilder() - ); - - self::$factory->setCodec($codec); - } + self::$factory = clone Uuid::getFactory(); + $codec = new OrderedTimeCodec(self::$factory->getUuidBuilder()); + self::$factory->setCodec($codec); return self::$factory; } diff --git a/src/App/src/Middleware/RememberMeMiddleware.php b/src/App/src/Middleware/RememberMeMiddleware.php index 4709eb52..389bc18b 100644 --- a/src/App/src/Middleware/RememberMeMiddleware.php +++ b/src/App/src/Middleware/RememberMeMiddleware.php @@ -87,6 +87,7 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface $user->getDetail()->getArrayCopy(), ); + /** @psalm-suppress UndefinedInterfaceMethod */ $this->authenticationService->getStorage()->write($identity); } } diff --git a/src/App/src/Resolver/EntityListenerResolver.php b/src/App/src/Resolver/EntityListenerResolver.php index d4a30f04..c45413ea 100644 --- a/src/App/src/Resolver/EntityListenerResolver.php +++ b/src/App/src/Resolver/EntityListenerResolver.php @@ -5,7 +5,9 @@ namespace Frontend\App\Resolver; use Doctrine\ORM\Mapping\DefaultEntityListenerResolver; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; +use Psr\Container\NotFoundExceptionInterface; /** * Class EntityListenerResolver @@ -14,7 +16,7 @@ class EntityListenerResolver extends DefaultEntityListenerResolver { /** @var ContainerInterface $container */ - protected $container; + protected ContainerInterface $container; /** * EntityListenerResolver constructor. @@ -26,10 +28,12 @@ public function __construct(ContainerInterface $container) } /** - * @param $className - * @return mixed + * @param string $className + * @return object + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface */ - public function resolve($className) + public function resolve($className): object { return $this->container->get($className); } diff --git a/src/App/src/Service/RecaptchaService.php b/src/App/src/Service/RecaptchaService.php index 868c68e8..cae6905b 100644 --- a/src/App/src/Service/RecaptchaService.php +++ b/src/App/src/Service/RecaptchaService.php @@ -46,7 +46,7 @@ public function setResponse(string $response): self */ public function isValid(): bool { - if (! isset($this->response)) { + if (empty($this->response)) { throw new InvalidArgumentException('Recaptcha response not initialized.'); } @@ -64,6 +64,8 @@ public function isValid(): bool curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data)); $response = curl_exec($curl); + + /** @psalm-suppress InvalidScalarArgument */ $response = json_decode($response, true); $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); diff --git a/src/Contact/src/Form/ContactForm.php b/src/Contact/src/Form/ContactForm.php index 3d267c64..058e3f33 100644 --- a/src/Contact/src/Form/ContactForm.php +++ b/src/Contact/src/Form/ContactForm.php @@ -9,7 +9,7 @@ use Laminas\Form\Element\Text; use Laminas\Form\Element\Textarea; use Laminas\Form\Form; -use Laminas\InputFilter\InputFilter; +use Laminas\InputFilter\InputFilterInterface; /** * Class ContactForm @@ -17,8 +17,8 @@ */ class ContactForm extends Form { - /** @var InputFilter $inputFilter */ - protected $inputFilter; + /** @var InputFilterInterface $inputFilter */ + protected InputFilterInterface $inputFilter; /** * ContactForm constructor. @@ -84,21 +84,12 @@ public function init() ], 'type' => Textarea::class, ]); - -// $this->add([ -// 'name' => 'submit', -// 'type' => 'submit', -// 'attributes' => [ -// 'type' => 'submit', -// 'value' => 'Send message' -// ] -// ], ['priority' => -105]); } /** - * @return null|InputFilter|\Laminas\InputFilter\InputFilterInterface + * @return InputFilterInterface */ - public function getInputFilter(): \Laminas\InputFilter\InputFilterInterface + public function getInputFilter(): InputFilterInterface { return $this->inputFilter; } diff --git a/src/Plugin/src/ConfigProvider.php b/src/Plugin/src/ConfigProvider.php index fad952a0..5ebad757 100644 --- a/src/Plugin/src/ConfigProvider.php +++ b/src/Plugin/src/ConfigProvider.php @@ -4,7 +4,6 @@ namespace Frontend\Plugin; -use Frontend\Plugin\Factory\FlashMessengerPluginFactory; use Frontend\Plugin\Factory\FormsPluginFactory; use Frontend\Plugin\Factory\PluginManagerAwareInitializer; use Frontend\Plugin\Factory\PluginManagerFactory; @@ -26,7 +25,6 @@ public function __invoke(): array 'dot_controller' => [ 'plugin_manager' => [ 'factories' => [ - 'messenger' => FlashMessengerPluginFactory::class, 'forms' => FormsPluginFactory::class, ], ], diff --git a/src/Plugin/src/FormsPlugin.php b/src/Plugin/src/FormsPlugin.php index 05e1e7fa..f279d716 100644 --- a/src/Plugin/src/FormsPlugin.php +++ b/src/Plugin/src/FormsPlugin.php @@ -14,9 +14,11 @@ use Dot\FlashMessenger\FlashMessengerInterface; use Dot\Form\Factory\FormAbstractServiceFactory; use Dot\Form\FormElementManager; +use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerInterface; use Laminas\Form\Form; use Laminas\Form\FormInterface; +use Psr\Container\NotFoundExceptionInterface; /** * Class FormsPlugin @@ -24,14 +26,14 @@ */ class FormsPlugin implements PluginInterface { - /** @var FormElementManager */ - protected $formElementManager; + /** @var FormElementManager $formElementManager */ + protected FormElementManager $formElementManager; - /** @var ContainerInterface */ - protected $container; + /** @var ContainerInterface $container */ + protected ContainerInterface $container; - /** @var FlashMessengerInterface */ - protected $flashMessenger; + /** @var FlashMessengerInterface|null $flashMessenger*/ + protected ?FlashMessengerInterface $flashMessenger; /** * FormsPlugin constructor. @@ -50,8 +52,10 @@ public function __construct( } /** - * @param string $name - * @return object + * @param string|null $name + * @return mixed + * @throws ContainerExceptionInterface + * @throws NotFoundExceptionInterface */ public function __invoke(string $name = null) { @@ -85,7 +89,7 @@ public function __invoke(string $name = null) /** * @param Form $form */ - public function restoreState(Form $form) + public function restoreState(Form $form): void { if ($this->flashMessenger) { $dataKey = $form->getName() . '_data'; @@ -159,6 +163,7 @@ public function getErrors(Form $form): array /** * @param array $formMessages + * @psalm-suppress InvalidArrayOffset * @return array */ protected function processFormErrors(array $formMessages): array @@ -167,7 +172,7 @@ protected function processFormErrors(array $formMessages): array foreach ($formMessages as $key => $message) { if (is_array($message)) { if (!isset($errors[$key])) { - $errors[$key] = array(); + $errors[$key] = []; } foreach ($message as $k => $m) { diff --git a/src/Plugin/src/TemplatePlugin.php b/src/Plugin/src/TemplatePlugin.php index 3aebfe00..1d82cd7e 100644 --- a/src/Plugin/src/TemplatePlugin.php +++ b/src/Plugin/src/TemplatePlugin.php @@ -18,8 +18,8 @@ */ class TemplatePlugin implements PluginInterface { - /** @var TemplateRendererInterface */ - protected $template; + /** @var TemplateRendererInterface $template */ + protected TemplateRendererInterface $template; /** * TemplatePlugin constructor. @@ -32,8 +32,8 @@ public function __construct(TemplateRendererInterface $template) /** * @param string|null $templateName - * @param array|null $params - * @return mixed + * @param array $params + * @return self|string */ public function __invoke(string $templateName = null, array $params = []) { diff --git a/src/Slug/src/SlugCollector.php b/src/Slug/src/SlugCollector.php index 370ffd7f..4d2ec300 100644 --- a/src/Slug/src/SlugCollector.php +++ b/src/Slug/src/SlugCollector.php @@ -282,6 +282,7 @@ public function generateUri(Slug $slug, RouteResult $routeResult, $matchParams = if ($part[0] !== self::REMOVABLE_PART) { // Check substitute value with regex + /** @psalm-suppress UndefinedVariable */ if (!empty($addOns)) { $substitutions[$part[0]] = $addOns[$p]; } diff --git a/src/User/src/Authentication/AuthenticationAdapter.php b/src/User/src/Authentication/AuthenticationAdapter.php index e5480d3e..73353f31 100644 --- a/src/User/src/Authentication/AuthenticationAdapter.php +++ b/src/User/src/Authentication/AuthenticationAdapter.php @@ -6,20 +6,21 @@ use Frontend\User\Entity\User; use Frontend\User\Entity\UserIdentity; use Frontend\User\Entity\UserRole; +use Laminas\Authentication\Adapter\AbstractAdapter; use Laminas\Authentication\Adapter\AdapterInterface; use Exception; use Laminas\Authentication\Result; -class AuthenticationAdapter implements AdapterInterface +class AuthenticationAdapter extends AbstractAdapter implements AdapterInterface { private const METHOD_NOT_EXISTS = "Method %s not found in %s ."; private const OPTION_VALUE_NOT_PROVIDED = "Option '%s' not provided for '%s' option."; /** @var string $identity */ - private string $identity; + protected $identity; /** @var string $credential */ - private string $credential; + protected $credential; /** @var EntityManager $entityManager */ private EntityManager $entityManager; @@ -38,42 +39,6 @@ public function __construct($entityManager, array $config) $this->config = $config; } - /** - * @param string $identity - * @return $this - */ - public function setIdentity(string $identity): self - { - $this->identity = $identity; - return $this; - } - - /** - * @param string $credential - * @return $this - */ - public function setCredential(string $credential): self - { - $this->credential = $credential; - return $this; - } - - /** - * @return string - */ - private function getIdentity(): string - { - return $this->identity; - } - - /** - * @return string - */ - private function getCredential(): string - { - return $this->credential; - } - /** * @return Result * @throws Exception @@ -99,7 +64,6 @@ public function authenticate(): Result ); } - /** @var callable $getCredential */ $getCredential = "get" . ucfirst($this->config['orm_default']['credential_property']); /** Check if get credential method exist in the provided identity class */ @@ -117,7 +81,6 @@ public function authenticate(): Result /** Check for extra validation options */ if (! empty($this->config['orm_default']['options'])) { foreach ($this->config['orm_default']['options'] as $property => $option) { - /** @var callable $methodName */ $methodName = "get" . ucfirst($property); /** Check if the method exists in the provided identity class */ diff --git a/src/User/src/Authentication/AuthenticationAdapterFactory.php b/src/User/src/Authentication/AuthenticationAdapterFactory.php index 74a4f7f7..ae2f5be3 100644 --- a/src/User/src/Authentication/AuthenticationAdapterFactory.php +++ b/src/User/src/Authentication/AuthenticationAdapterFactory.php @@ -15,6 +15,7 @@ class AuthenticationAdapterFactory */ public function __invoke(ContainerInterface $container): AuthenticationAdapter { + // TODO Refactor this to use the specific entity repository, not the entity manager if (! $container->has(EntityManager::class)) { throw new Exception('EntityManager not found.'); } diff --git a/src/User/src/Controller/AccountController.php b/src/User/src/Controller/AccountController.php index 50ed92e9..9ab8c4e1 100644 --- a/src/User/src/Controller/AccountController.php +++ b/src/User/src/Controller/AccountController.php @@ -11,7 +11,6 @@ use Frontend\Plugin\FormsPlugin; use Frontend\User\Entity\User; use Frontend\User\Entity\UserIdentity; -use Frontend\User\Entity\UserInterface; use Frontend\User\Entity\UserResetPassword; use Frontend\User\Form\ProfileDeleteForm; use Frontend\User\Form\ProfileDetailsForm; @@ -23,13 +22,11 @@ use Laminas\Authentication\AuthenticationService; use Laminas\Authentication\AuthenticationServiceInterface; use Laminas\Diactoros\Response\HtmlResponse; -use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\RedirectResponse; use Mezzio\Router\RouterInterface; use Mezzio\Template\TemplateRendererInterface; use Dot\AnnotatedServices\Annotation\Inject; use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\UploadedFileInterface; use Exception; class AccountController extends AbstractActionController @@ -314,7 +311,6 @@ public function avatarAction(): ResponseInterface $this->template->render('user::profile', [ 'action' => 'avatar', 'content' => $this->template->render('profile::avatar', [ - 'userUploadsBaseUrl' => 'http://localhost:8080/uploads/user/', 'user' => $user, 'form' => $form ]), diff --git a/src/User/src/Controller/UserController.php b/src/User/src/Controller/UserController.php index 2711707a..15b7a42e 100644 --- a/src/User/src/Controller/UserController.php +++ b/src/User/src/Controller/UserController.php @@ -2,16 +2,19 @@ namespace Frontend\User\Controller; +use Doctrine\ORM\NonUniqueResultException; +use Doctrine\ORM\OptimisticLockException; +use Doctrine\ORM\ORMException; use Dot\Controller\AbstractActionController; use Dot\FlashMessenger\FlashMessenger; use Fig\Http\Message\RequestMethodInterface; use Frontend\Plugin\FormsPlugin; +use Frontend\User\Authentication\AuthenticationAdapter; use Frontend\User\Entity\User; use Frontend\User\Form\LoginForm; use Frontend\User\Form\RegisterForm; use Frontend\User\Service\UserService; use Laminas\Authentication\AuthenticationService; -use Laminas\Authentication\AuthenticationServiceInterface; use Laminas\Diactoros\Response\HtmlResponse; use Laminas\Diactoros\Response\RedirectResponse; use Mezzio\Router\RouterInterface; @@ -31,8 +34,8 @@ class UserController extends AbstractActionController /** @var UserService $userService */ protected UserService $userService; - /** @var AuthenticationServiceInterface $authenticationService */ - protected AuthenticationServiceInterface $authenticationService; + /** @var AuthenticationService $authenticationService */ + protected AuthenticationService $authenticationService; /** @var FlashMessenger $messenger */ protected FlashMessenger $messenger; @@ -81,14 +84,17 @@ public function __construct( } /** - * @throws \Doctrine\ORM\NonUniqueResultException + * @return ResponseInterface + * @throws NonUniqueResultException + * @throws ORMException + * @throws OptimisticLockException */ public function loginAction(): ResponseInterface { if ($this->authenticationService->hasIdentity()) { return new RedirectResponse($this->router->generateUri("page")); } - /** @var LoginForm $form */ + $form = new LoginForm(); $shouldRebind = $this->messenger->getData('shouldRebind') ?? true; @@ -99,6 +105,7 @@ public function loginAction(): ResponseInterface if (RequestMethodInterface::METHOD_POST === $this->getRequest()->getMethod()) { $form->setData($this->getRequest()->getParsedBody()); if ($form->isValid()) { + /** @var AuthenticationAdapter $adapter */ $adapter = $this->authenticationService->getAdapter(); $data = $form->getData(); $adapter->setIdentity($data['identity'])->setCredential($data['password']); diff --git a/src/User/src/Entity/User.php b/src/User/src/Entity/User.php index 78ccbddf..8961cfe7 100644 --- a/src/User/src/Entity/User.php +++ b/src/User/src/Entity/User.php @@ -5,12 +5,13 @@ namespace Frontend\User\Entity; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\ORM\Mapping as ORM; +use Doctrine\Common\Collections\Collection; +use Dot\Authorization\Role\RoleInterface; use Frontend\App\Common\AbstractEntity; use Frontend\App\Common\UuidOrderedTimeGenerator; +use Doctrine\ORM\Mapping as ORM; use Exception; -use function array_map; use function bin2hex; use function random_bytes; @@ -40,45 +41,38 @@ class User extends AbstractEntity implements UserInterface /** * @ORM\OneToOne(targetEntity="Frontend\User\Entity\UserDetail", cascade={"persist", "remove"}, mappedBy="user") - * @var UserDetail $detail */ - protected $detail; + protected UserDetail $detail; /** * @ORM\OneToOne(targetEntity="Frontend\User\Entity\UserAvatar", cascade={"persist", "remove"}, mappedBy="user") - * @var UserAvatar $avatar */ - protected $avatar; + protected ?UserAvatar $avatar; /** * @ORM\Column(name="identity", type="string", length=191, nullable=false, unique=true) - * @var string $identity */ - protected $identity; + protected string $identity; /** * @ORM\Column(name="password", type="string", length=191, nullable=false) - * @var string $password */ - protected $password; + protected string $password; /** * @ORM\Column(name="status", type="string", length=20, columnDefinition="ENUM('pending', 'active')") - * @var string $status */ - protected $status = self::STATUS_PENDING; + protected string $status = self::STATUS_PENDING; /** * @ORM\Column(name="isDeleted", type="boolean") - * @var bool $isDeleted */ - protected $isDeleted = self::IS_DELETED_NO; + protected bool $isDeleted = self::IS_DELETED_NO; /** * @ORM\Column(name="hash", type="string", length=64, nullable=false, unique=true) - * @var string $hash */ - protected $hash; + protected string $hash; /** * @ORM\ManyToMany(targetEntity="Frontend\User\Entity\UserRole") @@ -87,16 +81,14 @@ class User extends AbstractEntity implements UserInterface * joinColumns={@ORM\JoinColumn(name="userUuid", referencedColumnName="uuid")}, * inverseJoinColumns={@ORM\JoinColumn(name="roleUuid", referencedColumnName="uuid")} * ) - * @var ArrayCollection $roles */ - protected $roles = []; + protected Collection $roles; /** * @ORM\OneToMany(targetEntity="UserResetPassword", * cascade={"persist", "remove"}, mappedBy="user", fetch="EXTRA_LAZY") - * @var UserResetPassword[] $resetPassword */ - protected $resetPasswords; + protected Collection $resetPasswords; /** * User constructor. @@ -120,9 +112,9 @@ public function getDetail(): ?UserDetail /** * @param UserDetail $detail - * @return UserInterface + * @return self */ - public function setDetail(UserDetail $detail): UserInterface + public function setDetail(UserDetail $detail): self { $this->detail = $detail; @@ -139,9 +131,9 @@ public function getAvatar(): ?UserAvatar /** * @param UserAvatar $avatar - * @return UserInterface + * @return self */ - public function setAvatar(UserAvatar $avatar): UserInterface + public function setAvatar(UserAvatar $avatar): self { $this->avatar = $avatar; @@ -160,9 +152,9 @@ public function getIdentity(): string /** * @param string $identity - * @return UserInterface + * @return self */ - public function setIdentity(string $identity): UserInterface + public function setIdentity(string $identity): self { $this->identity = $identity; @@ -178,10 +170,10 @@ public function getPassword(): string } /** - * @param string|null $password - * @return UserInterface + * @param string $password + * @return self */ - public function setPassword(?string $password): UserInterface + public function setPassword(string $password): self { $this->password = $password; @@ -198,9 +190,9 @@ public function getStatus(): string /** * @param string $status - * @return UserInterface + * @return self */ - public function setStatus(string $status): UserInterface + public function setStatus(string $status): self { $this->status = $status; @@ -217,9 +209,9 @@ public function getIsDeleted(): bool /** * @param bool $isDeleted - * @return $this + * @return self */ - public function setIsDeleted(bool $isDeleted) + public function setIsDeleted(bool $isDeleted): self { $this->isDeleted = $isDeleted; @@ -235,10 +227,10 @@ public function getHash(): string } /** - * @param string|null $hash - * @return $this + * @param string $hash + * @return self */ - public function setHash(string $hash = null) + public function setHash(string $hash): self { $this->hash = $hash; @@ -254,10 +246,10 @@ public function getRoles() } /** - * @param UserRole $role - * @return UserInterface + * @param RoleInterface $role + * @return self */ - public function addRole(UserRole $role): UserInterface + public function addRole(RoleInterface $role): self { if (!$this->roles->contains($role)) { $this->roles->add($role); @@ -267,10 +259,10 @@ public function addRole(UserRole $role): UserInterface } /** - * @param UserRole $role - * @return UserInterface + * @param RoleInterface $role + * @return self */ - public function removeRole(UserRole $role): UserInterface + public function removeRole(RoleInterface $role): self { if (!$this->roles->contains($role)) { $this->roles->removeElement($role); @@ -280,10 +272,9 @@ public function removeRole(UserRole $role): UserInterface } /** - * @return $this - * @throws Exception + * @return self */ - public function renewHash() + public function renewHash(): self { $this->hash = self::generateHash(); @@ -292,7 +283,6 @@ public function renewHash() /** * @return string - * @throws Exception */ public static function generateHash(): string { @@ -308,15 +298,15 @@ public static function generateHash(): string /** * @return bool */ - public function isActive() + public function isActive(): bool { return $this->status === self::STATUS_ACTIVE; } /** - * @return $this + * @return self */ - public function markAsDeleted() + public function markAsDeleted(): self { $this->isDeleted = self::IS_DELETED_YES; @@ -326,38 +316,37 @@ public function markAsDeleted() /** * @return string */ - public function getName() + public function getName(): string { return $this->getDetail()->getFirstName() . ' ' . $this->getDetail()->getLastName(); } /** - * @return User + * @return self */ - public function activate() + public function activate(): self { return $this->setStatus(self::STATUS_ACTIVE); } /** - * @return $this - * @throws Exception + * @return self */ - public function resetRoles() + public function resetRoles(): self { - foreach ($this->roles->getIterator()->getArrayCopy() as $role) { + $this->roles->map(function (RoleInterface $role) { $this->removeRole($role); - } + }); + $this->roles = new ArrayCollection(); return $this; } /** - * @return $this - * @throws Exception + * @return self */ - public function createResetPassword() + public function createResetPassword(): self { $resetPassword = new UserResetPassword(); $resetPassword->setHash(self::generateHash()); @@ -370,16 +359,19 @@ public function createResetPassword() /** * @param UserResetPassword $resetPassword + * @return self */ - public function addResetPassword(UserResetPassword $resetPassword) + public function addResetPassword(UserResetPassword $resetPassword): self { $this->resetPasswords->add($resetPassword); + + return $this; } /** * @return ArrayCollection */ - public function getResetPasswords() + public function getResetPasswords(): ArrayCollection { return $this->resetPasswords; } @@ -388,16 +380,16 @@ public function getResetPasswords() * @param UserResetPassword $resetPassword * @return bool */ - public function hasResetPassword(UserResetPassword $resetPassword) + public function hasResetPassword(UserResetPassword $resetPassword): bool { return $this->resetPasswords->contains($resetPassword); } /** * @param UserResetPassword $resetPassword - * @return $this + * @return self */ - public function removeResetPassword(UserResetPassword $resetPassword) + public function removeResetPassword(UserResetPassword $resetPassword): self { $this->resetPasswords->removeElement($resetPassword); @@ -406,9 +398,9 @@ public function removeResetPassword(UserResetPassword $resetPassword) /** * @param array $resetPasswords - * @return $this + * @return self */ - public function setResetPasswords(array $resetPasswords) + public function setResetPasswords(array $resetPasswords): self { foreach ($resetPasswords as $resetPassword) { $this->resetPasswords->add($resetPassword); diff --git a/src/User/src/Entity/UserAvatar.php b/src/User/src/Entity/UserAvatar.php index 069d6c6d..eeb5ffbe 100644 --- a/src/User/src/Entity/UserAvatar.php +++ b/src/User/src/Entity/UserAvatar.php @@ -20,20 +20,18 @@ class UserAvatar extends AbstractEntity /** * @ORM\OneToOne(targetEntity="Frontend\User\Entity\User", inversedBy="avatar") * @ORM\JoinColumn(name="userUuid", referencedColumnName="uuid", nullable=false) - * @var UserInterface $user */ - protected $user; + protected UserInterface $user; /** * @ORM\Column(name="name", type="string", length=191) - * @var $name */ - protected $name; + protected string $name; /** * @var string $url */ - protected $url; + protected string $url; /** * UserAvatar constructor. @@ -53,7 +51,7 @@ public function getUser(): UserInterface /** * @param UserInterface $user - * @return UserAvatar + * @return self */ public function setUser(UserInterface $user): self { @@ -63,16 +61,16 @@ public function setUser(UserInterface $user): self } /** - * @return mixed + * @return string */ - public function getName() + public function getName(): string { return $this->name; } /** * @param $name - * @return UserAvatar + * @return self */ public function setName($name): self { @@ -91,6 +89,7 @@ public function getUrl(): string /** * @param string $url + * @return void */ public function setUrl(string $url): void { diff --git a/src/User/src/Entity/UserDetail.php b/src/User/src/Entity/UserDetail.php index 7adf3e62..a40b94f0 100644 --- a/src/User/src/Entity/UserDetail.php +++ b/src/User/src/Entity/UserDetail.php @@ -19,21 +19,18 @@ class UserDetail extends AbstractEntity /** * @ORM\OneToOne(targetEntity="Frontend\User\Entity\User", inversedBy="detail") * @ORM\JoinColumn(name="userUuid", referencedColumnName="uuid", nullable=false) - * @var UserInterface $user */ - protected $user; + protected UserInterface $user; /** * @ORM\Column(name="firstName", type="string", length=191, nullable=true) - * @var $firstName */ - protected $firstName; + protected string $firstName; /** * @ORM\Column(name="lastName", type="string", length=191, nullable=true) - * @var $lastName */ - protected $lastName; + protected string $lastName; /** * UserDetail constructor. @@ -44,7 +41,7 @@ public function __construct() } /** - * @return User + * @return UserInterface */ public function getUser(): UserInterface { @@ -53,9 +50,9 @@ public function getUser(): UserInterface /** * @param User $user - * @return $this + * @return self */ - public function setUser(User $user) + public function setUser(User $user): self { $this->user = $user; @@ -63,16 +60,16 @@ public function setUser(User $user) } /** - * @return mixed + * @return string|null */ - public function getFirstName() + public function getFirstName(): ?string { return $this->firstName; } /** * @param $firstName - * @return UserDetail + * @return self */ public function setFirstName($firstName): self { @@ -82,16 +79,16 @@ public function setFirstName($firstName): self } /** - * @return mixed + * @return string|null */ - public function getLastName() + public function getLastName(): ?string { return $this->lastName; } /** * @param $lastName - * @return UserDetail + * @return self */ public function setLastName($lastName): self { diff --git a/src/User/src/Entity/UserIdentity.php b/src/User/src/Entity/UserIdentity.php index 53341c67..c0e14ac0 100644 --- a/src/User/src/Entity/UserIdentity.php +++ b/src/User/src/Entity/UserIdentity.php @@ -13,16 +13,16 @@ class UserIdentity implements UserInterface { /** @var string $identity */ - protected $identity; + protected string $identity; /** @var array $roles */ - protected $roles; + protected array $roles; /** @var array $details */ - protected $details; + protected array $details; /** @var string $uuid */ - protected $uuid; + protected string $uuid; /** * UserIdentity constructor. @@ -44,15 +44,25 @@ public function __construct( } /** - * Get the unique user identity (id, username, email address or ...) + * @return string + */ + public function getUuid(): string + { + return $this->uuid; + } + + /** + * @return string */ public function getIdentity(): string { return $this->identity; } + /** * @return iterable + * @psalm-suppress LessSpecificImplementedReturnType */ public function getRoles(): iterable { @@ -61,8 +71,8 @@ public function getRoles(): iterable /** * @param string $name - * @param null $default - * @return mixed|null + * @param null|mixed $default + * @return mixed */ public function getDetail(string $name, $default = null) { @@ -71,17 +81,10 @@ public function getDetail(string $name, $default = null) /** * @return array + * @psalm-return array */ public function getDetails(): array { return $this->details; } - - /** - * @return User - */ - public function getUuid(): string - { - return $this->uuid; - } } diff --git a/src/User/src/Entity/UserInterface.php b/src/User/src/Entity/UserInterface.php index c9a80279..873f64d3 100644 --- a/src/User/src/Entity/UserInterface.php +++ b/src/User/src/Entity/UserInterface.php @@ -4,12 +4,19 @@ namespace Frontend\User\Entity; +use Ramsey\Uuid\UuidInterface; + /** * Interface UserInterface * @package Frontend\User\Entity */ interface UserInterface { + /** + * @return UuidInterface + */ + public function getUuid(): UuidInterface; + /** * @return UserDetail|null */ diff --git a/src/User/src/Entity/UserResetPassword.php b/src/User/src/Entity/UserResetPassword.php index 55d34036..654a0c9b 100644 --- a/src/User/src/Entity/UserResetPassword.php +++ b/src/User/src/Entity/UserResetPassword.php @@ -30,27 +30,23 @@ class UserResetPassword extends AbstractEntity /** * @ORM\ManyToOne(targetEntity="User", cascade={"persist", "remove"}, inversedBy="resetPasswords") * @ORM\JoinColumn(name="userUuid", referencedColumnName="uuid", nullable=false) - * @var User $user */ - protected $user; + protected User $user; /** * @ORM\Column(name="expires", type="datetime_immutable", nullable=false) - * @var DateTimeImmutable */ - protected $expires; + protected DateTimeImmutable $expires; /** * @ORM\Column(name="hash", type="string", length=64, nullable=false, unique=true) - * @var $hash */ - protected $hash; + protected string $hash; /** * @ORM\Column(name="status", type="string", length=20, nullable=false) - * @var string $status */ - protected $status = self::STATUS_REQUESTED; + protected string $status = self::STATUS_REQUESTED; /** * UserResetPassword constructor. @@ -74,9 +70,9 @@ public function getUser(): User /** * @param User $user - * @return $this + * @return self */ - public function setUser(User $user) + public function setUser(User $user): self { $this->user = $user; @@ -93,9 +89,9 @@ public function getExpires(): DateTimeImmutable /** * @param DateTimeImmutable $expires - * @return $this + * @return self */ - public function setExpires(DateTimeImmutable $expires) + public function setExpires(DateTimeImmutable $expires): self { $this->expires = $expires; @@ -103,18 +99,18 @@ public function setExpires(DateTimeImmutable $expires) } /** - * @return mixed + * @return string */ - public function getHash() + public function getHash(): string { return $this->hash; } /** * @param $hash - * @return $this + * @return self */ - public function setHash($hash) + public function setHash($hash): self { $this->hash = $hash; @@ -131,9 +127,9 @@ public function getStatus(): string /** * @param string $status - * @return $this + * @return self */ - public function setStatus(string $status) + public function setStatus(string $status): self { $this->status = $status; @@ -147,7 +143,7 @@ public function setStatus(string $status) /** * @return bool */ - public function isCompleted() + public function isCompleted(): bool { return $this->getStatus() === self::STATUS_COMPLETED; } @@ -166,9 +162,9 @@ public function isValid(): bool } /** - * @return $this + * @return self */ - public function markAsCompleted() + public function markAsCompleted(): self { $this->status = self::STATUS_COMPLETED; diff --git a/src/User/src/Entity/UserRole.php b/src/User/src/Entity/UserRole.php index 79d34f7d..0f92b454 100644 --- a/src/User/src/Entity/UserRole.php +++ b/src/User/src/Entity/UserRole.php @@ -5,6 +5,7 @@ namespace Frontend\User\Entity; use Doctrine\ORM\Mapping as ORM; +use Dot\Authorization\Role\RoleInterface; use Frontend\App\Common\AbstractEntity; /** @@ -14,7 +15,7 @@ * @ORM\HasLifecycleCallbacks() * @package Frontend\User\Entity */ -class UserRole extends AbstractEntity +class UserRole extends AbstractEntity implements RoleInterface { public const ROLE_ADMIN = 'admin'; public const ROLE_USER = 'user'; @@ -27,9 +28,8 @@ class UserRole extends AbstractEntity /** * @ORM\Column(name="name", type="string", length=30, nullable=false, unique=true) - * @var string $name */ - protected $name; + protected string $name; /** * UserRole constructor. diff --git a/src/User/src/EventListener/UserAvatarEventListener.php b/src/User/src/EventListener/UserAvatarEventListener.php index 7bf6e835..01e20e09 100644 --- a/src/User/src/EventListener/UserAvatarEventListener.php +++ b/src/User/src/EventListener/UserAvatarEventListener.php @@ -16,8 +16,7 @@ */ class UserAvatarEventListener { - /** @var array $config */ - protected $config; + protected array $config; /** * UserAvatarEventListener constructor. diff --git a/src/User/src/Form/LoginForm.php b/src/User/src/Form/LoginForm.php index 3b1ac0b0..bab69be2 100644 --- a/src/User/src/Form/LoginForm.php +++ b/src/User/src/Form/LoginForm.php @@ -9,7 +9,7 @@ use Laminas\Form\Element\Password; use Laminas\Form\Element\Submit; use Laminas\Form\Form; -use Laminas\InputFilter\InputFilter; +use Laminas\InputFilter\InputFilterInterface; /** * Class LoginForm @@ -17,7 +17,7 @@ */ class LoginForm extends Form { - /** @var InputFilter $inputFilter */ + /** @var InputFilterInterface $inputFilter */ protected $inputFilter; /** @@ -82,9 +82,9 @@ public function init() } /** - * @return null|InputFilter|\Laminas\InputFilter\InputFilterInterface + * @return InputFilterInterface */ - public function getInputFilter(): \Laminas\InputFilter\InputFilterInterface + public function getInputFilter(): InputFilterInterface { return $this->inputFilter; } diff --git a/src/User/src/Form/ProfileDeleteForm.php b/src/User/src/Form/ProfileDeleteForm.php index 62ec2b3a..a75c8132 100644 --- a/src/User/src/Form/ProfileDeleteForm.php +++ b/src/User/src/Form/ProfileDeleteForm.php @@ -9,6 +9,7 @@ use Laminas\Form\Element\Submit; use Laminas\Form\Form; use Laminas\InputFilter\InputFilter; +use Laminas\InputFilter\InputFilterInterface; /** * Class ProfileDeleteForm @@ -16,7 +17,7 @@ */ class ProfileDeleteForm extends Form { - /** @var InputFilter $inputFilter */ + /** @var InputFilterInterface $inputFilter */ protected $inputFilter; /** @@ -65,9 +66,9 @@ public function init() } /** - * @return null|InputFilter|\Laminas\InputFilter\InputFilterInterface + * @return InputFilterInterface */ - public function getInputFilter(): \Laminas\InputFilter\InputFilterInterface + public function getInputFilter(): InputFilterInterface { return $this->inputFilter; } diff --git a/src/User/src/Form/ProfileDetailsForm.php b/src/User/src/Form/ProfileDetailsForm.php index 8b068fdb..e10095f0 100644 --- a/src/User/src/Form/ProfileDetailsForm.php +++ b/src/User/src/Form/ProfileDetailsForm.php @@ -5,15 +5,11 @@ namespace Frontend\User\Form; use Frontend\User\Fieldset\UserDetailFieldset; -use Frontend\User\InputFilter\RegisterInputFilter; use Frontend\User\InputFilter\UserDetailInputFilter; -use Laminas\Form\Element\Collection; -use Laminas\Form\Element\Email; -use Laminas\Form\Element\Password; use Laminas\Form\Element\Submit; -use Laminas\Form\Element\Text; use Laminas\Form\Form; use Laminas\InputFilter\InputFilter; +use Laminas\InputFilter\InputFilterInterface; /** * Class ProfileDetailsForm @@ -21,8 +17,8 @@ */ class ProfileDetailsForm extends Form { - /** @var InputFilter $inputFilter */ - protected $inputFilter; + /** @var InputFilterInterface $inputFilter */ + protected InputFilterInterface $inputFilter; /** * ProfileDetailsForm constructor. @@ -60,9 +56,9 @@ public function init() } /** - * @return null|InputFilter|\Laminas\InputFilter\InputFilterInterface + * @return InputFilterInterface */ - public function getInputFilter(): \Laminas\InputFilter\InputFilterInterface + public function getInputFilter(): InputFilterInterface { return $this->inputFilter; } diff --git a/src/User/src/Form/ProfilePasswordForm.php b/src/User/src/Form/ProfilePasswordForm.php index 3d6c72bf..9e872f57 100644 --- a/src/User/src/Form/ProfilePasswordForm.php +++ b/src/User/src/Form/ProfilePasswordForm.php @@ -7,8 +7,8 @@ use Frontend\User\InputFilter\ProfilePasswordInputFilter; use Laminas\Form\Element\Password; use Laminas\Form\Element\Submit; +use Laminas\InputFilter\InputFilterInterface; use Laminas\Form\Form; -use Laminas\InputFilter\InputFilter; /** * Class ProfilePasswordForm @@ -16,8 +16,8 @@ */ class ProfilePasswordForm extends Form { - /** @var InputFilter $inputFilter */ - protected $inputFilter; + /** @var InputFilterInterface $inputFilter */ + protected InputFilterInterface $inputFilter; /** * ProfilePasswordForm constructor. @@ -71,9 +71,9 @@ public function init() } /** - * @return null|InputFilter|\Laminas\InputFilter\InputFilterInterface + * @return InputFilterInterface */ - public function getInputFilter(): \Laminas\InputFilter\InputFilterInterface + public function getInputFilter(): InputFilterInterface { return $this->inputFilter; } diff --git a/src/User/src/Form/RegisterForm.php b/src/User/src/Form/RegisterForm.php index 0599d798..48074e39 100644 --- a/src/User/src/Form/RegisterForm.php +++ b/src/User/src/Form/RegisterForm.php @@ -7,13 +7,11 @@ use Frontend\User\Fieldset\UserDetailFieldset; use Frontend\User\InputFilter\RegisterInputFilter; use Frontend\User\InputFilter\UserDetailInputFilter; -use Laminas\Form\Element\Collection; use Laminas\Form\Element\Email; use Laminas\Form\Element\Password; use Laminas\Form\Element\Submit; -use Laminas\Form\Element\Text; +use Laminas\InputFilter\InputFilterInterface; use Laminas\Form\Form; -use Laminas\InputFilter\InputFilter; /** * Class RegisterForm @@ -21,8 +19,8 @@ */ class RegisterForm extends Form { - /** @var InputFilter $inputFilter */ - protected $inputFilter; + /** @var InputFilterInterface $inputFilter */ + protected InputFilterInterface $inputFilter; /** * RegisterForm constructor. @@ -94,9 +92,9 @@ public function init() } /** - * @return null|InputFilter|\Laminas\InputFilter\InputFilterInterface + * @return InputFilterInterface */ - public function getInputFilter(): \Laminas\InputFilter\InputFilterInterface + public function getInputFilter(): InputFilterInterface { return $this->inputFilter; } diff --git a/src/User/src/Form/RequestResetPasswordForm.php b/src/User/src/Form/RequestResetPasswordForm.php index 5a94e088..6d597afa 100644 --- a/src/User/src/Form/RequestResetPasswordForm.php +++ b/src/User/src/Form/RequestResetPasswordForm.php @@ -9,6 +9,7 @@ use Laminas\Form\Element\Submit; use Laminas\Form\Form; use Laminas\InputFilter\InputFilter; +use Laminas\InputFilter\InputFilterInterface; /** * Class RequestResetPasswordForm @@ -16,11 +17,11 @@ */ class RequestResetPasswordForm extends Form { - /** @var InputFilter $inputFilter */ + /** @var InputFilterInterface $inputFilter */ protected $inputFilter; /** - * LoginForm constructor. + * RequestResetPasswordForm constructor. * @param null $name * @param array $options */ @@ -60,9 +61,9 @@ public function init() } /** - * @return null|InputFilter|\Laminas\InputFilter\InputFilterInterface + * @return InputFilterInterface */ - public function getInputFilter(): \Laminas\InputFilter\InputFilterInterface + public function getInputFilter(): InputFilterInterface { return $this->inputFilter; } diff --git a/src/User/src/Form/ResetPasswordForm.php b/src/User/src/Form/ResetPasswordForm.php index 37b427a6..ca491813 100644 --- a/src/User/src/Form/ResetPasswordForm.php +++ b/src/User/src/Form/ResetPasswordForm.php @@ -4,17 +4,11 @@ namespace Frontend\User\Form; -use Frontend\User\Fieldset\UserDetailFieldset; -use Frontend\User\InputFilter\RegisterInputFilter; use Frontend\User\InputFilter\ResetPasswordInputFilter; -use Frontend\User\InputFilter\UserDetailInputFilter; -use Laminas\Form\Element\Collection; -use Laminas\Form\Element\Email; use Laminas\Form\Element\Password; use Laminas\Form\Element\Submit; -use Laminas\Form\Element\Text; use Laminas\Form\Form; -use Laminas\InputFilter\InputFilter; +use Laminas\InputFilter\InputFilterInterface; /** * Class ResetPasswordForm @@ -22,7 +16,7 @@ */ class ResetPasswordForm extends Form { - /** @var InputFilter $inputFilter */ + /** @var InputFilterInterface $inputFilter */ protected $inputFilter; /** @@ -77,9 +71,9 @@ public function init() } /** - * @return null|InputFilter|\Laminas\InputFilter\InputFilterInterface + * @return InputFilterInterface */ - public function getInputFilter(): \Laminas\InputFilter\InputFilterInterface + public function getInputFilter(): InputFilterInterface { return $this->inputFilter; } diff --git a/src/User/src/Repository/UserRepository.php b/src/User/src/Repository/UserRepository.php index da20ed74..e688692e 100644 --- a/src/User/src/Repository/UserRepository.php +++ b/src/User/src/Repository/UserRepository.php @@ -12,6 +12,7 @@ use Doctrine\ORM\NonUniqueResultException; use Doctrine\ORM\ORMException; use Doctrine\ORM\OptimisticLockException; +use DateTimeImmutable; use Exception; /** @@ -57,8 +58,6 @@ public function findByIdentity(string $identity): UserInterface /** * @param User $user - * @throws ORMException - * @throws OptimisticLockException */ public function saveUser(User $user) { @@ -90,20 +89,6 @@ public function exists(string $email = '', ?string $uuid = '') } } - /** - * @param string $email - * @return mixed - * @throws NonUniqueResultException - */ - public function getUserByEmail(string $email) - { - $qb = $this->getEntityManager()->createQueryBuilder(); - $qb->select('user') - ->from(User::class, 'user') - ->where('user.identity = :identity')->setParameter('identity', $email); - return $qb->getQuery()->useQueryCache(true)->getOneOrNullResult(); - } - /** * @param string $hash * @return User|null @@ -125,10 +110,8 @@ public function findByResetPasswordHash(string $hash): ?User /** * @param UserRememberMe $rememberUser * @return void - * @throws ORMException - * @throws OptimisticLockException */ - public function saveRememberUser(UserRememberMe $rememberUser) + public function saveRememberUser(UserRememberMe $rememberUser): void { $em = $this->getEntityManager(); $rememberUser->touch(); @@ -156,7 +139,7 @@ public function getRememberUser($token): ?UserRememberMe /** * @param User $user * @param string $userAgent - * @return int|mixed|string|null + * @return mixed * @throws NonUniqueResultException */ public function findRememberMeUser(User $user, string $userAgent) @@ -174,10 +157,10 @@ public function findRememberMeUser(User $user, string $userAgent) } /** - * @param \DateTimeImmutable $currentDate - * @return void + * @param DateTimeImmutable $currentDate + * @return mixed */ - public function deleteExpiredCookies(\DateTimeImmutable $currentDate) + public function deleteExpiredCookies(DateTimeImmutable $currentDate) { $qb = $this->getEntityManager()->createQueryBuilder(); $qb->delete(UserRememberMe::class, 'user_remember_me') @@ -190,10 +173,8 @@ public function deleteExpiredCookies(\DateTimeImmutable $currentDate) /** * @param UserRememberMe $userRememberMe * @return void - * @throws ORMException - * @throws OptimisticLockException */ - public function removeUserRememberMe(UserRememberMe $userRememberMe) + public function removeUserRememberMe(UserRememberMe $userRememberMe): void { $this->getEntityManager()->remove($userRememberMe); $this->getEntityManager()->flush(); diff --git a/src/User/src/Service/UserService.php b/src/User/src/Service/UserService.php index 688fa9e9..fb0d3c47 100644 --- a/src/User/src/Service/UserService.php +++ b/src/User/src/Service/UserService.php @@ -5,14 +5,16 @@ namespace Frontend\User\Service; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\NonUniqueResultException; +use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\ORMException; use Dot\AnnotatedServices\Annotation\Inject; use Dot\AnnotatedServices\Annotation\Service; use Dot\Mail\Exception\MailException; use Dot\Mail\Service\MailService; +use Exception; use Frontend\App\Common\Message; use Frontend\App\Common\UuidOrderedTimeGenerator; -use Frontend\Contact\Repository\MessageRepository; use Frontend\User\Entity\UserRememberMe; use Frontend\User\Entity\User; use Frontend\User\Entity\UserAvatar; @@ -100,7 +102,7 @@ public function __construct( /** * @param string $uuid * @return User|null - * @throws \Doctrine\ORM\NonUniqueResultException + * @throws NonUniqueResultException */ public function findByUuid(string $uuid) { @@ -110,7 +112,7 @@ public function findByUuid(string $uuid) /** * @param string $identity * @return UserInterface - * @throws \Doctrine\ORM\NonUniqueResultException + * @throws NonUniqueResultException */ public function findByIdentity(string $identity): UserInterface { @@ -120,9 +122,8 @@ public function findByIdentity(string $identity): UserInterface /** * @param array $data * @return UserInterface - * @throws \Exception - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\OptimisticLockException + * @throws Exception + * @throws ORMException */ public function createUser(array $data): UserInterface { @@ -146,7 +147,7 @@ public function createUser(array $data): UserInterface foreach ($data['roles'] as $roleName) { $role = $this->userRoleRepository->findByName($roleName); if (!$role instanceof UserRole) { - throw new \Exception('Role not found: ' . $roleName); + throw new Exception('Role not found: ' . $roleName); } $user->addRole($role); } @@ -158,7 +159,7 @@ public function createUser(array $data): UserInterface } if (empty($user->getRoles())) { - throw new \Exception(Message::RESTRICTION_ROLES); + throw new Exception(Message::RESTRICTION_ROLES); } $this->userRepository->saveUser($user); @@ -170,13 +171,10 @@ public function createUser(array $data): UserInterface /** * @param User $user * @param array $data - * @return User + * @return UserInterface * @throws ORMException - * @throws \Doctrine\ORM\NoResultException - * @throws \Doctrine\ORM\NonUniqueResultException - * @throws \Doctrine\ORM\OptimisticLockException */ - public function updateUser(User $user, array $data = []) + public function updateUser(User $user, array $data = []): UserInterface { if (isset($data['email']) && !is_null($data['email'])) { if ($this->exists($data['email'], $user->getUuid()->toString())) { @@ -235,7 +233,7 @@ public function updateUser(User $user, array $data = []) } } if (empty($user->getRoles())) { - throw new \Exception(Message::RESTRICTION_ROLES); + throw new Exception(Message::RESTRICTION_ROLES); } $this->userRepository->saveUser($user); @@ -248,7 +246,7 @@ public function updateUser(User $user, array $data = []) * @param UploadedFile $uploadedFile * @return UserAvatar */ - protected function createAvatar(User $user, UploadedFile $uploadedFile) + protected function createAvatar(User $user, UploadedFile $uploadedFile): UserAvatar { $path = $this->config['uploads']['user']['path'] . DIRECTORY_SEPARATOR; $path .= $user->getUuid()->toString() . DIRECTORY_SEPARATOR; @@ -265,7 +263,7 @@ protected function createAvatar(User $user, UploadedFile $uploadedFile) } $fileName = sprintf( 'avatar-%s.%s', - UuidOrderedTimeGenerator::generateUuid(), + UuidOrderedTimeGenerator::generateUuid()->toString(), self::EXTENSIONS[$uploadedFile->getClientMediaType()] ); $avatar->setName($fileName); @@ -284,7 +282,7 @@ protected function createAvatar(User $user, UploadedFile $uploadedFile) * @param string $path * @return bool */ - public function deleteAvatarFile(string $path) + public function deleteAvatarFile(string $path): bool { if (empty($path)) { return false; @@ -301,10 +299,8 @@ public function deleteAvatarFile(string $path) * @param string $email * @param string|null $uuid * @return bool - * @throws \Doctrine\ORM\NoResultException - * @throws \Doctrine\ORM\NonUniqueResultException */ - public function exists(string $email = '', ?string $uuid = '') + public function exists(string $email = '', ?string $uuid = ''): bool { return !is_null( $this->userRepository->exists($email, $uuid) @@ -324,7 +320,7 @@ public function getUsers(): array * @return bool * @throws MailException */ - public function sendActivationMail(User $user) + public function sendActivationMail(User $user): bool { if ($user->isActive()) { return false; @@ -362,44 +358,22 @@ public function findOneBy(array $params = []): ?User /** * @param User $user * @return User - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\OptimisticLockException + * @throws ORMException + * @throws OptimisticLockException */ - public function activateUser(User $user) + public function activateUser(User $user): User { $this->userRepository->saveUser($user->activate()); return $user; } - /** - * @param string $email - * @return array - * @throws \Doctrine\ORM\NonUniqueResultException - */ - public function getRoleNamesByEmail(string $email) - { - $roleList = []; - - /** @var User $user */ - $user = $this->userRepository->getUserByEmail($email); - - if (!empty($user)) { - /** @var UserRole $role */ - foreach ($user->getRoles() as $role) { - $roleList[] = $role->getName(); - } - } - - return $roleList; - } - /** * @param User $user * @return bool * @throws MailException */ - public function sendResetPasswordRequestedMail(User $user) + public function sendResetPasswordRequestedMail(User $user): bool { $this->mailService->setBody( $this->templateRenderer->render('user::reset-password-requested', [ @@ -419,7 +393,7 @@ public function sendResetPasswordRequestedMail(User $user) * @param string|null $hash * @return User|null * @throws \Doctrine\ORM\NoResultException - * @throws \Doctrine\ORM\NonUniqueResultException + * @throws NonUniqueResultException */ public function findByResetPasswordHash(?string $hash): ?User { @@ -464,8 +438,8 @@ public function getRepository(): UserRepository * @param string $userAgent * @return void * @throws ORMException - * @throws \Doctrine\ORM\NonUniqueResultException - * @throws \Doctrine\ORM\OptimisticLockException + * @throws NonUniqueResultException + * @throws OptimisticLockException */ public function addRememberMeToken(User $user, string $userAgent) { @@ -508,8 +482,8 @@ public function addRememberMeToken(User $user, string $userAgent) * @return void * @throws ORMException * @throws \Doctrine\ORM\NoResultException - * @throws \Doctrine\ORM\NonUniqueResultException - * @throws \Doctrine\ORM\OptimisticLockException + * @throws NonUniqueResultException + * @throws OptimisticLockException */ public function deleteRememberMeCookie() { diff --git a/src/User/src/Service/UserServiceInterface.php b/src/User/src/Service/UserServiceInterface.php index a40bedd1..46c1f12f 100644 --- a/src/User/src/Service/UserServiceInterface.php +++ b/src/User/src/Service/UserServiceInterface.php @@ -2,6 +2,7 @@ namespace Frontend\User\Service; +use Doctrine\ORM\OptimisticLockException; use Doctrine\ORM\ORMException; use Dot\Mail\Exception\MailException; use Frontend\User\Entity\User; @@ -14,12 +15,13 @@ */ interface UserServiceInterface { + // TODO refactor this interface, it should only have CRUD methods. /** * @param array $data * @return UserInterface * @throws \Exception - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\OptimisticLockException + * @throws ORMException + * @throws OptimisticLockException */ public function createUser(array $data): UserInterface; @@ -28,7 +30,7 @@ public function createUser(array $data): UserInterface; * @return bool * @throws MailException */ - public function sendActivationMail(User $user); + public function sendActivationMail(User $user): bool; /** * @param array $params @@ -39,18 +41,11 @@ public function findOneBy(array $params = []): ?User; /** * @param User $user * @return User - * @throws \Doctrine\ORM\ORMException - * @throws \Doctrine\ORM\OptimisticLockException + * @throws ORMException + * @throws OptimisticLockException */ public function activateUser(User $user); - /** - * @param string $email - * @return array - * @throws \Doctrine\ORM\NonUniqueResultException - */ - public function getRoleNamesByEmail(string $email); - /** * @param string $uuid * @return User|null @@ -68,7 +63,7 @@ public function getRepository(): UserRepository; * @return void * @throws ORMException * @throws \Doctrine\ORM\NonUniqueResultException - * @throws \Doctrine\ORM\OptimisticLockException + * @throws OptimisticLockException */ public function addRememberMeToken(User $user, string $userAgent); @@ -77,7 +72,7 @@ public function addRememberMeToken(User $user, string $userAgent); * @throws ORMException * @throws \Doctrine\ORM\NoResultException * @throws \Doctrine\ORM\NonUniqueResultException - * @throws \Doctrine\ORM\OptimisticLockException + * @throws OptimisticLockException */ public function deleteRememberMeCookie(); }