feat: stores user's media preferences
This commit is contained in:
@@ -4,15 +4,47 @@ namespace App\User\Action\Handler;
|
||||
|
||||
use App\User\Action\Command\SaveUserMediaPreferencesCommand;
|
||||
use App\User\Action\Result\SaveUserMediaPreferencesResult;
|
||||
use App\User\Framework\Entity\User;
|
||||
use App\User\Framework\Entity\UserPreference;
|
||||
use App\User\Framework\Repository\PreferencesRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface as C;
|
||||
use OneToMany\RichBundle\Contract\HandlerInterface;
|
||||
use OneToMany\RichBundle\Contract\ResultInterface as R;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
|
||||
/** @implements HandlerInterface<SaveUserMediaPreferencesCommand> */
|
||||
class SaveUserMediaPreferencesHandler implements HandlerInterface
|
||||
{
|
||||
public function __construct(
|
||||
private readonly EntityManagerInterface $entityManager,
|
||||
private readonly PreferencesRepository $preferenceRepository,
|
||||
private readonly Security $token,
|
||||
) {}
|
||||
|
||||
public function handle(C $command): R
|
||||
{
|
||||
return new SaveUserMediaPreferencesResult('Success');
|
||||
/** @var User $user */
|
||||
$user = $this->token->getUser();
|
||||
|
||||
foreach ($command as $preference => $value) {
|
||||
if ($user->hasUserPreference($preference)) {
|
||||
$user->updateUserPreference($preference, $value);
|
||||
$this->entityManager->flush();
|
||||
continue;
|
||||
}
|
||||
|
||||
$preference = $this->preferenceRepository->find($preference);
|
||||
$user->addUserPreference(
|
||||
(new UserPreference())
|
||||
->setUser($user)
|
||||
->setPreference($preference)
|
||||
->setPreferenceValue($value)
|
||||
);
|
||||
}
|
||||
|
||||
$this->entityManager->flush();
|
||||
|
||||
return new SaveUserMediaPreferencesResult($user->getUserPreferences());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\User\Action\Input;
|
||||
|
||||
use App\User\Action\Command\SaveUserMediaPreferencesCommand;
|
||||
use OneToMany\RichBundle\Attribute\SourceRequest;
|
||||
use OneToMany\RichBundle\Attribute\SourceSecurity;
|
||||
use OneToMany\RichBundle\Contract\CommandInterface as C;
|
||||
use OneToMany\RichBundle\Contract\InputInterface;
|
||||
|
||||
@@ -11,6 +12,9 @@ use OneToMany\RichBundle\Contract\InputInterface;
|
||||
class SaveUserMediaPreferencesInput implements InputInterface
|
||||
{
|
||||
public function __construct(
|
||||
#[SourceSecurity]
|
||||
public mixed $userId,
|
||||
|
||||
#[SourceRequest('resolution')]
|
||||
public string $resolution,
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
|
||||
namespace App\User\Action\Result;
|
||||
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use OneToMany\RichBundle\Contract\ResultInterface;
|
||||
|
||||
/** @implements ResultInterface */
|
||||
class SaveUserMediaPreferencesResult implements ResultInterface
|
||||
{
|
||||
public function __construct(
|
||||
public string $status,
|
||||
public Collection $userPreferences,
|
||||
) {}
|
||||
}
|
||||
@@ -4,10 +4,15 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\User\Framework\Controller\Web;
|
||||
|
||||
use Aimeos\Map;
|
||||
use App\User\Action\Handler\SaveUserMediaPreferencesHandler;
|
||||
use App\User\Action\Input\SaveUserMediaPreferencesInput;
|
||||
use App\User\Framework\Entity\User;
|
||||
use App\User\Framework\Entity\UserPreference;
|
||||
use App\User\Framework\Repository\PreferencesRepository;
|
||||
use App\Util\CountryCodes;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
@@ -15,16 +20,29 @@ class PreferencesController extends AbstractController
|
||||
{
|
||||
public function __construct(
|
||||
private readonly PreferencesRepository $preferencesRepository,
|
||||
private readonly SaveUserMediaPreferencesHandler $saveUserMediaPreferencesHandler,
|
||||
private readonly Security $security,
|
||||
) {}
|
||||
#[Route('/media/preferences', 'app_media_preferences', methods: ['GET'])]
|
||||
public function mediaPreferences(): Response
|
||||
{
|
||||
$enabledPreferences = $this->preferencesRepository->findEnabled();
|
||||
|
||||
if ($this->security->getUser()->getUserPreferences()->count() !== count($enabledPreferences)) {
|
||||
$this->setUserPreferences($this->security->getUser(), $enabledPreferences);
|
||||
}
|
||||
|
||||
$userPreferences = $this->security->getUser()->getUserPreferences()->toArray();
|
||||
$userPreferences = Map::from($userPreferences)
|
||||
->rekey(fn($preference) => $preference->getPreference()->getId());
|
||||
|
||||
return $this->render(
|
||||
'user/preferences.html.twig',
|
||||
[
|
||||
'preferences' => $this->preferencesRepository->findEnabled(),
|
||||
'languages' => CountryCodes::$countries,
|
||||
'providers' => ['test' => 'Test'],
|
||||
'userPreferences' => $userPreferences->toArray(),
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -34,12 +52,31 @@ class PreferencesController extends AbstractController
|
||||
SaveUserMediaPreferencesInput $input,
|
||||
): Response
|
||||
{
|
||||
dd($input);
|
||||
$userPreferences = $this->saveUserMediaPreferencesHandler->handle($input->toCommand())->userPreferences;
|
||||
$userPreferences = Map::from($userPreferences)->rekey(fn($preference) => $preference->getPreference()->getId());
|
||||
|
||||
return $this->render(
|
||||
'user/preferences.html.twig',
|
||||
[
|
||||
'preferences' => $this->preferencesRepository->findEnabled(),
|
||||
'languages' => CountryCodes::$countries,
|
||||
'providers' => ['test' => 'Test'],
|
||||
'userPreferences' => $userPreferences->toArray(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private function setUserPreferences(User $user, array $preferences): void
|
||||
{
|
||||
foreach ($preferences as $preference) {
|
||||
if (false === $user->hasUserPreference($preference->getId())) {
|
||||
$user->addUserPreference((new UserPreference())
|
||||
->setUser($user)
|
||||
->setPreference($preference)
|
||||
->setPreferenceValue(null)
|
||||
);
|
||||
}
|
||||
}
|
||||
$this->preferencesRepository->getEntityManager()->flush();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
namespace App\User\Framework\Controller\Web;
|
||||
|
||||
use App\User\Framework\Entity\User;
|
||||
use App\User\Framework\Entity\UserPreference;
|
||||
use App\User\Framework\Form\RegistrationFormType;
|
||||
use App\User\Framework\Repository\PreferencesRepository;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@@ -14,8 +16,12 @@ use Symfony\Component\Routing\Attribute\Route;
|
||||
class RegistrationController extends AbstractController
|
||||
{
|
||||
#[Route('/register', name: 'app_register')]
|
||||
public function register(Request $request, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
public function register(
|
||||
Request $request,
|
||||
UserPasswordHasherInterface $userPasswordHasher,
|
||||
EntityManagerInterface $entityManager,
|
||||
PreferencesRepository $preferencesRepository,
|
||||
): Response {
|
||||
$user = new User();
|
||||
$form = $this->createForm(RegistrationFormType::class, $user);
|
||||
$form->handleRequest($request);
|
||||
@@ -30,7 +36,9 @@ class RegistrationController extends AbstractController
|
||||
$entityManager->persist($user);
|
||||
$entityManager->flush();
|
||||
|
||||
// do anything else you need here, like send an email
|
||||
$this->setUserPreferences($user, $preferencesRepository->findEnabled());
|
||||
|
||||
$preferencesRepository->getEntityManager()->flush();
|
||||
|
||||
return $this->redirectToRoute('app_index');
|
||||
}
|
||||
@@ -39,4 +47,15 @@ class RegistrationController extends AbstractController
|
||||
'registrationForm' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
private function setUserPreferences(User $user, array $preferences): void
|
||||
{
|
||||
foreach ($preferences as $preference) {
|
||||
$user->addUserPreference((new UserPreference())
|
||||
->setUser($user)
|
||||
->setPreference($preference)
|
||||
->setPreferenceValue(null)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class Preference
|
||||
/**
|
||||
* @var Collection<int, PreferenceOption>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: PreferenceOption::class, mappedBy: 'preference')]
|
||||
#[ORM\OneToMany(targetEntity: PreferenceOption::class, mappedBy: 'preference', fetch: 'EAGER')]
|
||||
private Collection $preferenceOptions;
|
||||
|
||||
public function __construct()
|
||||
|
||||
@@ -2,13 +2,17 @@
|
||||
|
||||
namespace App\User\Framework\Entity;
|
||||
|
||||
use App\User\Framework\Repository\PreferencesRepository;
|
||||
use App\User\Framework\Repository\UserRepository;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Doctrine\Common\Collections\Collection;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
#[ORM\Entity(repositoryClass: UserRepository::class)]
|
||||
#[ORM\HasLifecycleCallbacks]
|
||||
#[UniqueEntity(fields: ['email'], message: 'There is already an account with this email')]
|
||||
class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
{
|
||||
@@ -29,6 +33,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
#[ORM\Column(type: 'string')]
|
||||
private string $password;
|
||||
|
||||
/**
|
||||
* @var Collection<int, UserPreference>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: UserPreference::class, mappedBy: 'user', cascade: ['persist', 'remove'])]
|
||||
private Collection $userPreferences;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->userPreferences = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@@ -110,4 +125,63 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
// If you store any temporary, sensitive data on the user, clear it here
|
||||
// $this->plainPassword = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, UserPreference>
|
||||
*/
|
||||
public function getUserPreferences(): Collection
|
||||
{
|
||||
return $this->userPreferences;
|
||||
}
|
||||
|
||||
public function getUserPreference(string $preferenceName)
|
||||
{
|
||||
foreach ($this->userPreferences as $userPreference) {
|
||||
if ($userPreference->getPreference()->getName() === $preferenceName) {
|
||||
return $userPreference->getPreference();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function hasUserPreference(string $preferenceName): bool
|
||||
{
|
||||
foreach ($this->userPreferences as $userPreference) {
|
||||
if ($userPreference->getPreference()->getId() === $preferenceName) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function updateUserPreference(string $preferenceName, mixed $preferenceValue): static
|
||||
{
|
||||
foreach ($this->userPreferences as $userPreference) {
|
||||
if ($userPreference->getPreference()->getId() === $preferenceName) {
|
||||
$userPreference->setPreferenceValue($preferenceValue);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addUserPreference(UserPreference $userPreference): static
|
||||
{
|
||||
if (!$this->userPreferences->contains($userPreference)) {
|
||||
$this->userPreferences->add($userPreference);
|
||||
$userPreference->setUser($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeUserPreference(UserPreference $userPreference): static
|
||||
{
|
||||
if ($this->userPreferences->removeElement($userPreference)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($userPreference->getUser() === $this) {
|
||||
$userPreference->setUser(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
67
src/User/Framework/Entity/UserPreference.php
Normal file
67
src/User/Framework/Entity/UserPreference.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Framework\Entity;
|
||||
|
||||
use App\User\Framework\Repository\UserPreferenceRepository;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: UserPreferenceRepository::class)]
|
||||
class UserPreference
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'userPreferences')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?User $user = null;
|
||||
|
||||
#[ORM\ManyToOne(fetch: 'EAGER')]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
private ?Preference $preference = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $preference_value = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getUser(): ?User
|
||||
{
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function setUser(?User $user): static
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPreference(): ?Preference
|
||||
{
|
||||
return $this->preference;
|
||||
}
|
||||
|
||||
public function setPreference(?Preference $preference): static
|
||||
{
|
||||
$this->preference = $preference;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPreferenceValue(): ?string
|
||||
{
|
||||
return $this->preference_value;
|
||||
}
|
||||
|
||||
public function setPreferenceValue(?string $preference_value): static
|
||||
{
|
||||
$this->preference_value = $preference_value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
43
src/User/Framework/Repository/UserPreferenceRepository.php
Normal file
43
src/User/Framework/Repository/UserPreferenceRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\User\Framework\Repository;
|
||||
|
||||
use App\User\Framework\Entity\UserPreference;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<UserPreference>
|
||||
*/
|
||||
class UserPreferenceRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, UserPreference::class);
|
||||
}
|
||||
|
||||
public function findUserPreferences(int $userId): array
|
||||
{
|
||||
return $this->findBy(['userId' => $userId]);
|
||||
}
|
||||
|
||||
public function findUserResolution(int $userId): ?UserPreference
|
||||
{
|
||||
return $this->findOneBy(['userId' => $userId, 'preference' => 'resolution']);
|
||||
}
|
||||
|
||||
public function findUserCodec(int $userId): ?UserPreference
|
||||
{
|
||||
return $this->findOneBy(['userId' => $userId, 'preference' => 'codec']);
|
||||
}
|
||||
|
||||
public function findUserLanguage(int $userId): ?UserPreference
|
||||
{
|
||||
return $this->findOneBy(['userId' => $userId, 'preference' => 'language']);
|
||||
}
|
||||
|
||||
public function findUserProvider(int $userId): ?UserPreference
|
||||
{
|
||||
return $this->findOneBy(['userId' => $userId, 'preference' => 'resolution']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user