Skip to content

Commit

Permalink
Merge pull request #990 from cakephp/fix-enum-gen
Browse files Browse the repository at this point in the history
Improve enum generation
  • Loading branch information
dereuromark authored Jun 2, 2024
2 parents 976dbe3 + 357076f commit b8f25d0
Show file tree
Hide file tree
Showing 18 changed files with 389 additions and 13 deletions.
22 changes: 22 additions & 0 deletions src/View/Helper/BakeHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
use Cake\Core\Configure;
use Cake\Core\ConventionsTrait;
use Cake\Database\Schema\TableSchema;
use Cake\Database\Type\EnumType;
use Cake\Database\TypeFactory;
use Cake\Datasource\SchemaInterface;
use Cake\ORM\Table;
use Cake\Utility\Inflector;
Expand Down Expand Up @@ -281,6 +283,26 @@ public function columnData(string $field, TableSchema $schema): ?array
return $schema->getColumn($field);
}

/**
* Check if a column is both an enum, and the mapped enum implements `label()` as a method.
*
* @param string $field the field to check
* @param \Cake\Database\Schema\TableSchema $schema The table schema to read from.
* @return bool
*/
public function enumSupportsLabel(string $field, TableSchema $schema): bool
{
$typeName = $schema->getColumnType($field);
if (!str_starts_with($typeName, 'enum-')) {
return false;
}
$type = TypeFactory::build($typeName);
assert($type instanceof EnumType);
$enumClass = $type->getEnumClassName();

return method_exists($enumClass, 'label');
}

/**
* Get alias of associated table.
*
Expand Down
5 changes: 3 additions & 2 deletions templates/bake/Template/index.twig
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@
{% endif %}
{% if isKey is not same as(true) %}
{% set columnData = Bake.columnData(field, schema) %}
{% set supportsLabel = Bake.enumSupportsLabel(field, schema) %}
{% if columnData.type starts with 'enum-' %}
<td><?= ${{ singularVar }}->{{ field }} === null ? '' : h(${{ singularVar }}->{{ field }}->label()) ?></td>
<td><?= ${{ singularVar }}->{{ field }} === null ? '' : h(${{ singularVar }}->{{ field }}->{% if supportsLabel %}label(){% else %}value{% endif %}) ?></td>
{% elseif columnData.type not in ['integer', 'float', 'decimal', 'biginteger', 'smallinteger', 'tinyinteger'] %}
<td><?= h(${{ singularVar }}->{{ field }}) ?></td>
{% elseif columnData.null %}
Expand Down Expand Up @@ -81,4 +82,4 @@
</ul>
<p><?= $this->Paginator->counter(__('Page {{ '{{' }}page{{ '}}' }} of {{ '{{' }}pages{{ '}}' }}, showing {{ '{{' }}current{{ '}}' }} record(s) out of {{ '{{' }}count{{ '}}' }} total')) ?></p>
</div>
</div>
</div>
7 changes: 4 additions & 3 deletions templates/bake/Template/view.twig
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,11 @@
<tr>
<th><?= __('{{ field|humanize }}') ?></th>
{% set columnData = Bake.columnData(field, schema) %}
{% set supportsLabel = Bake.enumSupportsLabel(field, schema) %}
{% if columnData.null %}
<td><?= ${{ singularVar }}->{{ field }} === null ? '' : h(${{ singularVar }}->{{ field }}->label()) ?></td>
<td><?= ${{ singularVar }}->{{ field }} === null ? '' : h(${{ singularVar }}->{{ field }}->{% if supportsLabel %}label(){% else %}value{% endif %}) ?></td>
{% else %}
<td><?= h(${{ singularVar }}->{{ field }}->label()) ?></td>
<td><?= h(${{ singularVar }}->{{ field }}->{% if supportsLabel %}label(){% else %}value{% endif %}) ?></td>
{% endif %}
</tr>
{% endfor %}
Expand Down Expand Up @@ -151,4 +152,4 @@
{% endfor %}
</div>
</div>
</div>
</div>
85 changes: 85 additions & 0 deletions tests/TestCase/Command/TemplateCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
namespace Bake\Test\TestCase\Command;

use Bake\Command\TemplateCommand;
use Bake\Test\App\Model\Enum\ArticleStatus;
use Bake\Test\App\Model\Enum\BakeUserStatus;
use Bake\Test\App\Model\Table\BakeArticlesTable;
use Bake\Test\TestCase\TestCase;
use Cake\Console\Arguments;
Expand All @@ -25,6 +27,7 @@
use Cake\Console\Exception\StopException;
use Cake\Core\Configure;
use Cake\Core\Plugin;
use Cake\Database\Type\EnumType;
use Cake\View\Exception\MissingTemplateException;

/**
Expand All @@ -42,6 +45,7 @@ class TemplateCommandTest extends TestCase
'plugin.Bake.Tags',
'plugin.Bake.ArticlesTags',
'plugin.Bake.Posts',
'plugin.Bake.Users',
'plugin.Bake.Comments',
'plugin.Bake.BakeArticles',
'plugin.Bake.BakeTemplateAuthors',
Expand Down Expand Up @@ -449,6 +453,47 @@ public function testBakeView()
$this->assertSameAsFile(__FUNCTION__ . '.php', $result);
}

/**
* test baking view with enum class
*
* @return void
*/
public function testBakeViewEnum()
{
$table = $this->fetchTable('BakeUsers');
$table->associations()->removeAll();
$table->getSchema()->setColumnType('status', EnumType::from(BakeUserStatus::class));

$this->generatedFile = ROOT . 'templates/BakeUsers/view.php';
$this->exec('bake template bake_users view');

$this->assertExitCode(CommandInterface::CODE_SUCCESS);
$this->assertFileExists($this->generatedFile);

$result = file_get_contents($this->generatedFile);
$this->assertSameAsFile(__FUNCTION__ . '.php', $result);
}

