Add NPC database table with server-side DataTable and per-NPC game notes
- Npc entity (village spreadsheet columns) + game_notes text field for
the DM's live play notes, plus updated_at touched on every change
- Race / VillageStatus / BloodCartInvolvement / MysteryImportance as
string-backed PHP enums, rendered as dropdowns on the edit form
- /npcs: server-side DataTables (paging, global search and column sort
all run in the backend via NpcRepository::findForDataTable); name cell
links to the edit page, game notes shown truncated
- /npcs/{id}: Bootstrap-themed edit form (all fields + a large game
notes textarea); Symfony forms now use the bootstrap_5 theme
- app.js: generic server-side DataTable wiring driven by data-* on the
<table>/<th> (data-datatable-src, data-row-url, data-format)
- app:npc:import console command - upserts from data/npcs.csv by
(family, name), never overwrites game_notes; --purge / --dry-run
- data/npcs.csv: 180 villagers exported from the working spreadsheet
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Npc;
|
||||
use App\Enum\BloodCartInvolvement;
|
||||
use App\Enum\MysteryImportance;
|
||||
use App\Enum\Race;
|
||||
use App\Enum\VillageStatus;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\EnumType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class NpcType extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$enum = static fn (string $class) => [
|
||||
'class' => $class,
|
||||
'choice_label' => static fn ($case) => $case->value,
|
||||
];
|
||||
|
||||
$builder
|
||||
->add('family', TextType::class)
|
||||
->add('name', TextType::class)
|
||||
->add('age', IntegerType::class, ['required' => false])
|
||||
->add('race', EnumType::class, $enum(Race::class))
|
||||
->add('occupation', TextType::class, ['required' => false])
|
||||
->add('relationships', TextareaType::class, [
|
||||
'required' => false,
|
||||
'label' => 'Relationships / Notes',
|
||||
'attr' => ['rows' => 3],
|
||||
])
|
||||
->add('villageStatus', EnumType::class, $enum(VillageStatus::class))
|
||||
->add('bloodCartInvolvement', EnumType::class, $enum(BloodCartInvolvement::class))
|
||||
->add('mysteryImportance', EnumType::class, $enum(MysteryImportance::class))
|
||||
->add('gameNotes', TextareaType::class, [
|
||||
'required' => false,
|
||||
'label' => 'Game notes',
|
||||
'attr' => ['rows' => 10, 'placeholder' => 'What happened with this NPC during play…'],
|
||||
]);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults(['data_class' => Npc::class]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user