RouteRegistrarTest.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. <?php
  2. namespace Illuminate\Tests\Routing;
  3. use BadMethodCallException;
  4. use FooController;
  5. use Illuminate\Container\Container;
  6. use Illuminate\Contracts\Events\Dispatcher;
  7. use Illuminate\Http\Request;
  8. use Illuminate\Routing\Route;
  9. use Illuminate\Routing\Router;
  10. use Mockery as m;
  11. use PHPUnit\Framework\TestCase;
  12. use Stringable;
  13. class RouteRegistrarTest extends TestCase
  14. {
  15. /**
  16. * @var \Illuminate\Routing\Router
  17. */
  18. protected $router;
  19. protected function setUp(): void
  20. {
  21. parent::setUp();
  22. $this->router = new Router(m::mock(Dispatcher::class), Container::getInstance());
  23. }
  24. protected function tearDown(): void
  25. {
  26. m::close();
  27. }
  28. public function testMiddlewareFluentRegistration()
  29. {
  30. $this->router->middleware(['one', 'two'])->get('users', function () {
  31. return 'all-users';
  32. });
  33. $this->seeResponse('all-users', Request::create('users', 'GET'));
  34. $this->assertEquals(['one', 'two'], $this->getRoute()->middleware());
  35. $this->router->middleware('three', 'four')->get('users', function () {
  36. return 'all-users';
  37. });
  38. $this->seeResponse('all-users', Request::create('users', 'GET'));
  39. $this->assertEquals(['three', 'four'], $this->getRoute()->middleware());
  40. $this->router->get('users', function () {
  41. return 'all-users';
  42. })->middleware('five', 'six');
  43. $this->seeResponse('all-users', Request::create('users', 'GET'));
  44. $this->assertEquals(['five', 'six'], $this->getRoute()->middleware());
  45. $this->router->middleware('seven')->get('users', function () {
  46. return 'all-users';
  47. });
  48. $this->seeResponse('all-users', Request::create('users', 'GET'));
  49. $this->assertEquals(['seven'], $this->getRoute()->middleware());
  50. }
  51. public function testNullNamespaceIsRespected()
  52. {
  53. $this->router->middleware(['one'])->namespace(null)->get('users', function () {
  54. return 'all-users';
  55. });
  56. $this->assertNull($this->getRoute()->getAction()['namespace']);
  57. }
  58. public function testMiddlewareAsStringableObject()
  59. {
  60. $one = new class implements Stringable
  61. {
  62. public function __toString()
  63. {
  64. return 'one';
  65. }
  66. };
  67. $this->router->middleware($one)->get('users', function () {
  68. return 'all-users';
  69. });
  70. $this->seeResponse('all-users', Request::create('users', 'GET'));
  71. $this->assertSame(['one'], $this->getRoute()->middleware());
  72. }
  73. public function testMiddlewareAsStringableObjectOnRouteInstance()
  74. {
  75. $one = new class implements Stringable
  76. {
  77. public function __toString()
  78. {
  79. return 'one';
  80. }
  81. };
  82. $this->router->get('users', function () {
  83. return 'all-users';
  84. })->middleware($one);
  85. $this->seeResponse('all-users', Request::create('users', 'GET'));
  86. $this->assertSame(['one'], $this->getRoute()->middleware());
  87. }
  88. public function testMiddlewareAsArrayWithStringables()
  89. {
  90. $one = new class implements Stringable
  91. {
  92. public function __toString()
  93. {
  94. return 'one';
  95. }
  96. };
  97. $this->router->middleware([$one, 'two'])->get('users', function () {
  98. return 'all-users';
  99. });
  100. $this->seeResponse('all-users', Request::create('users', 'GET'));
  101. $this->assertSame(['one', 'two'], $this->getRoute()->middleware());
  102. }
  103. public function testWithoutMiddlewareRegistration()
  104. {
  105. $this->router->middleware(['one', 'two'])->get('users', function () {
  106. return 'all-users';
  107. })->withoutMiddleware('one');
  108. $this->seeResponse('all-users', Request::create('users', 'GET'));
  109. $this->assertEquals(['one'], $this->getRoute()->excludedMiddleware());
  110. }
  111. public function testCanRegisterGetRouteWithClosureAction()
  112. {
  113. $this->router->middleware('get-middleware')->get('users', function () {
  114. return 'all-users';
  115. });
  116. $this->seeResponse('all-users', Request::create('users', 'GET'));
  117. $this->seeMiddleware('get-middleware');
  118. }
  119. public function testCanRegisterPostRouteWithClosureAction()
  120. {
  121. $this->router->middleware('post-middleware')->post('users', function () {
  122. return 'saved';
  123. });
  124. $this->seeResponse('saved', Request::create('users', 'POST'));
  125. $this->seeMiddleware('post-middleware');
  126. }
  127. public function testCanRegisterAnyRouteWithClosureAction()
  128. {
  129. $this->router->middleware('test-middleware')->any('users', function () {
  130. return 'anything';
  131. });
  132. $this->seeResponse('anything', Request::create('users', 'PUT'));
  133. $this->seeMiddleware('test-middleware');
  134. }
  135. public function testCanRegisterMatchRouteWithClosureAction()
  136. {
  137. $this->router->middleware('match-middleware')->match(['DELETE'], 'users', function () {
  138. return 'deleted';
  139. });
  140. $this->seeResponse('deleted', Request::create('users', 'DELETE'));
  141. $this->seeMiddleware('match-middleware');
  142. }
  143. public function testCanRegisterRouteWithArrayAndClosureAction()
  144. {
  145. $this->router->middleware('patch-middleware')->patch('users', [function () {
  146. return 'updated';
  147. }]);
  148. $this->seeResponse('updated', Request::create('users', 'PATCH'));
  149. $this->seeMiddleware('patch-middleware');
  150. }
  151. public function testCanRegisterRouteWithArrayAndClosureUsesAction()
  152. {
  153. $this->router->middleware('put-middleware')->put('users', ['uses' => function () {
  154. return 'replaced';
  155. }]);
  156. $this->seeResponse('replaced', Request::create('users', 'PUT'));
  157. $this->seeMiddleware('put-middleware');
  158. }
  159. public function testCanRegisterRouteWithControllerAction()
  160. {
  161. $this->router->middleware('controller-middleware')
  162. ->get('users', RouteRegistrarControllerStub::class.'@index');
  163. $this->seeResponse('controller', Request::create('users', 'GET'));
  164. $this->seeMiddleware('controller-middleware');
  165. }
  166. public function testCanRegisterRouteWithControllerActionArray()
  167. {
  168. $this->router->middleware('controller-middleware')
  169. ->get('users', [RouteRegistrarControllerStub::class, 'index']);
  170. $this->seeResponse('controller', Request::create('users', 'GET'));
  171. $this->seeMiddleware('controller-middleware');
  172. }
  173. public function testCanRegisterNamespacedGroupRouteWithControllerActionArray()
  174. {
  175. $this->router->group(['namespace' => 'WhatEver'], function () {
  176. $this->router->middleware('controller-middleware')
  177. ->get('users', [RouteRegistrarControllerStub::class, 'index']);
  178. });
  179. $this->seeResponse('controller', Request::create('users', 'GET'));
  180. $this->seeMiddleware('controller-middleware');
  181. $this->router->group(['namespace' => 'WhatEver'], function () {
  182. $this->router->middleware('controller-middleware')
  183. ->get('users', ['\\'.RouteRegistrarControllerStub::class, 'index']);
  184. });
  185. $this->seeResponse('controller', Request::create('users', 'GET'));
  186. $this->seeMiddleware('controller-middleware');
  187. }
  188. public function testCanRegisterRouteWithArrayAndControllerAction()
  189. {
  190. $this->router->middleware('controller-middleware')->put('users', [
  191. 'uses' => RouteRegistrarControllerStub::class.'@index',
  192. ]);
  193. $this->seeResponse('controller', Request::create('users', 'PUT'));
  194. $this->seeMiddleware('controller-middleware');
  195. }
  196. public function testCanRegisterGroupWithMiddleware()
  197. {
  198. $this->router->middleware('group-middleware')->group(function ($router) {
  199. $router->get('users', function () {
  200. return 'all-users';
  201. });
  202. });
  203. $this->seeResponse('all-users', Request::create('users', 'GET'));
  204. $this->seeMiddleware('group-middleware');
  205. }
  206. public function testCanRegisterGroupWithoutMiddleware()
  207. {
  208. $this->router->withoutMiddleware('one')->group(function ($router) {
  209. $router->get('users', function () {
  210. return 'all-users';
  211. })->middleware(['one', 'two']);
  212. });
  213. $this->seeResponse('all-users', Request::create('users', 'GET'));
  214. $this->assertEquals(['one'], $this->getRoute()->excludedMiddleware());
  215. }
  216. public function testCanRegisterGroupWithStringableMiddleware()
  217. {
  218. $one = new class implements Stringable
  219. {
  220. public function __toString()
  221. {
  222. return 'one';
  223. }
  224. };
  225. $this->router->middleware($one)->group(function ($router) {
  226. $router->get('users', function () {
  227. return 'all-users';
  228. });
  229. });
  230. $this->seeResponse('all-users', Request::create('users', 'GET'));
  231. $this->seeMiddleware('one');
  232. }
  233. public function testCanRegisterGroupWithNamespace()
  234. {
  235. $this->router->namespace('App\Http\Controllers')->group(function ($router) {
  236. $router->get('users', 'UsersController@index');
  237. });
  238. $this->assertSame(
  239. 'App\Http\Controllers\UsersController@index',
  240. $this->getRoute()->getAction()['uses']
  241. );
  242. }
  243. public function testCanRegisterGroupWithPrefix()
  244. {
  245. $this->router->prefix('api')->group(function ($router) {
  246. $router->get('users', 'UsersController@index');
  247. });
  248. $this->assertSame('api/users', $this->getRoute()->uri());
  249. }
  250. public function testCanRegisterGroupWithPrefixAndWhere()
  251. {
  252. $this->router->prefix('foo/{bar}')->where(['bar' => '[0-9]+'])->group(function ($router) {
  253. $router->get('here', function () {
  254. return 'good';
  255. });
  256. });
  257. $this->seeResponse('good', Request::create('foo/12345/here', 'GET'));
  258. }
  259. public function testCanRegisterGroupWithNamePrefix()
  260. {
  261. $this->router->name('api.')->group(function ($router) {
  262. $router->get('users', 'UsersController@index')->name('users');
  263. });
  264. $this->assertSame('api.users', $this->getRoute()->getName());
  265. }
  266. public function testCanRegisterGroupWithDomain()
  267. {
  268. $this->router->domain('{account}.myapp.com')->group(function ($router) {
  269. $router->get('users', 'UsersController@index');
  270. });
  271. $this->assertSame('{account}.myapp.com', $this->getRoute()->getDomain());
  272. }
  273. public function testCanRegisterGroupWithDomainAndNamePrefix()
  274. {
  275. $this->router->domain('{account}.myapp.com')->name('api.')->group(function ($router) {
  276. $router->get('users', 'UsersController@index')->name('users');
  277. });
  278. $this->assertSame('{account}.myapp.com', $this->getRoute()->getDomain());
  279. $this->assertSame('api.users', $this->getRoute()->getName());
  280. }
  281. public function testCanRegisterGroupWithController()
  282. {
  283. $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) {
  284. $router->get('users', 'index');
  285. });
  286. $this->assertSame(
  287. RouteRegistrarControllerStub::class.'@index',
  288. $this->getRoute()->getAction()['uses']
  289. );
  290. }
  291. public function testCanOverrideGroupControllerWithStringSyntax()
  292. {
  293. $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) {
  294. $router->get('users', 'UserController@index');
  295. });
  296. $this->assertSame(
  297. 'UserController@index',
  298. $this->getRoute()->getAction()['uses']
  299. );
  300. }
  301. public function testCanOverrideGroupControllerWithClosureSyntax()
  302. {
  303. $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) {
  304. $router->get('users', function () {
  305. return 'hello world';
  306. });
  307. });
  308. $this->seeResponse('hello world', Request::create('users', 'GET'));
  309. }
  310. public function testCanOverrideGroupControllerWithInvokableControllerSyntax()
  311. {
  312. $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) {
  313. $router->get('users', InvokableRouteRegistrarControllerStub::class);
  314. });
  315. $this->assertSame(
  316. InvokableRouteRegistrarControllerStub::class.'@__invoke',
  317. $this->getRoute()->getAction()['uses']
  318. );
  319. }
  320. public function testWillUseTheLatestGroupController()
  321. {
  322. $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) {
  323. $router->group(['controller' => FooController::class], function ($router) {
  324. $router->get('users', 'index');
  325. });
  326. });
  327. $this->assertSame(
  328. FooController::class.'@index',
  329. $this->getRoute()->getAction()['uses']
  330. );
  331. }
  332. public function testCanOverrideGroupControllerWithArraySyntax()
  333. {
  334. $this->router->controller(RouteRegistrarControllerStub::class)->group(function ($router) {
  335. $router->get('users', [FooController::class, 'index']);
  336. });
  337. $this->assertSame(
  338. FooController::class.'@index',
  339. $this->getRoute()->getAction()['uses']
  340. );
  341. }
  342. public function testRouteGroupingWithoutPrefix()
  343. {
  344. $this->router->group([], function ($router) {
  345. $router->prefix('bar')->get('baz', ['as' => 'baz', function () {
  346. return 'hello';
  347. }]);
  348. });
  349. $this->seeResponse('hello', Request::create('bar/baz', 'GET'));
  350. }
  351. public function testRegisteringNonApprovedAttributesThrows()
  352. {
  353. $this->expectException(BadMethodCallException::class);
  354. $this->expectExceptionMessage('Method Illuminate\Routing\RouteRegistrar::missing does not exist.');
  355. $this->router->domain('foo')->missing('bar')->group(function ($router) {
  356. //
  357. });
  358. }
  359. public function testCanRegisterResource()
  360. {
  361. $this->router->middleware('resource-middleware')
  362. ->resource('users', RouteRegistrarControllerStub::class);
  363. $this->seeResponse('deleted', Request::create('users/1', 'DELETE'));
  364. $this->seeMiddleware('resource-middleware');
  365. }
  366. public function testCanRegisterResourcesWithExceptOption()
  367. {
  368. $this->router->resources([
  369. 'resource-one' => RouteRegistrarControllerStubOne::class,
  370. 'resource-two' => RouteRegistrarControllerStubTwo::class,
  371. 'resource-three' => RouteRegistrarControllerStubThree::class,
  372. ], ['except' => ['create', 'show']]);
  373. $this->assertCount(15, $this->router->getRoutes());
  374. foreach (['one', 'two', 'three'] as $resource) {
  375. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index'));
  376. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store'));
  377. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit'));
  378. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update'));
  379. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy'));
  380. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create'));
  381. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show'));
  382. }
  383. }
  384. public function testCanRegisterResourcesWithOnlyOption()
  385. {
  386. $this->router->resources([
  387. 'resource-one' => RouteRegistrarControllerStubOne::class,
  388. 'resource-two' => RouteRegistrarControllerStubTwo::class,
  389. 'resource-three' => RouteRegistrarControllerStubThree::class,
  390. ], ['only' => ['create', 'show']]);
  391. $this->assertCount(6, $this->router->getRoutes());
  392. foreach (['one', 'two', 'three'] as $resource) {
  393. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create'));
  394. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show'));
  395. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index'));
  396. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store'));
  397. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit'));
  398. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update'));
  399. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy'));
  400. }
  401. }
  402. public function testCanRegisterResourcesWithoutOption()
  403. {
  404. $this->router->resources([
  405. 'resource-one' => RouteRegistrarControllerStubOne::class,
  406. 'resource-two' => RouteRegistrarControllerStubTwo::class,
  407. 'resource-three' => RouteRegistrarControllerStubThree::class,
  408. ]);
  409. $this->assertCount(21, $this->router->getRoutes());
  410. foreach (['one', 'two', 'three'] as $resource) {
  411. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index'));
  412. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create'));
  413. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store'));
  414. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show'));
  415. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit'));
  416. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update'));
  417. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy'));
  418. }
  419. }
  420. public function testCanRegisterResourceWithMissingOption()
  421. {
  422. $this->router->middleware('resource-middleware')
  423. ->resource('users', RouteRegistrarControllerStub::class)
  424. ->missing(function () {
  425. return 'missing';
  426. });
  427. $this->assertIsCallable($this->router->getRoutes()->getByName('users.show')->getMissing());
  428. $this->assertIsCallable($this->router->getRoutes()->getByName('users.edit')->getMissing());
  429. $this->assertIsCallable($this->router->getRoutes()->getByName('users.update')->getMissing());
  430. $this->assertIsCallable($this->router->getRoutes()->getByName('users.destroy')->getMissing());
  431. $this->assertNull($this->router->getRoutes()->getByName('users.index')->getMissing());
  432. $this->assertNull($this->router->getRoutes()->getByName('users.create')->getMissing());
  433. $this->assertNull($this->router->getRoutes()->getByName('users.store')->getMissing());
  434. }
  435. public function testCanAccessRegisteredResourceRoutesAsRouteCollection()
  436. {
  437. $resource = $this->router->middleware('resource-middleware')
  438. ->resource('users', RouteRegistrarControllerStub::class)
  439. ->register();
  440. $this->assertCount(7, $resource->getRoutes());
  441. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.index'));
  442. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.create'));
  443. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.store'));
  444. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.show'));
  445. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.edit'));
  446. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.update'));
  447. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.destroy'));
  448. }
  449. public function testCanLimitMethodsOnRegisteredResource()
  450. {
  451. $this->router->resource('users', RouteRegistrarControllerStub::class)
  452. ->only('index', 'show', 'destroy');
  453. $this->assertCount(3, $this->router->getRoutes());
  454. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.index'));
  455. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.show'));
  456. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.destroy'));
  457. }
  458. public function testCanExcludeMethodsOnRegisteredResource()
  459. {
  460. $this->router->resource('users', RouteRegistrarControllerStub::class)
  461. ->except(['index', 'create', 'store', 'show', 'edit']);
  462. $this->assertCount(2, $this->router->getRoutes());
  463. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.update'));
  464. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.destroy'));
  465. }
  466. public function testCanSetShallowOptionOnRegisteredResource()
  467. {
  468. $this->router->resource('users.tasks', RouteRegistrarControllerStub::class)->shallow();
  469. $this->assertCount(7, $this->router->getRoutes());
  470. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.tasks.index'));
  471. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('tasks.show'));
  472. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('users.tasks.show'));
  473. }
  474. public function testCanSetScopedOptionOnRegisteredResource()
  475. {
  476. $this->router->resource('users.tasks', RouteRegistrarControllerStub::class)->scoped();
  477. $this->assertSame(
  478. ['user' => null],
  479. $this->router->getRoutes()->getByName('users.tasks.index')->bindingFields()
  480. );
  481. $this->assertSame(
  482. ['user' => null, 'task' => null],
  483. $this->router->getRoutes()->getByName('users.tasks.show')->bindingFields()
  484. );
  485. $this->router->resource('users.tasks', RouteRegistrarControllerStub::class)->scoped([
  486. 'task' => 'slug',
  487. ]);
  488. $this->assertSame(
  489. ['user' => null],
  490. $this->router->getRoutes()->getByName('users.tasks.index')->bindingFields()
  491. );
  492. $this->assertSame(
  493. ['user' => null, 'task' => 'slug'],
  494. $this->router->getRoutes()->getByName('users.tasks.show')->bindingFields()
  495. );
  496. }
  497. public function testCanExcludeMethodsOnRegisteredApiResource()
  498. {
  499. $this->router->apiResource('users', RouteRegistrarControllerStub::class)
  500. ->except(['index', 'show', 'store']);
  501. $this->assertCount(2, $this->router->getRoutes());
  502. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.update'));
  503. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.destroy'));
  504. }
  505. public function testCanRegisterApiResourcesWithExceptOption()
  506. {
  507. $this->router->apiResources([
  508. 'resource-one' => RouteRegistrarControllerStubOne::class,
  509. 'resource-two' => RouteRegistrarControllerStubTwo::class,
  510. 'resource-three' => RouteRegistrarControllerStubThree::class,
  511. ], ['except' => ['create', 'show']]);
  512. $this->assertCount(12, $this->router->getRoutes());
  513. foreach (['one', 'two', 'three'] as $resource) {
  514. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index'));
  515. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store'));
  516. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update'));
  517. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy'));
  518. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create'));
  519. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show'));
  520. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit'));
  521. }
  522. }
  523. public function testCanRegisterApiResourcesWithOnlyOption()
  524. {
  525. $this->router->apiResources([
  526. 'resource-one' => RouteRegistrarControllerStubOne::class,
  527. 'resource-two' => RouteRegistrarControllerStubTwo::class,
  528. 'resource-three' => RouteRegistrarControllerStubThree::class,
  529. ], ['only' => ['index', 'show']]);
  530. $this->assertCount(6, $this->router->getRoutes());
  531. foreach (['one', 'two', 'three'] as $resource) {
  532. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index'));
  533. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show'));
  534. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store'));
  535. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update'));
  536. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy'));
  537. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create'));
  538. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit'));
  539. }
  540. }
  541. public function testCanRegisterApiResourcesWithoutOption()
  542. {
  543. $this->router->apiResources([
  544. 'resource-one' => RouteRegistrarControllerStubOne::class,
  545. 'resource-two' => RouteRegistrarControllerStubTwo::class,
  546. 'resource-three' => RouteRegistrarControllerStubThree::class,
  547. ]);
  548. $this->assertCount(15, $this->router->getRoutes());
  549. foreach (['one', 'two', 'three'] as $resource) {
  550. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.index'));
  551. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.show'));
  552. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.store'));
  553. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.update'));
  554. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.destroy'));
  555. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.create'));
  556. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('resource-'.$resource.'.edit'));
  557. }
  558. }
  559. public function testUserCanRegisterApiResource()
  560. {
  561. $this->router->apiResource('users', RouteRegistrarControllerStub::class);
  562. $this->assertCount(5, $this->router->getRoutes());
  563. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('users.create'));
  564. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('users.edit'));
  565. }
  566. public function testUserCanRegisterApiResourceWithExceptOption()
  567. {
  568. $this->router->apiResource('users', RouteRegistrarControllerStub::class, [
  569. 'except' => ['destroy'],
  570. ]);
  571. $this->assertCount(4, $this->router->getRoutes());
  572. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('users.create'));
  573. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('users.edit'));
  574. $this->assertFalse($this->router->getRoutes()->hasNamedRoute('users.destroy'));
  575. }
  576. public function testUserCanRegisterApiResourceWithOnlyOption()
  577. {
  578. $this->router->apiResource('users', RouteRegistrarControllerStub::class, [
  579. 'only' => ['index', 'show'],
  580. ]);
  581. $this->assertCount(2, $this->router->getRoutes());
  582. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.index'));
  583. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('users.show'));
  584. }
  585. public function testCanNameRoutesOnRegisteredResource()
  586. {
  587. $this->router->resource('comments', RouteRegistrarControllerStub::class)
  588. ->only('create', 'store')->names('reply');
  589. $this->router->resource('users', RouteRegistrarControllerStub::class)
  590. ->only('create', 'store')->names([
  591. 'create' => 'user.build',
  592. 'store' => 'user.save',
  593. ]);
  594. $this->router->resource('posts', RouteRegistrarControllerStub::class)
  595. ->only('create', 'destroy')
  596. ->name('create', 'posts.make')
  597. ->name('destroy', 'posts.remove');
  598. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('reply.create'));
  599. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('reply.store'));
  600. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('user.build'));
  601. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('user.save'));
  602. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('posts.make'));
  603. $this->assertTrue($this->router->getRoutes()->hasNamedRoute('posts.remove'));
  604. }
  605. public function testCanOverrideParametersOnRegisteredResource()
  606. {
  607. $this->router->resource('users', RouteRegistrarControllerStub::class)
  608. ->parameters(['users' => 'admin_user']);
  609. $this->router->resource('posts', RouteRegistrarControllerStub::class)
  610. ->parameter('posts', 'topic');
  611. $this->assertStringContainsString('admin_user', $this->router->getRoutes()->getByName('users.show')->uri);
  612. $this->assertStringContainsString('topic', $this->router->getRoutes()->getByName('posts.show')->uri);
  613. }
  614. public function testCanSetMiddlewareOnRegisteredResource()
  615. {
  616. $this->router->resource('users', RouteRegistrarControllerStub::class)
  617. ->middleware(RouteRegistrarMiddlewareStub::class);
  618. $this->seeMiddleware(RouteRegistrarMiddlewareStub::class);
  619. }
  620. public function testResourceWithoutMiddlewareRegistration()
  621. {
  622. $this->router->resource('users', RouteRegistrarControllerStub::class)
  623. ->only('index')
  624. ->middleware(['one', 'two'])
  625. ->withoutMiddleware('one');
  626. $this->seeResponse('controller', Request::create('users', 'GET'));
  627. $this->assertEquals(['one'], $this->getRoute()->excludedMiddleware());
  628. }
  629. public function testResourceWithMiddlewareAsStringable()
  630. {
  631. $one = new class implements Stringable
  632. {
  633. public function __toString()
  634. {
  635. return 'one';
  636. }
  637. };
  638. $this->router->resource('users', RouteRegistrarControllerStub::class)
  639. ->only('index')
  640. ->middleware([$one, 'two'])
  641. ->withoutMiddleware('one');
  642. $this->seeResponse('controller', Request::create('users', 'GET'));
  643. $this->assertEquals(['one', 'two'], $this->getRoute()->middleware());
  644. $this->assertEquals(['one'], $this->getRoute()->excludedMiddleware());
  645. }
  646. public function testResourceWheres()
  647. {
  648. $wheres = [
  649. 'user' => '\d+',
  650. 'test' => '[a-z]+',
  651. ];
  652. $this->router->resource('users', RouteRegistrarControllerStub::class)
  653. ->where($wheres);
  654. /** @var \Illuminate\Routing\Route $route */
  655. foreach ($this->router->getRoutes() as $route) {
  656. $this->assertEquals($wheres, $route->wheres);
  657. }
  658. }
  659. public function testWhereNumberRegistration()
  660. {
  661. $wheres = ['foo' => '[0-9]+', 'bar' => '[0-9]+'];
  662. $this->router->get('/{foo}/{bar}')->whereNumber(['foo', 'bar']);
  663. $this->router->get('/api/{bar}/{foo}')->whereNumber(['bar', 'foo']);
  664. /** @var \Illuminate\Routing\Route $route */
  665. foreach ($this->router->getRoutes() as $route) {
  666. $this->assertEquals($wheres, $route->wheres);
  667. }
  668. }
  669. public function testWhereAlphaRegistration()
  670. {
  671. $wheres = ['foo' => '[a-zA-Z]+', 'bar' => '[a-zA-Z]+'];
  672. $this->router->get('/{foo}/{bar}')->whereAlpha(['foo', 'bar']);
  673. $this->router->get('/api/{bar}/{foo}')->whereAlpha(['bar', 'foo']);
  674. /** @var \Illuminate\Routing\Route $route */
  675. foreach ($this->router->getRoutes() as $route) {
  676. $this->assertEquals($wheres, $route->wheres);
  677. }
  678. }
  679. public function testWhereAlphaNumericRegistration()
  680. {
  681. $wheres = ['1a2b3c' => '[a-zA-Z0-9]+'];
  682. $this->router->get('/{foo}')->whereAlphaNumeric(['1a2b3c']);
  683. /** @var \Illuminate\Routing\Route $route */
  684. foreach ($this->router->getRoutes() as $route) {
  685. $this->assertEquals($wheres, $route->wheres);
  686. }
  687. }
  688. public function testCanSetRouteName()
  689. {
  690. $this->router->as('users.index')->get('users', function () {
  691. return 'all-users';
  692. });
  693. $this->seeResponse('all-users', Request::create('users', 'GET'));
  694. $this->assertSame('users.index', $this->getRoute()->getName());
  695. }
  696. public function testCanSetRouteNameUsingNameAlias()
  697. {
  698. $this->router->name('users.index')->get('users', function () {
  699. return 'all-users';
  700. });
  701. $this->seeResponse('all-users', Request::create('users', 'GET'));
  702. $this->assertSame('users.index', $this->getRoute()->getName());
  703. }
  704. /**
  705. * Get the last route registered with the router.
  706. *
  707. * @return \Illuminate\Routing\Route
  708. */
  709. protected function getRoute()
  710. {
  711. return last($this->router->getRoutes()->get());
  712. }
  713. /**
  714. * Assert that the last route has the given middleware.
  715. *
  716. * @param string $middleware
  717. * @return void
  718. */
  719. protected function seeMiddleware($middleware)
  720. {
  721. $this->assertEquals($middleware, $this->getRoute()->middleware()[0]);
  722. }
  723. /**
  724. * Assert that the last route has the given content.
  725. *
  726. * @param string $content
  727. * @param \Illuminate\Http\Request $request
  728. * @return void
  729. */
  730. protected function seeResponse($content, Request $request)
  731. {
  732. $route = $this->getRoute();
  733. $this->assertTrue($route->matches($request));
  734. $this->assertEquals($content, $route->bind($request)->run());
  735. }
  736. }
  737. class RouteRegistrarControllerStub
  738. {
  739. public function index()
  740. {
  741. return 'controller';
  742. }
  743. public function destroy()
  744. {
  745. return 'deleted';
  746. }
  747. }
  748. class InvokableRouteRegistrarControllerStub
  749. {
  750. public function __invoke()
  751. {
  752. return 'controller';
  753. }
  754. }
  755. class RouteRegistrarMiddlewareStub
  756. {
  757. //
  758. }