ViewBuilderTest.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  5. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  6. *
  7. * Licensed under The MIT License
  8. * For full copyright and license information, please see the LICENSE.txt
  9. * Redistributions of files must retain the above copyright notice
  10. *
  11. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  12. * @link https://cakephp.org CakePHP(tm) Project
  13. * @since 3.1.0
  14. * @license https://opensource.org/licenses/mit-license.php MIT License
  15. */
  16. namespace Cake\Test\TestCase\View;
  17. use Cake\Event\EventManager;
  18. use Cake\Http\Response;
  19. use Cake\Http\ServerRequest;
  20. use Cake\TestSuite\TestCase;
  21. use Cake\View\Exception\MissingViewException;
  22. use Cake\View\ViewBuilder;
  23. /**
  24. * View builder test case.
  25. */
  26. class ViewBuilderTest extends TestCase
  27. {
  28. public function testSetVar(): void
  29. {
  30. $builder = new ViewBuilder();
  31. $builder->setVar('testing', 'value');
  32. $this->assertSame('value', $builder->getVar('testing'));
  33. }
  34. public function testSetVars(): void
  35. {
  36. $builder = new ViewBuilder();
  37. $data = ['test' => 'val', 'foo' => 'bar'];
  38. $builder->setVars($data);
  39. $this->assertEquals($data, $builder->getVars());
  40. $update = ['test' => 'updated'];
  41. $builder->setVars($update);
  42. $this->assertEquals(
  43. ['foo' => 'bar', 'test' => 'updated'],
  44. $builder->getVars()
  45. );
  46. $update = ['overwrite' => 'yes'];
  47. $builder->setVars($update, false);
  48. $this->assertEquals(
  49. ['overwrite' => 'yes'],
  50. $builder->getVars()
  51. );
  52. }
  53. public function testHasVar(): void
  54. {
  55. $builder = new ViewBuilder();
  56. $this->assertFalse($builder->hasVar('foo'));
  57. $builder->setVar('foo', 'value');
  58. $this->assertTrue($builder->hasVar('foo'));
  59. $builder->setVar('bar', null);
  60. $this->assertTrue($builder->hasVar('bar'));
  61. }
  62. /**
  63. * data provider for string properties.
  64. *
  65. * @return array
  66. */
  67. public function stringPropertyProvider(): array
  68. {
  69. return [
  70. ['layoutPath', 'Admin/'],
  71. ['templatePath', 'Admin/'],
  72. ['plugin', 'TestPlugin'],
  73. ['layout', 'admin'],
  74. ['theme', 'TestPlugin'],
  75. ['template', 'edit'],
  76. ['name', 'Articles'],
  77. ['className', 'Cake\View\JsonView'],
  78. ];
  79. }
  80. /**
  81. * data provider for boolean properties.
  82. * Format: [key, expectedDefault, newValue]
  83. *
  84. * @return array
  85. */
  86. public function boolPropertyProvider(): array
  87. {
  88. return [
  89. ['autoLayout', true, false],
  90. ];
  91. }
  92. /**
  93. * data provider for array properties.
  94. *
  95. * @return array
  96. */
  97. public function arrayPropertyProvider(): array
  98. {
  99. return [
  100. ['helpers', ['Html', 'Form']],
  101. ['options', ['key' => 'value']],
  102. ];
  103. }
  104. /**
  105. * Test string property accessor/mutator methods.
  106. *
  107. * @dataProvider stringPropertyProvider
  108. */
  109. public function testStringProperties(string $property, string $value): void
  110. {
  111. $get = 'get' . ucfirst($property);
  112. $set = 'set' . ucfirst($property);
  113. $builder = new ViewBuilder();
  114. $this->assertNull($builder->{$get}(), 'Default value should be null');
  115. $this->assertSame($builder, $builder->{$set}($value), 'Setter returns this');
  116. $this->assertSame($value, $builder->{$get}(), 'Getter gets value.');
  117. }
  118. /**
  119. * Test string property accessor/mutator methods.
  120. *
  121. * @dataProvider boolPropertyProvider
  122. */
  123. public function testBoolProperties(string $property, bool $default, bool $value): void
  124. {
  125. $set = 'enable' . ucfirst($property);
  126. $get = 'is' . ucfirst($property) . 'Enabled';
  127. $builder = new ViewBuilder();
  128. $this->assertSame($default, $builder->{$get}(), 'Default value not as expected');
  129. $this->assertSame($builder, $builder->{$set}($value), 'Setter returns this');
  130. $this->assertSame($value, $builder->{$get}(), 'Getter gets value.');
  131. }
  132. /**
  133. * Test array property accessor/mutator methods.
  134. *
  135. * @dataProvider arrayPropertyProvider
  136. */
  137. public function testArrayProperties(string $property, array $value): void
  138. {
  139. $get = 'get' . ucfirst($property);
  140. $set = 'set' . ucfirst($property);
  141. $builder = new ViewBuilder();
  142. $this->assertSame([], $builder->{$get}(), 'Default value should be empty list');
  143. $this->deprecated(function () use ($set, $value, $builder) {
  144. // only deprecated wrapper should remove in cake 5, assert should kept
  145. if ($set !== 'setHelpers') {
  146. trigger_error('Only setHelpers has deprecation warning in cake +4.x', E_USER_DEPRECATED);
  147. }
  148. $this->assertSame($builder, $builder->{$set}($value), 'Setter returns this');
  149. });
  150. $this->assertSame($value, $builder->{$get}(), 'Getter gets value.');
  151. }
  152. /**
  153. * Test array property accessor/mutator methods.
  154. *
  155. * @dataProvider arrayPropertyProvider
  156. */
  157. public function testArrayPropertyMerge(string $property, array $value): void
  158. {
  159. $get = 'get' . ucfirst($property);
  160. $set = 'set' . ucfirst($property);
  161. $this->deprecated(function () use ($get, $set, $value) {
  162. // only deprecated wrapper and setHelpers testing should remove in cake 5, other asserts should kept
  163. if ($set !== 'setHelpers') {
  164. trigger_error('Only setHelpers has deprecation warning in cake 4.x', E_USER_DEPRECATED);
  165. }
  166. $builder = new ViewBuilder();
  167. $builder->{$set}($value);
  168. $builder->{$set}(['Merged'], true);
  169. $this->assertSame(array_merge($value, ['Merged']), $builder->{$get}(), 'Should merge');
  170. $builder->{$set}($value, false);
  171. $this->assertSame($value, $builder->{$get}(), 'Should replace');
  172. });
  173. }
  174. /**
  175. * Tests that adding non-assoc and assoc merge properly.
  176. *
  177. * @return void
  178. */
  179. public function testAddHelpers(): void
  180. {
  181. $builder = new ViewBuilder();
  182. $builder->addHelper('Form');
  183. $builder->addHelpers(['Form' => ['config' => 'value']]);
  184. $helpers = $builder->getHelpers();
  185. $expected = [
  186. 'Form',
  187. 'Form' => [
  188. 'config' => 'value',
  189. ],
  190. ];
  191. $this->assertSame($expected, $helpers);
  192. }
  193. /**
  194. * test building with all the options.
  195. */
  196. public function testBuildComplete(): void
  197. {
  198. $this->deprecated(function () {
  199. $request = new ServerRequest();
  200. $response = new Response();
  201. $events = new EventManager();
  202. $builder = new ViewBuilder();
  203. $builder->setName('Articles')
  204. ->setClassName('Ajax')
  205. ->setTemplate('edit')
  206. ->setLayout('default')
  207. ->setTemplatePath('Articles/')
  208. ->setHelpers(['Form', 'Html'], false)
  209. ->setLayoutPath('Admin/')
  210. ->setTheme('TestTheme')
  211. ->setPlugin('TestPlugin')
  212. ->setVars(['foo' => 'bar', 'x' => 'old']);
  213. $view = $builder->build(
  214. ['one' => 'value', 'x' => 'new'],
  215. $request,
  216. $response,
  217. $events
  218. );
  219. $this->assertInstanceOf('Cake\View\AjaxView', $view);
  220. $this->assertSame('edit', $view->getTemplate());
  221. $this->assertSame('default', $view->getLayout());
  222. $this->assertSame('Articles/', $view->getTemplatePath());
  223. $this->assertSame('Admin/', $view->getLayoutPath());
  224. $this->assertSame('TestPlugin', $view->getPlugin());
  225. $this->assertSame('TestTheme', $view->getTheme());
  226. $this->assertSame($request, $view->getRequest());
  227. $this->assertInstanceOf(Response::class, $view->getResponse());
  228. $this->assertSame($events, $view->getEventManager());
  229. $this->assertSame(['one', 'x', 'foo'], $view->getVars());
  230. $this->assertSame('value', $view->get('one'));
  231. $this->assertSame('bar', $view->get('foo'));
  232. $this->assertInstanceOf('Cake\View\Helper\HtmlHelper', $view->Html);
  233. $this->assertInstanceOf('Cake\View\Helper\FormHelper', $view->Form);
  234. });
  235. }
  236. /**
  237. * Test that the default is AppView.
  238. */
  239. public function testBuildAppViewMissing(): void
  240. {
  241. static::setAppNamespace('Nope');
  242. $builder = new ViewBuilder();
  243. $view = $builder->build();
  244. $this->assertInstanceOf('Cake\View\View', $view);
  245. }
  246. /**
  247. * Test that the default is AppView.
  248. */
  249. public function testBuildAppViewPresent(): void
  250. {
  251. static::setAppNamespace();
  252. $builder = new ViewBuilder();
  253. $view = $builder->build();
  254. $this->assertInstanceOf('TestApp\View\AppView', $view);
  255. }
  256. /**
  257. * test missing view class
  258. */
  259. public function testBuildMissingViewClass(): void
  260. {
  261. $this->expectException(MissingViewException::class);
  262. $this->expectExceptionMessage('View class "Foo" is missing.');
  263. $builder = new ViewBuilder();
  264. $builder->setClassName('Foo');
  265. $builder->build();
  266. }
  267. /**
  268. * testJsonSerialize()
  269. */
  270. public function testJsonSerialize(): void
  271. {
  272. $builder = new ViewBuilder();
  273. $builder
  274. ->setTemplate('default')
  275. ->setLayout('test')
  276. ->setHelpers(['Html'], false)
  277. ->setClassName('JsonView');
  278. $result = json_decode(json_encode($builder), true);
  279. $expected = [
  280. '_template' => 'default',
  281. '_layout' => 'test',
  282. '_helpers' => ['Html'],
  283. '_className' => 'JsonView',
  284. '_autoLayout' => true,
  285. ];
  286. $this->assertEquals($expected, $result);
  287. $result = json_decode(json_encode(unserialize(serialize($builder))), true);
  288. $this->assertEquals($expected, $result);
  289. }
  290. /**
  291. * testCreateFromArray()
  292. */
  293. public function testCreateFromArray(): void
  294. {
  295. $builder = new ViewBuilder();
  296. $builder
  297. ->setTemplate('default')
  298. ->setLayout('test')
  299. ->setHelpers(['Html'], false)
  300. ->setClassName('JsonView');
  301. $result = json_encode($builder);
  302. $builder = new ViewBuilder();
  303. $builder->createFromArray(json_decode($result, true));
  304. $this->assertSame('default', $builder->getTemplate());
  305. $this->assertSame('test', $builder->getLayout());
  306. $this->assertEquals(['Html'], $builder->getHelpers());
  307. $this->assertSame('JsonView', $builder->getClassName());
  308. }
  309. /**
  310. * test setOptions() with 1 string param, merge true
  311. */
  312. public function testSetOptionsOne(): void
  313. {
  314. $builder = new ViewBuilder();
  315. $this->assertSame($builder, $builder->setOptions(['newOption']));
  316. $this->assertContains('newOption', $builder->getOptions());
  317. }
  318. /**
  319. * test setOptions() with 2 strings in array, merge true.
  320. */
  321. public function testSetOptionsMultiple(): void
  322. {
  323. $builder = new ViewBuilder();
  324. $builder->setOptions(['oldOption'], false);
  325. $option = ['newOption', 'anotherOption'];
  326. $builder->setOptions($option);
  327. $expects = ['oldOption', 'newOption', 'anotherOption'];
  328. $result = $builder->getOptions();
  329. $this->assertContainsOnly('string', $result);
  330. $this->assertEquals($expects, $result);
  331. }
  332. /**
  333. * test empty params reads _viewOptions.
  334. */
  335. public function testReadingViewOptions(): void
  336. {
  337. $builder = new ViewBuilder();
  338. $builder->setOptions(['one', 'two', 'three'], false);
  339. $this->assertEquals(['one', 'two', 'three'], $builder->getOptions());
  340. }
  341. /**
  342. * test setting $merge `false` overrides correct options.
  343. */
  344. public function testMergeFalseViewOptions(): void
  345. {
  346. $builder = new ViewBuilder();
  347. $builder->setOptions(['one', 'two', 'three'], false);
  348. $expected = ['four', 'five', 'six'];
  349. $builder->setOptions($expected, false);
  350. $this->assertEquals($expected, $builder->getOptions());
  351. }
  352. /**
  353. * test _viewOptions is undefined and $opts is null, an empty array is returned.
  354. */
  355. public function testUndefinedValidViewOptions(): void
  356. {
  357. $builder = new ViewBuilder();
  358. $builder->setOptions([], false);
  359. $result = $builder->getOptions();
  360. $this->assertIsArray($result);
  361. $this->assertEmpty($result);
  362. }
  363. public function testOptionSetGet(): void
  364. {
  365. $builder = new ViewBuilder();
  366. $result = $builder->setOption('foo', 'bar');
  367. $this->assertSame($builder, $result);
  368. $this->assertSame('bar', $builder->getOption('foo'));
  369. $builder->setOption('foo', 'overwrite');
  370. $this->assertSame('overwrite', $builder->getOption('foo'));
  371. $this->assertNull($builder->getOption('nonexistent'));
  372. }
  373. public function testDisableAutoLayout(): void
  374. {
  375. $builder = new ViewBuilder();
  376. $this->assertTrue($builder->isAutoLayoutEnabled());
  377. $builder->disableAutoLayout();
  378. $this->assertFalse($builder->isAutoLayoutEnabled());
  379. }
  380. public function testAddHelperChained(): void
  381. {
  382. $builder = new ViewBuilder();
  383. $builder->addHelper('Form')
  384. ->addHelper('Time')
  385. ->addHelper('Text');
  386. $helpers = $builder->getHelpers();
  387. $expected = [
  388. 'Form',
  389. 'Time',
  390. 'Text',
  391. ];
  392. $this->assertSame($expected, $helpers);
  393. }
  394. public function testAddHelperOptions(): void
  395. {
  396. $builder = new ViewBuilder();
  397. $builder->addHelper('Form')
  398. ->addHelper('Text', ['foo' => 'bar']);
  399. $helpers = $builder->getHelpers();
  400. $this->assertSame(['foo' => 'bar'], $helpers['Text']);
  401. }
  402. }