/**
* test baking view with enum class
*
* @return void
*/
public function testBakeViewEnumNoLabel()
{
$table = $this->fetchTable('Articles');
$table->getSchema()->setColumnType('status', EnumType::from(ArticleStatus::class));

$this->generatedFile = ROOT . 'templates/Articles/view.php';
$this->exec('bake template articles view');

$this->assertExitCode(CommandInterface::CODE_SUCCESS);
$this->assertFileExists($this->generatedFile);

$result = file_get_contents($this->generatedFile);
$this->assertSameAsFile(__FUNCTION__ . '.php', $result);
}

/**
* Test generating view template with hidden fields
*
Expand Down Expand Up @@ -551,6 +596,46 @@ public function testBakeIndexWithIndexLimit()
$this->assertSameAsFile(__FUNCTION__ . '.php', $result);
}

/**
* test bake template with index enum types
*
* @return void
*/
public function testBakeIndexWithEnumWithLabel()
{
$table = $this->fetchTable('BakeUsers');
$table->getSchema()->setColumnType('status', EnumType::from(BakeUserStatus::class));

$this->generatedFile = ROOT . 'templates/BakeUsers/index.php';
$this->exec('bake template bake_users index');

$this->assertExitCode(CommandInterface::CODE_SUCCESS);
$this->assertFileExists($this->generatedFile);

$result = file_get_contents($this->generatedFile);
$this->assertSameAsFile(__FUNCTION__ . '.php', $result);
}

/**
* test bake template with index enum types
*
* @return void
*/
public function testBakeIndexWithEnumNoLabel()
{
$table = $this->fetchTable('Articles');
$table->getSchema()->setColumnType('status', EnumType::from(ArticleStatus::class));

$this->generatedFile = ROOT . 'templates/Articles/index.php';
$this->exec('bake template articles index');

$this->assertExitCode(CommandInterface::CODE_SUCCESS);
$this->assertFileExists($this->generatedFile);

$result = file_get_contents($this->generatedFile);
$this->assertSameAsFile(__FUNCTION__ . '.php', $result);
}

