Skip to content

Commit 5aab43a

Browse files
dunglasweaverryan
authored andcommitted
Add support for Symfony UX Turbo
1 parent e3e3c61 commit 5aab43a

File tree

7 files changed

+114
-2
lines changed

7 files changed

+114
-2
lines changed

.github/workflows/ci.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ jobs:
6565
ports:
6666
- 3306
6767
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
68+
mercure:
69+
image: dunglas/mercure
70+
env:
71+
SERVER_NAME: :1337
72+
MERCURE_PUBLISHER_JWT_KEY: '!ChangeMe!'
73+
MERCURE_SUBSCRIBER_JWT_KEY: '!ChangeMe!'
74+
MERCURE_EXTRA_DIRECTIVES: |
75+
anonymous
76+
cors_origins *
77+
ports:
78+
- 1337:1337
6879

6980
continue-on-error: ${{ matrix.allow-failures }}
7081

src/Doctrine/EntityClassGenerator.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public function __construct(Generator $generator, DoctrineHelper $doctrineHelper
3333
$this->doctrineHelper = $doctrineHelper;
3434
}
3535

36-
public function generateEntityClass(ClassNameDetails $entityClassDetails, bool $apiResource, bool $withPasswordUpgrade = false, bool $generateRepositoryClass = true): string
36+
public function generateEntityClass(ClassNameDetails $entityClassDetails, bool $apiResource, bool $withPasswordUpgrade = false, bool $generateRepositoryClass = true, bool $broadcast = false): string
3737
{
3838
$repoClassDetails = $this->generator->createClassNameDetails(
3939
$entityClassDetails->getRelativeName(),
@@ -50,6 +50,7 @@ public function generateEntityClass(ClassNameDetails $entityClassDetails, bool $
5050
'repository_full_class_name' => $repoClassDetails->getFullName(),
5151
'repository_class_name' => $repoClassDetails->getShortName(),
5252
'api_resource' => $apiResource,
53+
'broadcast' => $broadcast,
5354
'should_escape_table_name' => $this->doctrineHelper->isKeyword($tableName),
5455
'table_name' => $tableName,
5556
]

src/Maker/MakeEntity.php

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Symfony\Component\Console\Input\InputOption;
3636
use Symfony\Component\Console\Question\ConfirmationQuestion;
3737
use Symfony\Component\Console\Question\Question;
38+
use Symfony\UX\Turbo\Attribute\Broadcast;
3839

3940
/**
4041
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
@@ -84,6 +85,7 @@ public function configureCommand(Command $command, InputConfiguration $inputConf
8485
$command
8586
->addArgument('name', InputArgument::OPTIONAL, sprintf('Class name of the entity to create or update (e.g. <fg=yellow>%s</>)', Str::asClassName(Str::getRandomTerm())))
8687
->addOption('api-resource', 'a', InputOption::VALUE_NONE, 'Mark this class as an API Platform resource (expose a CRUD API for it)')
88+
->addOption('broadcast', 'b', InputOption::VALUE_NONE, 'Add the ability to broadcast entity updates using Symfony UX Turbo?')
8789
->addOption('regenerate', null, InputOption::VALUE_NONE, 'Instead of adding new fields, simply generate the methods (e.g. getter/setter) for existing fields')
8890
->addOption('overwrite', null, InputOption::VALUE_NONE, 'Overwrite any existing getter/setter methods')
8991
->setHelp(file_get_contents(__DIR__.'/../Resources/help/MakeEntity.txt'))
@@ -127,6 +129,18 @@ class_exists(ApiResource::class) &&
127129

128130
$input->setOption('api-resource', $value);
129131
}
132+
133+
if (
134+
!$input->getOption('broadcast') &&
135+
class_exists(Broadcast::class) &&
136+
!class_exists($this->generator->createClassNameDetails($value, 'Entity\\')->getFullName())
137+
) {
138+
$description = $command->getDefinition()->getOption('broadcast')->getDescription();
139+
$question = new ConfirmationQuestion($description, false);
140+
$value = $io->askQuestion($question);
141+
142+
$input->setOption('broadcast', $value);
143+
}
130144
}
131145

132146
public function generate(InputInterface $input, ConsoleStyle $io, Generator $generator)
@@ -148,11 +162,27 @@ public function generate(InputInterface $input, ConsoleStyle $io, Generator $gen
148162

149163
$classExists = class_exists($entityClassDetails->getFullName());
150164
if (!$classExists) {
165+
$broadcast = $input->getOption('broadcast');
151166
$entityPath = $this->entityClassGenerator->generateEntityClass(
152167
$entityClassDetails,
153-
$input->getOption('api-resource')
168+
$input->getOption('api-resource'),
169+
false,
170+
true,
171+
$broadcast
154172
);
155173

174+
if ($broadcast) {
175+
$shortName = $entityClassDetails->getShortName();
176+
$generator->generateTemplate(
177+
sprintf('broadcast/%s.stream.html.twig', $shortName),
178+
'doctrine/broadcast_twig_template.tpl.php',
179+
[
180+
'class_name' => Str::asSnakeCase($shortName),
181+
'class_name_plural' => Str::asSnakeCase(Str::singularCamelCaseToPluralCamelCase($shortName)),
182+
]
183+
);
184+
}
185+
156186
$generator->writeChanges();
157187
}
158188

@@ -280,6 +310,13 @@ public function configureDependencies(DependencyBuilder $dependencies, InputInte
280310
);
281311
}
282312

313+
if (null !== $input && $input->getOption('broadcast')) {
314+
$dependencies->addClassDependency(
315+
Broadcast::class,
316+
'ux-turbo-mercure'
317+
);
318+
}
319+
283320
ORMDependencyBuilder::buildDependencies($dependencies);
284321
}
285322

src/Resources/help/MakeEntity.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ automatically be available for this entity class:
99

1010
<info>php %command.full_name% --api-resource</info>
1111

12+
Symfony can also broadcast all changes made to the entity to the client using Symfony
13+
UX Turbo.
14+
15+
<info>php %command.full_name% --broadcast</info>
16+
1217
You can also generate all the getter/setter/adder/remover methods
1318
for the properties of existing entities:
1419

src/Resources/skeleton/doctrine/Entity.tpl.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@
66
<?php endif ?>
77
use <?= $repository_full_class_name ?>;
88
use Doctrine\ORM\Mapping as ORM;
9+
<?php if ($broadcast): ?>use Symfony\UX\Turbo\Attribute\Broadcast;
10+
<?php endif ?>
911

1012
/**
1113
<?php if ($api_resource && !$use_attributes): ?> * @ApiResource()
14+
<?php endif ?>
15+
<?php if ($broadcast && !$use_attributes): ?> * @Broadcast()
1216
<?php endif ?>
1317
* @ORM\Entity(repositoryClass=<?= $repository_class_name ?>::class)
1418
<?php if ($should_escape_table_name): ?> * @ORM\Table(name="`<?= $table_name ?>`")
@@ -17,6 +21,9 @@
1721
<?php if ($api_resource && $use_attributes): ?>
1822
#[ApiResource]
1923
<?php endif ?>
24+
<?php if ($broadcast && $use_attributes): ?>
25+
#[Broadcast]
26+
<?php endif ?>
2027
class <?= $class_name."\n" ?>
2128
{
2229
/**
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{# Learn how to use Turbo Streams: https://github.com/symfony/ux-turbo#broadcast-doctrine-entities-update #}
2+
{% block create %}
3+
<turbo-stream action="append" target="<?= $class_name_plural ?>">
4+
<template>
5+
<div id="{{ '<?= $class_name ?>_' ~ id }}">
6+
#{{ id }} created
7+
</div>
8+
</template>
9+
</turbo-stream>
10+
{% endblock %}
11+
12+
{% block update %}
13+
<turbo-stream action="update" target="<?= $class_name ?>_{{ id }}">
14+
<template>
15+
#{{ id }} updated
16+
</template>
17+
</turbo-stream>
18+
{% endblock %}
19+
20+
{% block remove %}
21+
<turbo-stream action="remove" target="<?= $class_name ?>_{{ id }}"></turbo-stream>
22+
{% endblock %}

tests/Maker/MakeEntityTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,5 +564,34 @@ public function getTestDetails()
564564
->configureDatabase()
565565
->updateSchemaAfterCommand(),
566566
];
567+
568+
yield 'entity_new_broadcast' => [MakerTestDetails::createTest(
569+
$this->getMakerInstance(MakeEntity::class),
570+
[
571+
// entity class name
572+
'User',
573+
// Mark the entity as broadcasted
574+
'y',
575+
// add not additional fields
576+
'',
577+
])
578+
->setRequiredPhpVersion(70200)
579+
->addExtraDependencies('ux-turbo-mercure')
580+
->setFixtureFilesPath(__DIR__.'/../fixtures/MakeEntity')
581+
->configureDatabase()
582+
->addReplacement(
583+
'.env',
584+
'https://127.0.0.1:8000/.well-known/mercure',
585+
'http://127.0.0.1:1337/.well-known/mercure'
586+
)
587+
->updateSchemaAfterCommand()
588+
->assert(function (string $output, string $directory) {
589+
$this->assertFileExists($directory.'/src/Entity/User.php');
590+
591+
$content = file_get_contents($directory.'/src/Entity/User.php');
592+
$this->assertStringContainsString('use Symfony\UX\Turbo\Attribute\Broadcast;', $content);
593+
$this->assertStringContainsString(\PHP_VERSION_ID >= 80000 ? '#[Broadcast]' : '@Broadcast', $content);
594+
}),
595+
];
567596
}
568597
}

0 commit comments

Comments
 (0)