wip: adds preference & preference_option tables

This commit is contained in:
2025-04-28 08:50:51 -05:00
parent 883442225f
commit 7045116b56
14 changed files with 483 additions and 6 deletions

View File

@@ -18,18 +18,18 @@ doctrine:
Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity
auto_mapping: true
mappings:
# App:
# type: attribute
# is_bundle: false
# dir: '%kernel.project_dir%/src/Entity'
# prefix: 'App\Entity'
# alias: App
Download:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Download/Framework/Entity'
prefix: 'App\Download\Framework\Entity'
alias: Download
User:
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/User/Framework/Entity'
prefix: 'App\User\Framework\Entity'
alias: User
controller_resolver:
auto_mapping: false

View File

@@ -6,3 +6,10 @@ controllersIndex:
defaults:
schemes: [ 'https' ]
controllersUser:
resource:
path: ../src/User/Framework/Controller
namespace: App\User\Framework\Controller
type: attribute
defaults:
schemes: ['https']

View File

@@ -0,0 +1,46 @@
<?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 Version20250428133608 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
$this->addSql(<<<'SQL'
CREATE TABLE preference (id VARCHAR(255) NOT NULL, name VARCHAR(255) DEFAULT NULL, description VARCHAR(255) DEFAULT NULL, enabled TINYINT(1) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB
SQL);
$this->addSql(<<<'SQL'
CREATE TABLE preference_option (id INT AUTO_INCREMENT NOT NULL, preference_id VARCHAR(255) DEFAULT NULL, name VARCHAR(255) DEFAULT NULL, value VARCHAR(255) DEFAULT NULL, enabled TINYINT(1) NOT NULL, INDEX IDX_607C52FD81022C0 (preference_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB
SQL);
$this->addSql(<<<'SQL'
ALTER TABLE preference_option ADD CONSTRAINT FK_607C52FD81022C0 FOREIGN KEY (preference_id) REFERENCES preference (id)
SQL);
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql(<<<'SQL'
ALTER TABLE preference_option DROP FOREIGN KEY FK_607C52FD81022C0
SQL);
$this->addSql(<<<'SQL'
DROP TABLE preference
SQL);
$this->addSql(<<<'SQL'
DROP TABLE preference_option
SQL);
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\User\Action\Command;
use OneToMany\RichBundle\Contract\CommandInterface;
/** @implements CommandInterface<SaveUserMediaPreferencesCommand> */
class SaveUserMediaPreferencesCommand implements CommandInterface
{
public function __construct(
public string $resolution,
public string $codec,
public string $language,
public string $provider,
) {}
}

View File

@@ -0,0 +1,18 @@
<?php
namespace App\User\Action\Handler;
use App\User\Action\Command\SaveUserMediaPreferencesCommand;
use App\User\Action\Result\SaveUserMediaPreferencesResult;
use OneToMany\RichBundle\Contract\CommandInterface as C;
use OneToMany\RichBundle\Contract\HandlerInterface;
use OneToMany\RichBundle\Contract\ResultInterface as R;
/** @implements HandlerInterface<SaveUserMediaPreferencesCommand> */
class SaveUserMediaPreferencesHandler implements HandlerInterface
{
public function handle(C $command): R
{
return new SaveUserMediaPreferencesResult('Success');
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\User\Action\Input;
use App\User\Action\Command\SaveUserMediaPreferencesCommand;
use OneToMany\RichBundle\Attribute\SourceRequest;
use OneToMany\RichBundle\Contract\CommandInterface as C;
use OneToMany\RichBundle\Contract\InputInterface;
/** @implements InputInterface<SaveUserMediaPreferencesInput, SaveUserMediaPreferencesCommand> */
class SaveUserMediaPreferencesInput implements InputInterface
{
public function __construct(
#[SourceRequest('resolution')]
public string $resolution,
#[SourceRequest('codec')]
public string $codec,
#[SourceRequest('language')]
public string $language,
#[SourceRequest('provider')]
public string $provider,
) {}
public function toCommand(): C
{
return new SaveUserMediaPreferencesCommand(
$this->resolution,
$this->codec,
$this->language,
$this->provider,
);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace App\User\Action\Result;
use OneToMany\RichBundle\Contract\ResultInterface;
/** @implements ResultInterface */
class SaveUserMediaPreferencesResult implements ResultInterface
{
public function __construct(
public string $status,
) {}
}

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace App\User\Framework\Controller\Web;
use App\User\Action\Input\SaveUserMediaPreferencesInput;
use App\User\Framework\Repository\PreferencesRepository;
use App\Util\CountryCodes;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
class PreferencesController extends AbstractController
{
public function __construct(
private readonly PreferencesRepository $preferencesRepository,
) {}
#[Route('/media/preferences', 'app_media_preferences', methods: ['GET'])]
public function mediaPreferences(): Response
{
return $this->render(
'user/preferences.html.twig',
[
'preferences' => $this->preferencesRepository->findEnabled(),
'languages' => CountryCodes::$countries,
'providers' => ['test' => 'Test'],
]
);
}
#[Route('/media/preferences', 'app_save_media_preferences', methods: ['POST'])]
public function saveMediaPreferences(
SaveUserMediaPreferencesInput $input,
): Response
{
dd($input);
return $this->render(
'user/preferences.html.twig',
[
'preferences' => $this->preferencesRepository->findEnabled(),
]
);
}
}

View File

@@ -0,0 +1,107 @@
<?php
namespace App\User\Framework\Entity;
use App\User\Framework\Repository\PreferencesRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: PreferencesRepository::class)]
class Preference
{
#[ORM\Id]
#[ORM\Column]
private ?string $id = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $name = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $description = null;
#[ORM\Column]
private ?bool $enabled = null;
/**
* @var Collection<int, PreferenceOption>
*/
#[ORM\OneToMany(targetEntity: PreferenceOption::class, mappedBy: 'preference')]
private Collection $preferenceOptions;
public function __construct()
{
$this->preferenceOptions = new ArrayCollection();
}
public function getId(): ?string
{
return $this->id;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(?string $name): static
{
$this->name = $name;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function isEnabled(): ?bool
{
return $this->enabled;
}
public function setEnabled(bool $enabled): static
{
$this->enabled = $enabled;
return $this;
}
/**
* @return Collection<int, PreferenceOption>
*/
public function getPreferenceOptions(): Collection
{
return $this->preferenceOptions;
}
public function addPreferenceOption(PreferenceOption $preferenceOption): static
{
if (!$this->preferenceOptions->contains($preferenceOption)) {
$this->preferenceOptions->add($preferenceOption);
$preferenceOption->setPreference($this);
}
return $this;
}
public function removePreferenceOption(PreferenceOption $preferenceOption): static
{
if ($this->preferenceOptions->removeElement($preferenceOption)) {
// set the owning side to null (unless already changed)
if ($preferenceOption->getPreference() === $this) {
$preferenceOption->setPreference(null);
}
}
return $this;
}
}

View File

@@ -0,0 +1,80 @@
<?php
namespace App\User\Framework\Entity;
use App\User\Framework\Repository\PreferenceOptionRepository;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity(repositoryClass: PreferenceOptionRepository::class)]
class PreferenceOption
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $name = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $value = null;
#[ORM\ManyToOne(inversedBy: 'preferenceOptions')]
private ?Preference $preference = null;
#[ORM\Column]
private ?bool $enabled = null;
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 getValue(): ?string
{
return $this->value;
}
public function setValue(?string $value): static
{
$this->value = $value;
return $this;
}
public function getPreference(): ?Preference
{
return $this->preference;
}
public function setPreference(?Preference $preference): static
{
$this->preference = $preference;
return $this;
}
public function isEnabled(): ?bool
{
return $this->enabled;
}
public function setEnabled(bool $enabled): static
{
$this->enabled = $enabled;
return $this;
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace App\User\Framework\Repository;
use App\User\Framework\Entity\PreferenceOption;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<PreferenceOption>
*/
class PreferenceOptionRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, PreferenceOption::class);
}
// /**
// * @return PreferenceOption[] Returns an array of PreferenceOption 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): ?PreferenceOption
// {
// return $this->createQueryBuilder('p')
// ->andWhere('p.exampleField = :val')
// ->setParameter('val', $value)
// ->getQuery()
// ->getOneOrNullResult()
// ;
// }
}

View File

@@ -0,0 +1,28 @@
<?php
namespace App\User\Framework\Repository;
use App\User\Framework\Entity\Preference;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<Preference>
*/
class PreferencesRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, Preference::class);
}
/** @return Preference[] Returns an array of Preferences objects */
public function findEnabled(): array
{
return $this->createQueryBuilder('p')
->andWhere('p.enabled = :val')
->setParameter('val', true)
->getQuery()
->getResult();
}
}

View File

@@ -20,6 +20,7 @@
<twig:NavBar />
</div>
<div class="col-span-5">
<h2 class="p-4 mb-2 text-3xl font-bold text-gray-50">{% block h2 %}{% endblock %}</h2>
{% block body %}{% endblock %}
</div>
</div>

View File

@@ -0,0 +1,37 @@
{% extends 'base.html.twig' %}
{% block title %}Preferences{% endblock %}
{% block h2 %}Preferences{% endblock %}
{% block body %}
<div class="p-4 flex flex-col">
<twig:Card title="Choose your preferences">
<p class="text-gray-50 mb-2">Define a set of filters to apply to your media download option results.</p>
<form id="media_preferences" class="flex flex-col max-w-64" name="media_preferences" method="post" action="{{ path('app_media_preferences') }}">
{% for preference in preferences %}
<label class="text-gray-50" for="{{ preference.name }}">{{ preference.name }}</label>
{% if preference.name|lower == "language" %}
<select class="p-1.5 rounded-md mb-2" name="{{ preference.name|lower }}" id="{{ preference.name }}">
{% for key, value in languages %}
<option class="text-gray-800" value="{{ key }}">{{ value }}</option>
{% endfor %}
</select>
{% elseif preference.name|lower == "provider" %}
<select class="p-1.5 rounded-md mb-2" name="{{ preference.name|lower }}" id="{{ preference.name }}">
{% for key, value in providers %}
<option class="text-gray-800" value="{{ key }}">{{ value }}</option>
{% endfor %}
</select>
{% else %}
<select class="p-1.5 rounded-md mb-2" name="{{ preference.name|lower }}" id="{{ preference.name }}">
{% for option in preference.preferenceOptions %}
<option class="text-gray-800" value="{{ option.id }}">{{ option.name }}</option>
{% endfor %}
</select>
{% endif %}
{% endfor %}
<button class="px-1.5 py-1 max-w-20 rounded-md bg-green-600 text-white" type="submit">Submit</button>
</form>
</twig:Card>
</div>
{% endblock %}