/**
* test Bake with plugins
*
Expand Down
2 changes: 1 addition & 1 deletion tests/comparisons/Template/testBakeIndex.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@
</ul>
<p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
</div>
</div>
</div>
2 changes: 1 addition & 1 deletion tests/comparisons/Template/testBakeIndexHiddenFields.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@
</ul>
<p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
</div>
</div>
</div>
50 changes: 50 additions & 0 deletions tests/comparisons/Template/testBakeIndexWithEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* @var \Bake\Test\App\View\AppView $this
* @var iterable<\Cake\Datasource\EntityInterface> $bakeUsers
*/
?>
<div class="bakeUsers index content">
<?= $this->Html->link(__('New Bake User'), ['action' => 'add'], ['class' => 'button float-right']) ?>
<h3><?= __('Bake Users') ?></h3>
<div class="table-responsive">
<table>
<thead>
<tr>
<th><?= $this->Paginator->sort('id') ?></th>
<th><?= $this->Paginator->sort('username') ?></th>
<th><?= $this->Paginator->sort('status') ?></th>
<th><?= $this->Paginator->sort('created') ?></th>
<th><?= $this->Paginator->sort('updated') ?></th>
<th class="actions"><?= __('Actions') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($bakeUsers as $bakeUser): ?>
<tr>
<td><?= $this->Number->format($bakeUser->id) ?></td>
<td><?= h($bakeUser->username) ?></td>
<td><?= $bakeUser->status === null ? '' : h($bakeUser->status->label()) ?></td>
<td><?= h($bakeUser->created) ?></td>
<td><?= h($bakeUser->updated) ?></td>
<td class="actions">
<?= $this->Html->link(__('View'), ['action' => 'view', $bakeUser->id]) ?>
<?= $this->Html->link(__('Edit'), ['action' => 'edit', $bakeUser->id]) ?>
<?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $bakeUser->id], ['confirm' => __('Are you sure you want to delete # {0}?', $bakeUser->id)]) ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="paginator">
<ul class="pagination">
<?= $this->Paginator->first('<< ' . __('first')) ?>
<?= $this->Paginator->prev('< ' . __('previous')) ?>
<?= $this->Paginator->numbers() ?>
<?= $this->Paginator->next(__('next') . ' >') ?>
<?= $this->Paginator->last(__('last') . ' >>') ?>
</ul>
<p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
</div>
</div>
48 changes: 48 additions & 0 deletions tests/comparisons/Template/testBakeIndexWithEnumNoLabel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php
/**
* @var \Bake\Test\App\View\AppView $this
* @var iterable<\Cake\Datasource\EntityInterface> $articles
*/
?>
<div class="articles index content">
<?= $this->Html->link(__('New Article'), ['action' => 'add'], ['class' => 'button float-right']) ?>
<h3><?= __('Articles') ?></h3>
<div class="table-responsive">
<table>
<thead>
<tr>
<th><?= $this->Paginator->sort('id') ?></th>
<th><?= $this->Paginator->sort('author_id') ?></th>
<th><?= $this->Paginator->sort('title') ?></th>
<th><?= $this->Paginator->sort('published') ?></th>
<th class="actions"><?= __('Actions') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($articles as $article): ?>
<tr>
<td><?= $this->Number->format($article->id) ?></td>
<td><?= $article->hasValue('author') ? $this->Html->link($article->author->name, ['controller' => 'Authors', 'action' => 'view', $article->author->id]) : '' ?></td>
<td><?= h($article->title) ?></td>
<td><?= $article->published === null ? '' : h($article->published->value) ?></td>
<td class="actions">
<?= $this->Html->link(__('View'), ['action' => 'view', $article->id]) ?>
<?= $this->Html->link(__('Edit'), ['action' => 'edit', $article->id]) ?>
<?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $article->id], ['confirm' => __('Are you sure you want to delete # {0}?', $article->id)]) ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="paginator">
<ul class="pagination">
<?= $this->Paginator->first('<< ' . __('first')) ?>
<?= $this->Paginator->prev('< ' . __('previous')) ?>
<?= $this->Paginator->numbers() ?>
<?= $this->Paginator->next(__('next') . ' >') ?>
<?= $this->Paginator->last(__('last') . ' >>') ?>
</ul>
<p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
</div>
</div>
50 changes: 50 additions & 0 deletions tests/comparisons/Template/testBakeIndexWithEnumWithLabel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* @var \Bake\Test\App\View\AppView $this
* @var iterable<\Cake\Datasource\EntityInterface> $bakeUsers
*/
?>
<div class="bakeUsers index content">
<?= $this->Html->link(__('New Bake User'), ['action' => 'add'], ['class' => 'button float-right']) ?>
<h3><?= __('Bake Users') ?></h3>
<div class="table-responsive">
<table>
<thead>
<tr>
<th><?= $this->Paginator->sort('id') ?></th>
<th><?= $this->Paginator->sort('username') ?></th>
<th><?= $this->Paginator->sort('status') ?></th>
<th><?= $this->Paginator->sort('created') ?></th>
<th><?= $this->Paginator->sort('updated') ?></th>
<th class="actions"><?= __('Actions') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($bakeUsers as $bakeUser): ?>
<tr>
<td><?= $this->Number->format($bakeUser->id) ?></td>
<td><?= h($bakeUser->username) ?></td>
<td><?= $bakeUser->status === null ? '' : h($bakeUser->status->label()) ?></td>
<td><?= h($bakeUser->created) ?></td>
<td><?= h($bakeUser->updated) ?></td>
<td class="actions">
<?= $this->Html->link(__('View'), ['action' => 'view', $bakeUser->id]) ?>
<?= $this->Html->link(__('Edit'), ['action' => 'edit', $bakeUser->id]) ?>
<?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $bakeUser->id], ['confirm' => __('Are you sure you want to delete # {0}?', $bakeUser->id)]) ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="paginator">
<ul class="pagination">
<?= $this->Paginator->first('<< ' . __('first')) ?>
<?= $this->Paginator->prev('< ' . __('previous')) ?>
<?= $this->Paginator->numbers() ?>
<?= $this->Paginator->next(__('next') . ' >') ?>
<?= $this->Paginator->last(__('last') . ' >>') ?>
</ul>
<p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
</div>
</div>
2 changes: 1 addition & 1 deletion tests/comparisons/Template/testBakeIndexWithIndexLimit.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,4 @@
</ul>
<p><?= $this->Paginator->counter(__('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')) ?></p>
</div>
</div>
</div>
2 changes: 1 addition & 1 deletion tests/comparisons/Template/testBakeView.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,4 @@
</div>
</div>
</div>
</div>
</div>
Loading

0 comments on commit b8f25d0

Please sign in to comment.