Skip to content

Commit 094fb0a

Browse files
committed
Standardize cell behavior
1 parent b9b9e48 commit 094fb0a

File tree

7 files changed

+103
-44
lines changed

7 files changed

+103
-44
lines changed

app/Config/Generators.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class Generators extends BaseConfig
2727
*/
2828
public array $views = [
2929
'make:cell' => 'CodeIgniter\Commands\Generators\Views\cell.tpl.php',
30+
'make:cell_view' => 'CodeIgniter\Commands\Generators\Views\cell_view.tpl.php',
3031
'make:command' => 'CodeIgniter\Commands\Generators\Views\command.tpl.php',
3132
'make:config' => 'CodeIgniter\Commands\Generators\Views\config.tpl.php',
3233
'make:controller' => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php',

system/CLI/GeneratorTrait.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,16 @@ protected function qualifyClassName(): string
235235
$component = singular($this->component);
236236

237237
/**
238-
* @see https://regex101.com/r/a5KNCR/1
238+
* @see https://regex101.com/r/a5KNCR/2
239239
*/
240-
$pattern = sprintf('/([a-z][a-z0-9_\/\\\\]+)(%s)/i', $component);
240+
$pattern = sprintf('/([a-z][a-z0-9_\/\\\\]+)(%s)$/i', $component);
241241

242242
if (preg_match($pattern, $class, $matches) === 1) {
243243
$class = $matches[1] . ucfirst($matches[2]);
244+
unset($matches);
244245
}
245246

246-
if ($this->enabledSuffixing && $this->getOption('suffix') && ! strripos($class, $component)) {
247+
if ($this->enabledSuffixing && $this->getOption('suffix') && preg_match($pattern, $class) !== 1) {
247248
$class .= ucfirst($component);
248249
}
249250

system/Commands/Generators/CellGenerator.php

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ class CellGenerator extends BaseCommand
6565
*/
6666
protected $options = [
6767
'--namespace' => 'Set root namespace. Default: "APP_NAMESPACE".',
68-
'--suffix' => 'Append the component title to the class name (e.g. User => UserCell).',
6968
'--force' => 'Force overwrite existing file.',
7069
];
7170

@@ -74,27 +73,26 @@ class CellGenerator extends BaseCommand
7473
*/
7574
public function run(array $params)
7675
{
77-
// Generate the Class first
78-
$this->component = 'Cell';
79-
$this->directory = 'Cells';
76+
$this->component = 'Cell';
77+
$this->directory = 'Cells';
78+
79+
$params = [...$params, ...['suffix' => null]];
80+
8081
$this->template = 'cell.tpl.php';
8182
$this->classNameLang = 'CLI.generator.className.cell';
82-
8383
$this->generateClass($params);
8484

85-
// Generate the View
85+
$this->name = 'make:cell_view';
86+
$this->template = 'cell_view.tpl.php';
8687
$this->classNameLang = 'CLI.generator.viewName.cell';
8788

88-
// Form the view name
89-
$segments = explode('\\', $this->qualifyClassName());
90-
91-
$view = array_pop($segments);
92-
$view = decamelize($view);
93-
$segments[] = $view;
94-
$view = implode('\\', $segments);
89+
$className = $this->qualifyClassName();
90+
$viewName = decamelize(class_basename($className));
91+
$viewName = preg_replace('/([a-z][a-z0-9_\/\\\\]+)(_cell)$/i', '$1', $viewName) ?? $viewName;
92+
$namespace = substr($className, 0, strrpos($className, '\\') + 1);
9593

96-
$this->template = 'cell_view.tpl.php';
94+
$this->generateView($namespace . $viewName, $params);
9795

98-
$this->generateView($view, $params);
96+
return 0;
9997
}
10098
}

system/View/Cells/Cell.php

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use CodeIgniter\Traits\PropertiesTrait;
1515
use ReflectionClass;
16+
use RuntimeException;
1617

1718
/**
1819
* Class Cell
@@ -64,37 +65,48 @@ public function setView(string $view)
6465
* from within the view, this method extracts $data into the
6566
* current scope and captures the output buffer instead of
6667
* relying on the view service.
68+
*
69+
* @throws RuntimeException
6770
*/
6871
final protected function view(?string $view, array $data = []): string
6972
{
7073
$properties = $this->getPublicProperties();
7174
$properties = $this->includeComputedProperties($properties);
7275
$properties = array_merge($properties, $data);
7376

74-
// If no view is specified, we'll try to guess it based on the class name.
75-
if (empty($view)) {
76-
// According to the docs, the name of the view file should be the
77-
// snake_cased version of the cell's class name, but for backward
78-
// compatibility, the name also accepts '_cell' being omitted.
79-
$ref = new ReflectionClass($this);
80-
$view = decamelize($ref->getShortName());
81-
$viewPath = dirname($ref->getFileName()) . DIRECTORY_SEPARATOR . $view . '.php';
82-
$view = is_file($viewPath) ? $viewPath : str_replace('_cell', '', $view);
77+
$view = (string) $view;
78+
79+
if ($view === '') {
80+
$viewName = decamelize(class_basename(static::class));
81+
$directory = dirname((new ReflectionClass($this))->getFileName()) . DIRECTORY_SEPARATOR;
82+
83+
$possibleView1 = $directory . substr($viewName, 0, strrpos($viewName, '_cell')) . '.php';
84+
$possibleView2 = $directory . $viewName . '.php';
8385
}
8486

85-
// Locate our view, preferring the directory of the class.
8687
if (! is_file($view)) {
87-
// Get the local pathname of the Cell
88-
$ref = new ReflectionClass($this);
89-
$view = dirname($ref->getFileName()) . DIRECTORY_SEPARATOR . $view . '.php';
88+
$directory = dirname((new ReflectionClass($this))->getFileName()) . DIRECTORY_SEPARATOR;
89+
90+
$view = $directory . $view . '.php';
91+
}
92+
93+
foreach ([$view, $possibleView1 ?? '', $possibleView2 ?? ''] as $candidateView) {
94+
if (is_file($candidateView)) {
95+
$foundView = $candidateView;
96+
break;
97+
}
98+
}
99+
100+
if (! isset($foundView)) {
101+
throw new RuntimeException('Cannot locate the view file for the cell.');
90102
}
91103

92-
return (function () use ($properties, $view): string {
104+
return (function () use ($properties, $foundView): string {
93105
extract($properties);
94106
ob_start();
95-
include $view;
107+
include $foundView;
96108

97-
return ob_get_clean() ?: '';
109+
return ob_get_clean();
98110
})();
99111
}
100112

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
/**
4+
* This file is part of CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <[email protected]>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace Tests\Support\View\Cells;
13+
14+
use CodeIgniter\View\Cells\Cell;
15+
16+
final class BadCell extends Cell
17+
{
18+
}

tests/system/Commands/CellGeneratorTest.php

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,35 +46,54 @@ protected function getFileContents(string $filepath): string
4646
return file_get_contents($filepath) ?: '';
4747
}
4848

49-
public function testGenerateCell()
49+
public function testGenerateCell(): void
5050
{
5151
command('make:cell RecentCell');
5252

5353
// Check the class was generated
5454
$file = APPPATH . 'Cells/RecentCell.php';
55+
$this->assertStringContainsString('File created: ' . clean_path($file), $this->getStreamFilterBuffer());
5556
$this->assertFileExists($file);
56-
$contents = $this->getFileContents($file);
57-
$this->assertStringContainsString('class RecentCell extends Cell', $contents);
57+
$this->assertStringContainsString('class RecentCell extends Cell', $this->getFileContents($file));
5858

5959
// Check the view was generated
60-
$file = APPPATH . 'Cells/recent_cell.php';
61-
$this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer());
60+
$file = APPPATH . 'Cells/recent.php';
61+
$this->assertStringContainsString('File created: ' . clean_path($file), $this->getStreamFilterBuffer());
6262
$this->assertFileExists($file);
63+
$this->assertSame("<div>\n <!-- Your HTML here -->\n</div>\n", $this->getFileContents($file));
6364
}
6465

65-
public function testGenerateCellSimpleName()
66+
public function testGenerateCellSimpleName(): void
6667
{
6768
command('make:cell Another');
6869

6970
// Check the class was generated
70-
$file = APPPATH . 'Cells/Another.php';
71+
$file = APPPATH . 'Cells/AnotherCell.php';
72+
$this->assertStringContainsString('File created: ' . clean_path($file), $this->getStreamFilterBuffer());
7173
$this->assertFileExists($file);
72-
$contents = $this->getFileContents($file);
73-
$this->assertStringContainsString('class Another extends Cell', $contents);
74+
$this->assertStringContainsString('class AnotherCell extends Cell', $this->getFileContents($file));
7475

7576
// Check the view was generated
7677
$file = APPPATH . 'Cells/another.php';
77-
$this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer());
78+
$this->assertStringContainsString('File created: ' . clean_path($file), $this->getStreamFilterBuffer());
7879
$this->assertFileExists($file);
80+
$this->assertSame("<div>\n <!-- Your HTML here -->\n</div>\n", $this->getFileContents($file));
81+
}
82+
83+
public function testGenerateCellWithCellInBetween(): void
84+
{
85+
command('make:cell PippoCellular');
86+
87+
// Check the class was generated
88+
$file = APPPATH . 'Cells/PippoCellularCell.php';
89+
$this->assertStringContainsString('File created: ' . clean_path($file), $this->getStreamFilterBuffer());
90+
$this->assertFileExists($file);
91+
$this->assertStringContainsString('class PippoCellularCell extends Cell', $this->getFileContents($file));
92+
93+
// Check the view was generated
94+
$file = APPPATH . 'Cells/pippo_cellular.php';
95+
$this->assertStringContainsString('File created: ' . clean_path($file), $this->getStreamFilterBuffer());
96+
$this->assertFileExists($file);
97+
$this->assertSame("<div>\n <!-- Your HTML here -->\n</div>\n", $this->getFileContents($file));
7998
}
8099
}

tests/system/View/ControlledCellTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313

1414
use CodeIgniter\Test\CIUnitTestCase;
1515
use CodeIgniter\View\Exceptions\ViewException;
16+
use RuntimeException;
1617
use Tests\Support\View\Cells\AdditionCell;
1718
use Tests\Support\View\Cells\AwesomeCell;
19+
use Tests\Support\View\Cells\BadCell;
1820
use Tests\Support\View\Cells\ColorsCell;
1921
use Tests\Support\View\Cells\GreetingCell;
2022
use Tests\Support\View\Cells\ListerCell;
@@ -65,6 +67,14 @@ public function testCellThroughRenderMethodWithExtraData()
6567
$this->assertStringContainsString('42, 23, 16, 15, 8, 4', $result);
6668
}
6769

70+
public function testCellThrowsExceptionWhenCannotFindTheViewFile()
71+
{
72+
$this->expectException(RuntimeException::class);
73+
$this->expectExceptionMessage('Cannot locate the view file for the cell.');
74+
75+
view_cell(BadCell::class);
76+
}
77+
6878
public function testCellWithParameters()
6979
{
7080
$result = view_cell(GreetingCell::class, 'greeting=Hi, name=CodeIgniter');

0 commit comments

Comments
 (0)