ãã㯠CakePHP Advent Calendar 2017 19æ¥ç®ã®è¨äºã§ããé ãã¦ããããªããã 18æ¥ç®ã¯ @neeton_iwasakiããã®CakePHP SocialAuth Pluginãã©ã°ã¤ã³ä½¿ç¨ä¾ | ããã¯ãã¼ãã§ããã
ååã®è¨äº CakePHP 3 ã®ãã¥ã¼ããªã¢ã«ã«ã¦ããããã¹ãã追å ãã (1) ã§ã¯ãæ§ç¯ããã¢ããªã±ã¼ã·ã§ã³ã«å¯¾ãã¦ãã¦ããããã¹ããæ¸ãããã®æºåãè¡ãããã¼ãã«ãã¨ã³ãã£ãã£ã¼ãã«ã¼ãã£ã³ã°ã®ãã¹ããæ¸ãã¾ããã
ä»åã¯æ®ãã®ã³ã³ããã¼ã©ã¼ã¯ã©ã¹ã«ãã¹ãã³ã¼ããæ¸ãã¦ããã¾ãããã
ã©ããªãã¹ããæ¸ãã
ãã¥ã¼ããªã¢ã«ã§ã¯ã ArticlesController
, TagsController
, UsersController
ã使ãã¾ããã
ãã¹ã¦ã®ã¢ã¯ã·ã§ã³ã«ã¤ãã¦ãã¹ããæ¸ãã¨èª¬æãéè¤ãã¦ãã¾ãã¾ãã
ããã§ã bake å¾ã®ã«ã¹ã¿ãã¤ãºã§æãå ãã ArticlesController
ã®ãã¹ã¦ã®ã¢ã¯ã·ã§ã³ã¨ UsersController
ã® login()
, logout()
ã¢ã¯ã·ã§ã³ã«ãã¹ãã追å ãã¾ãã
ArticlesTable
ã®ãã¹ã (1-5, 1-6, 2-5, 2-7) (ååã®è¨äº)User
ã®ãã¹ã (2-1) (ååã®è¨äº)Article
ã®ãã¹ã (2-6) (ååã®è¨äº)- ã«ã¼ãã£ã³ã°ã®ãã¹ã (2-3) (ååã®è¨äº)
- ãã°ã¤ã³ã»ãã°ã¢ã¦ãã®ãã¹ã (3-1, 3-2) (ãã®è¨äºã§ãã¹ããæ¸ãã¾ã)
ArticlesController
ã®ãã¹ã (ä¸è¨ä»¥å¤å ¨é¨) (ãã®è¨äºã§ãã¹ããæ¸ãã¾ã)
UsersController
ã®ãã¹ã
(å®è£ 㯠èªè¨¼æ©è½ã®ãã¹ãPull Request #17 ã§ç¢ºèªã§ãã¾ã)
ãã°ã¤ã³ login()
ã®ãã¹ããæ¸ã
ãã°ã¤ã³ã®ãã¹ãã§ã¯ä»¥ä¸ã®ãã¹ããæ¸ãã¦ã¿ã¾ãã
- ãã°ã¤ã³ãã¼ã¸ã表示ããããã¨
- èªè¨¼å¤±æãããã¨ã©ã¼ã¡ãã»ã¼ã¸ã表示ãã
- èªè¨¼æåãããèªè¨¼ã»ãã·ã§ã³ãæ¸ãè¾¼ã¿ãå ã®ãã¼ã¸ã«ãªãã¤ã¬ã¯ããã
ãã°ã¤ã³ã®ãã¹ããããããã«ã¯ ã¦ã¼ã¶ã¼æ
å ±ã®æºåãå¿
è¦ã§ããUsersFixture
ã¯ããã¼ã®ããã¹ããå
¥ã£ãã¾ã¾ãªã®ã§ããã¹ãã§ãããã¼ã¿ã«å¤æ´ãã¾ãã ããã§ã¯æ¬¡ã® init()
ã¡ã½ããã追å ãã¦ãã¹ããã¼ã¿ãçæãã¾ãã
<?php // tests/Fixture/UserFixture.php public function init() { $hasher = new DefaultPasswordHasher(); $this->records = [ [ 'id' => 1, 'email' => '[email protected]', 'password' => $hasher->hash('password'), 'created' => '2017-11-18 11:45:40', 'modified' => '2017-11-18 11:45:40' ], ]; parent::init(); }
init()
ã¡ã½ãããå®ç¾©ããã¨ããããã£åæä»£å
¥ããèªç±ã«ãã¹ããã¼ã¿ãçæã§ãã¾ãã UserFixture
å
¨ä½ã¯ä»¥ä¸ã®éãã§ãã
<?php // tests/Fixture/UserFixture.php namespace App\Test\Fixture; use Cake\Auth\DefaultPasswordHasher; use Cake\TestSuite\Fixture\TestFixture; /** * UsersFixture * */ class UsersFixture extends TestFixture { /** * Fields * * @var array */ // @codingStandardsIgnoreStart public $fields = [ 'id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 'email' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'collate' => 'utf8mb4_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], 'password' => ['type' => 'string', 'length' => 255, 'null' => false, 'default' => null, 'collate' => 'utf8mb4_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], 'created' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 'modified' => ['type' => 'datetime', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], '_constraints' => [ 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], ], '_options' => [ 'engine' => 'InnoDB', 'collation' => 'utf8mb4_general_ci' ], ]; // @codingStandardsIgnoreEnd /** * Records * * @var array */ public $records = []; public function init() { $hasher = new DefaultPasswordHasher(); $this->records = [ [ 'id' => 1, 'email' => '[email protected]', 'password' => $hasher->hash('password'), 'created' => '2017-11-18 11:45:40', 'modified' => '2017-11-18 11:45:40' ], ]; parent::init(); } }
UsersController
ã®ãã¹ããæ¸ãã¾ãããã
ãã°ã¤ã³æ©è½ã®ãã¹ãã3ã¤ã®ãã¹ãã¡ã½ããã«å®ç¾©ãã¾ããã
<?php // tests/TestCase/Controller/UsersController.php namespace App\Test\TestCase\Controller; use App\Controller\UsersController; use Cake\ORM\TableRegistry; use Cake\TestSuite\IntegrationTestCase; /** * App\Controller\UsersController Test Case */ class UsersControllerTest extends IntegrationTestCase { /** * Fixtures * * @var array */ public $fixtures = [ 'app.users', 'app.articles' ]; /** * ãã°ã¤ã³ãã¼ã¸ã表示ããã */ public function testLoginShow() { $this->get('/users/login'); $this->assertResponseOk(); $this->assertResponseContains('ãã°ã¤ã³'); } /** * ãã°ã¤ã³å¤±æ */ public function testLoginFailed() { $this->post('/users/login', [ 'email' => '[email protected]', 'password' => 'wrongpassword', ]); $this->assertResponseOk(); $this->assertResponseContains('ã¦ã¼ã¶ã¼åã¾ãã¯ãã¹ã¯ã¼ãã䏿£ã§ãã'); } /** * ãã°ã¤ã³æå */ public function testLoginSucceed() { $this->post('/users/login?redirect=%2Farticles%2Fadd', [ 'email' => '[email protected]', 'password' => 'password', ]); $this->assertRedirect('/articles/add'); $this->assertSession(1, 'Auth.User.id'); } }
get($url)
ã post($url, $data)
ã使ã£ã¦ã¢ã¯ã·ã§ã³ã¡ã½ãããå®è¡ãã assertResponseOk()
ã assertResponseContains(...)
ã§çµæ(å¿çããããããã£)ãæ¤è¨¼ãã¦ãã¾ãã
ã³ã³ããã¼ã©ã¼ã®ãã¹ãã«ã¤ãã¦
ãã®ãã¹ãã³ã¼ãã¯ã³ã³ããã¼ã©ã¼ã®çµ±åãã¹ãã使ã£ã¦å®è£
ãã¾ããããã¾ã¾ã§å®è£
ãããã¼ãã«ãã¨ã³ãã£ãã£ã¼ã®ã¦ããããã¹ãã¨æ¯ã¹ãã¨ããã¹ã対象ã®ãªãã¸ã§ã¯ãçæãã夿°ã¸ã®ä»£å
¥ãããã¾ããããããã¯ãã¹ã¦ã³ã³ããã¼ã©ã¼ã®çµ±åãã¹ãã®ããã«ç¨æãããã¡ã½ãã( get()
ã post()
ãå種ã¢ãµã¼ã·ã§ã³)ã§ã©ããããã¦ãã¾ãã
ãã®ãããªä»çµã¿ã¯ããã¹ãã³ã¼ããèªã¿ãããç°¡æ½ã«ããããå©ç¹ãããã¾ãã䏿¹ã§ãå¦çããã¼ã¿ãé ããã¦ããããããã¹ãã³ã¼ããæ¸ãã«ããæãããã¨ãããããããã¾ããããã®å ´åã IntegrationTestCase
ã®ã³ã¼ããèªãã¨ã軽æ¸ã§ãããã¨æãã¾ãã
ãã°ã¢ã¦ã logout()
ã®ãã¹ããæ¸ã
<?php // tests/TestCase/Controller/UsersController.php // ... ç¥ /** * ãã°ã¢ã¦ã */ public function testLogout() { $this->session(['Auth.User.id' => 1]); $this->get('/users/logout'); $this->assertSession([], 'Auth'); $this->assertRedirect('/users/login'); } // ... ç¥
$this->session(...)
ã§èªè¨¼æ¸ã¿æã®ã»ãã·ã§ã³ãã¼ã¿ãä½ãã logout
ã¢ã¯ã·ã§ã³ãå®è¡å¾ã®æ¯ãèããæ¤è¨¼ãã¾ãã
ArticlesController
ã®ãã¹ã
ArticlesController
ã«ã¯6ã¤ã®ã¢ã¯ã·ã§ã³ã¡ã½ãããããã¾ããã¾ãã¯bakeã§ãã¹ãã±ã¼ã¹ã¯ã©ã¹ãçæãã¾ãã
$ bin/cake bake test Controller ArticlesController
è¨äºä¸è¦§ index()
(å®è£ 㯠ãã¹ã追å : è¨äºä¸è¦§ã表示 Pull Request #18 ã§ç¢ºèªã§ãã¾ã)
- åè¨äºã®ã¿ã¤ãã«ã表示ããããã¨
ããã¹ããã¾ããå
ã
ãã£ã testIndex()
ã¡ã½ããã以ä¸ã«ç½®ãæãã¦ãã ããã
<?php // tests/TestCase/Controller/ArticlesControllerTest.php public function testè¨äºä¸è¦§ã表示() { $this->get('/articles'); $this->assertResponseOk(); $this->assertResponseContains('CakePHP3 ãã¥ã¼ããªã¢ã«'); $this->assertResponseContains('Happy new year'); }
è¨äºè©³ç´° view()
(å®è£ 㯠ãã¹ã追å : è¨äºè©³ç´°ã表示 Pull Request #19 ã§ç¢ºèªã§ãã¾ã)
- 詳細ãã¼ã¸ã表示ããããã¨
- 詳細ãã¼ã¸ãåå¨ããªãã¨ã404ã«ãªããã¨
ããã¹ããã¾ãã testView()
ã以ä¸ã§ããããã¦ãã ããã
<?php // tests/TestCase/Controller/ArticlesControllerTest.php public function testè¨äºè©³ç´°ãã¼ã¸ã表示() { $this->get('/articles/view/CakePHP3-chutoriaru'); $this->assertResponseOk(); $this->assertResponseContains('CakePHP3 ãã¥ã¼ããªã¢ã«'); // title $this->assertResponseContains('ãã®ãã¥ã¼ããªã¢ã«ã¯ç°¡å㪠' . 'CMS ã¢ããªã±ã¼ã·ã§ã³ãä½ãã¾ãã'); // body } public function testè¨äºè©³ç´°ãã¼ã¸ãåå¨ããªã() { $this->get('/articles/view/not-found-articles'); $this->assertResponseCode(404); }
ã¡ãªã¿ã«ã articles
ãã¼ãã«ã«ã¯ published
ã«ã©ã ãããã¾ããããã¥ã¼ããªã¢ã«ã§ã¯ãã£ã«ã¿ãå®è£
ãã¦ãã¾ããã published = 1
ã®è¨äºã ã表示ãããã¸ãã¯ã追å ããããããã«å¯¾ãããã¹ããæ¸ãã¦ãããã§ãããã
è¨äºè¿½å add()
(å®è£ 㯠ãã¹ã追å : è¨äºè¿½å Pull Request #20 ã§ç¢ºèªã§ãã¾ã)
- è¨äºè¿½å ãã¼ã¸ã«ã¢ã¯ã»ã¹ã§ãã
- è¨äºã追å ãããã¨ãè¨äºä¸è¦§ã«ãªãã¤ã¬ã¯ããã
- ããªãã¼ã·ã§ã³ã¨ã©ã¼ã ã¨è¿½å ã§ãããã¨ã©ã¼ã¡ãã»ã¼ã¸ã表示ããã
ããã¹ããã¾ãã
è¨äºã追å ããã«ã¯ã users
ãã¼ãã«ãå¿
è¦ãªããããã£ã¯ã¹ãã£ã¼ã«è¿½å ãã¦ããã¾ãã
<?php // tests/TestCase/Controller/ArticlesControllerTest.php public $fixtures = [ 'app.users', // ãã®è¡ã追å 'app.articles', 'app.tags', 'app.articles_tags' ];
æºåã§ããã®ã§ã testAdd()
ã以ä¸ã§ããããã¦ãã ããã
<?php // tests/TestCase/Controller/ArticlesControllerTest.php public function testè¨äºè¿½å ãã¼ã¸ã«ã¢ã¯ã»ã¹ã§ãã() { $this->session(['Auth.User.id' => 1]); $this->get('/articles/add'); $this->assertResponseOk(); $this->assertResponseContains('è¨äºã®è¿½å '); } public function testè¨äºã追å ãããã¨è¨äºä¸è¦§ã«ãªãã¤ã¬ã¯ããã() { $this->session(['Auth.User.id' => 1]); $this->post('/articles/add', [ 'title' => 'Nintendo Switch ãè³¼å ¥ï¼', 'body' => 'ã¯ãªã¹ãã¹ãã¬ã¼ã³ãã¨ãã¦è²·ã£ã', 'tag_string' => 'game,2017', ]); $this->assertSession('Your article has been saved.', 'Flash.flash.0.message'); $this->assertRedirect('/articles'); $this->get('/articles'); $this->assertResponseContains('Nintendo Switch ãè³¼å ¥ï¼'); } public function testããªãã¼ã·ã§ã³ã¨ã©ã¼ã ã¨è¿½å ã§ããã¨ã©ã¼ã¡ãã»ã¼ã¸ã表示ããã() { $this->session(['Auth.User.id' => 1]); $this->post('/articles/add', [ 'title' => 'Nintendo Switch ãè³¼å ¥ï¼', 'body' => '', 'tag_string' => '', ]); $this->assertResponseOk(); $this->assertResponseContains('Unable to add your article.'); $this->get('/articles'); $this->assertResponseNotContains('Nintendo Switch ãè³¼å ¥ï¼'); }
è¨äºã®è¿½å ã¯ãã°ã¤ã³ããªãã¨ã§ãã¾ããã $this->session(['Auth.User.id' => 1]);
ã§èªè¨¼æ¸ã¿ã®ç¶æ
ã«ãã¾ãã
è¨äºç·¨é edit()
(å®è£ 㯠ãã¹ã追å : è¨äºç·¨é Pull Request #21 ã§ç¢ºèªã§ãã¾ã)
- è¨äºç·¨éãã¼ã¸ã«ã¢ã¯ã»ã¹ã§ãã
- è¨äºãæ´æ°ãããã®å¾ãè¨äºä¸è¦§ã«ãªãã¤ã¬ã¯ããã
- ããªãã¼ã·ã§ã³ã¨ã©ã¼ã ã¨æ´æ°ã§ãããã¨ã©ã¼ã¡ãã»ã¼ã¸ã表示ããã
ããã¹ããã¾ããtestEdit()
ã以ä¸ã§ããããã¦ãã ããã
<?php // tests/TestCase/Controller/ArticlesControllerTest.php public function testè¨äºç·¨éãã¼ã¸ã«ã¢ã¯ã»ã¹ã§ãã() { $this->session(['Auth.User.id' => 1]); $this->get('/articles/edit/CakePHP3-chutoriaru'); $this->assertResponseContains('è¨äºã®ç·¨é'); $this->assertResponseContains('CakePHP3 ãã¥ã¼ããªã¢ã«'); } public function testè¨äºãæ´æ°ãè¨äºä¸è¦§ã«ãªãã¤ã¬ã¯ããã() { $this->session(['Auth.User.id' => 1]); $this->post('/articles/edit/CakePHP3-chutoriaru', [ // ã¿ã¤ãã«ã夿´ãã 'title' => '1æéã§åããCakePHP3 ãã¥ã¼ããªã¢ã«', 'body' => 'ãã®ãã¥ã¼ããªã¢ã«ã¯ç°¡å㪠CMS ã¢ããªã±ã¼ã·ã§ã³ãä½ãã¾ãã ã¯ããã« CakePHP ã®ã¤ã³ã¹ãã¼ã«ãè¡ãããã¼ã¿ãã¼ã¹ã®ä½æã ããã¦ã¢ããªã±ã¼ã·ã§ã³ãç´ æ©ãä»ä¸ããããã® CakePHP ãæä¾ãããã¼ã«ã使ãã¾ãã', 'tag_string' => 'PHP,CakePHP', ]); $this->assertRedirect('/articles'); $this->assertSession('Your article has been updated.', 'Flash.flash.0.message'); $this->get('/articles'); $this->assertResponseContains('1æéã§åããCakePHP3 ãã¥ã¼ããªã¢ã«'); } public function testããªãã¼ã·ã§ã³ã¨ã©ã¼ã ã¨æ´æ°ã§ããã¨ã©ã¼ã¡ãã»ã¼ã¸ã表示ããã() { $this->session(['Auth.User.id' => 1]); $this->post('/articles/edit/CakePHP3-chutoriaru', [ // ã¿ã¤ãã«ã夿´ãã 'title' => '1æéã§åããCakePHP3 ãã¥ã¼ããªã¢ã«', 'body' => '', ]); $this->assertResponseOk(); $this->assertResponseContains('Unable to update your article.'); $this->get('/articles'); $this->assertResponseNotContains('1æéã§åããCakePHP3 ãã¥ã¼ããªã¢ã«'); }
ã»ã¨ãã©è¨äºã®è¿½å ã¨ä¸ç·ã§ãã
è¨äºåé¤ remove()
(å®è£ 㯠ãã¹ã追å : è¨äºåé¤ Pull Request #22 ã§ç¢ºèªã§ãã¾ã)
- è¨äºãåé¤ããããã®å¾ãè¨äºä¸è¦§ã«ãªãã¤ã¬ã¯ããã
- getãªã¯ã¨ã¹ãã®å ´ååé¤ããªã
ããã¹ããã¾ããtestDelete()
ã以ä¸ã§ããããã¦ãã ããã
<?php // tests/TestCase/Controller/ArticlesControllerTest.php public function testè¨äºãåé¤ãã¦ãã®å¾è¨äºä¸è¦§ã«ãªãã¤ã¬ã¯ããã() { $this->session(['Auth.User.id' => 1]); $this->post('/articles/delete/CakePHP3-chutoriaru'); $this->assertRedirect('/articles'); $this->get('/articles'); $this->assertResponseNotContains('CakePHP3 ãã¥ã¼ããªã¢ã«'); } public function testGetãªã¯ã¨ã¹ãã®å ´ååé¤ããªã() { $this->session(['Auth.User.id' => 1]); $this->get('/articles/delete/CakePHP3-chutoriaru'); $this->assertResponseCode(405); $this->get('/articles'); $this->assertResponseContains('CakePHP3 ãã¥ã¼ããªã¢ã«'); }
ã¿ã°æ¤ç´¢ tags()
(å®è£ 㯠ãã¹ã追å : ã¿ã°æ¤ç´¢ Pull Request #23 ã§ç¢ºèªã§ãã¾ã)
- è¤æ°ã¿ã°ãæå®ãã¦ã¢ã¯ã»ã¹
- åå¨ããªãã¿ã°ãæå®ãã¦ã¢ã¯ã»ã¹
ããã¹ããã¾ããtestTags()
ã以ä¸ã§ããããã¦ãã ããã
<?php // tests/TestCase/Controller/ArticlesControllerTest.php public function testè¤æ°ã¿ã°ãæå®ãã¦ã¢ã¯ã»ã¹() { $this->get('/articles/tagged/php/cakephp'); $this->assertResponseOk(); $this->assertResponseRegExp('/Articles tagged with\s+php or cakephp/m'); $this->assertResponseContains('CakePHP3 ãã¥ã¼ããªã¢ã«'); } public function teståå¨ããªãã¿ã°ãæå®ãã¦ã¢ã¯ã»ã¹() { $this->get('/articles/tagged/undefined-tag'); $this->assertResponseOk(); $this->assertResponseRegExp('/Articles tagged with\s+undefined-tag/m'); $this->assertResponseContains('è¨äºãè¦ã¤ããã¾ããã§ããã'); }
ãã®è¨äºã§ã¯åºæ¬çã«ãããã¯ã·ã§ã³ã³ã¼ãã夿´ãã¦ã¾ãããã¿ã°æ¤ç´¢ã®å ´åãåå¨ããªãã¿ã°ãæå®ããå ´åã«ãè¨äºä¸è¦§ã®é¨åã«ä½ã表示ãããªãã®ã§ããè¨äºãè¦ã¤ããã¾ããã§ããããã¨è¡¨ç¤ºãã¦ããã®è¡¨ç¤ºããã¹ããã¾ããããã³ãã¬ã¼ãã以ä¸ã®ããã«ä¿®æ£ãã¦ãã ããã
<?php // src/Template/Articles/tags.ctp /** * @var array $tags * @var App\Model\Entity\Article[] $articles */ ?> <h1> Articles tagged with <?= $this->Text->toList(h($tags), 'or') ?> </h1> <section> <?php if ($articles->count() === 0): ?> <p>è¨äºãè¦ã¤ããã¾ããã§ããã</p> <?php endif; ?> <?php foreach ($articles as $article): ?> <article> <!-- ãªã³ã¯ã®ä½æã« HtmlHelper ãä½¿ç¨ --> <h4><?= $this->Html->link( $article->title, ['controller' => 'Articles', 'action' => 'view', $article->slug] ) ?></h4> <span><?= h($article->created) ?> </article> <?php endforeach; ?> </section>
ã¾ã¨ã
CMSãã¥ã¼ããªã¢ã«ã§å®è£ ããã³ã³ããã¼ã©ã¼ã«ãã¹ããæ¸ãæ¹æ³ãç´¹ä»ãã¾ããã
CakePHP Advent Calendar 2017 19æ¥ç®ã®è¨äºã§ããã
ä»é²ã»CircleCI ã§ç¶ç¶çã¤ã³ãã°ã¬ã¼ã·ã§ã³ããè¨å®
(å®è£ 㯠CircleCI ã»ããã¢ãã Pull Request #11 ã§ç¢ºèªã§ãã¾ã)
ä»åããã¹ãå®è£ ã¯ã¡ã½ãããã¨ã«Pull Requestã§åãã¦ãã¾ããã(Pull Requests · tenkoma/cakephp_cms)ããã¦ããã¹ããå®è£ ãå§ããåã«CircleCI ã§Pushæ¯ã«å ¨ãã¹ããå®è¡ããæºåããã¾ããã
CircleCIã®ã»ããã¢ããæé ã¯çç¥ãã¾ãããCakePHP3ããã¸ã§ã¯ããCircleCIã§ãã¹ãããããã®è¨å®ãã¡ã¤ã«ã¯cakephp_cms/config.yml at masterã§ç¢ºèªã§ãã¾ãã
ãã¹ãã³ã¼ããå¢ãã¦ããã¨ãæ¯åãã¼ã«ã«ã§å ¨ãã¹ããå®è¡ããã®ã¯å¤§å¤ã§ããCircleCIãTravisCIãªã©ã使ã£ã¦èªååããæ¹æ³ãã¨ãã¨ã楽ã«ãªãã§ãããã