tag:crieit.net,2005:https://crieit.net/users/chocol4t/feed chocoの投稿 - Crieit Crieitでユーザーchocoによる最近の投稿 2020-03-04T22:44:48+09:00 https://crieit.net/users/chocol4t/feed tag:crieit.net,2005:PublicArticle/15748 2020-03-04T22:44:48+09:00 2020-03-04T22:44:48+09:00 https://crieit.net/posts/Docker-Xdebug DockerでXdebugのインストールを失敗した場合 <p>DockerのコンテナにXdebugをインストールしようとして失敗した。<br /> 発生したエラーは以下の2点。</p> <ul> <li>autoconfがインストールされていなかった</li> <li>Cコンパイラがインストールされていなかった</li> </ul> <h2 id="実行環境"><a href="#%E5%AE%9F%E8%A1%8C%E7%92%B0%E5%A2%83">実行環境</a></h2> <ul> <li>Docker 2.2.0.0</li> <li>PHP 7.4 <ul> <li><a target="_blank" rel="nofollow noopener" href="https://hub.docker.com/_/php">php:7.4-fpm-alpine</a></li> </ul></li> <li>Xdebug 2.9.2</li> </ul> <h2 id="その1 autoconfがインストールされていない"><a href="#%E3%81%9D%E3%81%AE1+autoconf%E3%81%8C%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84">その1 autoconfがインストールされていない</a></h2> <p>以下のようなエラーが表示された場合はautoconfがインストールされていない。</p> <pre><code>downloading xdebug-2.9.2.tgz ... Starting to download xdebug-2.9.2.tgz (242,959 bytes) ..................................................done: 242,959 bytes 90 source files, building running: phpize Configuring for: PHP Api Version: 20190902 Zend Module Api No: 20190902 Zend Extension Api No: 320190902 Cannot find autoconf. Please check your autoconf installation and the $PHP_AUTOCONF environment variable. Then, rerun this script. ERROR: `phpize' failed </code></pre> <p>この場合は<code>apk add autoconf</code>を実行してインストールすればよい。</p> <h2 id="その2 コンパイラがインストールされていない"><a href="#%E3%81%9D%E3%81%AE2+%E3%82%B3%E3%83%B3%E3%83%91%E3%82%A4%E3%83%A9%E3%81%8C%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84">その2 コンパイラがインストールされていない</a></h2> <p>以下のようなエラーが表示された場合はコンパイラのインストールがされていない。</p> <pre><code>downloading xdebug-2.9.2.tgz ... Starting to download xdebug-2.9.2.tgz (242,959 bytes) ..................................................done: 242,959 bytes 90 source files, building running: phpize Configuring for: PHP Api Version: 20190902 Zend Module Api No: 20190902 Zend Extension Api No: 320190902 building in /tmp/pear/temp/pear-build-defaultuserhmhpmF/xdebug-2.9.2 running: /tmp/pear/temp/xdebug/configure --with-php-config=/usr/local/bin/php-config checking for grep that handles long lines and -e... /bin/grep checking for egrep... /bin/grep -E checking for a sed that does not truncate output... /bin/sed checking for pkg-config... no checking for cc... no checking for gcc... no configure: error: in `/tmp/pear/temp/pear-build-defaultuserhmhpmF/xdebug-2.9.2': configure: error: no acceptable C compiler found in $PATH See `config.log' for more details ERROR: `/tmp/pear/temp/xdebug/configure --with-php-config=/usr/local/bin/php-config' failed </code></pre> <p>この場合は<code>apk add gcc g++ make</code>を実行してインストールすればコンパイルが可能になる。</p> <p>また、<code>apk add build-base</code>の実行でも必要なパッケージのインストールが行える。<br /> <a target="_blank" rel="nofollow noopener" href="https://pkgs.alpinelinux.org/package/edge/main/x86_64/build-base">build-base</a>は以下7つのパッケージをインストールする。</p> <ul> <li>binutils</li> <li>file</li> <li>fortify-headers</li> <li>g++</li> <li>gcc</li> <li>libc-dev</li> <li>make</li> </ul> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/ucan-lab/items/fbf021bf69896538e515">php-alpineコンテナにxdebugをインストールする時にハマったメモ - Qiita</a></li> </ul> choco tag:crieit.net,2005:PublicArticle/15743 2020-03-02T17:00:28+09:00 2020-03-02T17:00:28+09:00 https://crieit.net/posts/return-json-when-validation-of-form-request-fails FormRequestのバリデーション失敗時にjsonを返す <p>以下どちらかの実装でjsonレスポンスにできる。</p> <ul> <li><code>failedValidation()</code>をオーバーライドする</li> <li>ヘッダーに<code>Accept</code>または<code>X-Requested-With</code>を追加する</li> </ul> <p>Laravelのバージョンは6.15.0です。</p> <h2><code>failedValidation()</code>のオーバーライド</h2> <p>フォームリクエストクラスの<code>failedValidation()</code>をオーバーライドすることでjsonレスポンスかつメッセージをカスタマイズすることも可能。以下はサインアップのエンドポイントを想定したリクエストの例。</p> <pre><code class="php"><?php namespace App\Http\Requests; use Illuminate\Contracts\Validation\Validator; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Http\Exceptions\HttpResponseException; class SignUpRequest extends FormRequest { /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'user_id' => 'required', 'password' => 'required' ]; } public function messages() { return [ 'user_id.required' => 'ユーザーIDは必須です。', 'password.required' => 'パスワードは必須です。', ]; } protected function failedValidation(Validator $validator) { throw new HttpResponseException( response()->json([ 'message' => $validator->errors()->toArray(), ], 403) ); } } </code></pre> <h2>ヘッダーに<code>Accept</code>または<code>X-Requested-With</code>を追加する</h2> <p>エクセプションハンドラを変更していない場合、バリデーションエラー発生時は<code>Illuminate/Foundation/Exceptions/Handler::render()</code>でレスポンス生成が行われる。</p> <pre><code class="php"> // Illuminate/Foundation/Exceptions/Handler.php public function render($request, Exception $e) { if (method_exists($e, 'render') && $response = $e->render($request)) { return Router::toResponse($request, $response); } elseif ($e instanceof Responsable) { return $e->toResponse($request); } $e = $this->prepareException($e); if ($e instanceof HttpResponseException) { return $e->getResponse(); } elseif ($e instanceof AuthenticationException) { return $this->unauthenticated($request, $e); } elseif ($e instanceof ValidationException) { return $this->convertValidationExceptionToResponse($e, $request); } return $request->expectsJson() ? $this->prepareJsonResponse($request, $e) : $this->prepareResponse($request, $e); } </code></pre> <p>今回はバリデーションエラーの場合なので<code>convertValidationExceptionToResponse()</code>が実行される。</p> <pre><code class="php"> // Illuminate/Foundation/Exceptions/Handler.php protected function convertValidationExceptionToResponse(ValidationException $e, $request) { if ($e->response) { return $e->response; } return $request->expectsJson() ? $this->invalidJson($request, $e) : $this->invalid($request, $e); } </code></pre> <p><code>expectsJson()</code>はヘッダに<code>X-Requested-With: XMLHttpRequest</code>が含まれているか、ヘッダに<code>Accept: .../json</code>もしくは<code>Accept: ...+json</code>が含まれている場合にjsonレスポンスを返却する。</p> <p>そのためミドルウェアでヘッダを追加することでjsonレスポンスが取得できる。</p> <pre><code class="php"><?php // app/Http/Middleware/EnforceJson.php namespace App\Http\Middleware; use Closure; /** * @see https://stackoverflow.com/questions/44453221/how-to-set-header-for-all-requests-in-route-group */ class EnforceJson { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { $request->headers->set('Accept', 'application/json'); return $next($request); } } </code></pre> <pre><code class="php"><?php // app/Http/Kernel.php namespace App\Http; use Illuminate\Foundation\Http\Kernel as HttpKernel; class Kernel extends HttpKernel { // ... protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ], 'api' => [ 'throttle:60,1', \Illuminate\Routing\Middleware\SubstituteBindings::class, \App\Http\Middleware\EnforceJson::class, // 追加 ], ]; // ... } </code></pre> <p>個人的には返却するメッセージを変更できるので<code>failedValidation()</code>をオーバーライドするほうが好みです。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/junsan50/items/ec7f810decd3b82d3d76">【Laravel5】FormRequestのバリデーション結果をJSON APIで返す - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/kd9951/items/9b6ef7d2c505522d873b">Laravel APIで常にJSONをリクエストするミドルウェア - Qiita</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/44453221/how-to-set-header-for-all-requests-in-route-group">php - How to set header for all requests in route group - Stack Overflow</a></li> </ul> choco tag:crieit.net,2005:PublicArticle/15176 2019-06-30T11:52:44+09:00 2019-06-30T12:02:24+09:00 https://crieit.net/posts/Laravel-Eloquent-Tips 【Laravel】Eloquent Tips <p>Eloquentを使う際にちょっと便利になるTipsをまとめてみました。<br /> 網羅性はないので参考程度に。</p> <h2 id="テーブル名の変更"><a href="#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E5%90%8D%E3%81%AE%E5%A4%89%E6%9B%B4">テーブル名の変更</a></h2> <p><code>$table</code>を定義することで任意のテーブルへのアクセス出来ます。</p> <pre><code class="php"><?php use Illuminate\Database\Eloquent\Model; class Example extends Model { protected $table = 'custom_example'; } </code></pre> <h2 id="主キー名の変更"><a href="#%E4%B8%BB%E3%82%AD%E3%83%BC%E5%90%8D%E3%81%AE%E5%A4%89%E6%9B%B4">主キー名の変更</a></h2> <p><code>$primaryKey</code>を定義して変更することが可能です。</p> <pre><code class="php"><?php use Illuminate\Database\Eloquent\Model; class Example extends Model { // デフォルトは'id'で定義されています。 protected $primaryKey = 'custom_key'; } </code></pre> <h2 id="主キーの型を変更する"><a href="#%E4%B8%BB%E3%82%AD%E3%83%BC%E3%81%AE%E5%9E%8B%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B">主キーの型を変更する</a></h2> <p><code>$keyType</code>を定義して変更することが可能です。</p> <pre><code class="php"><?php use Illuminate\Database\Eloquent\Model; class Example extends Model { // デフォルトは'int'で定義されています。 protected $keyType = 'string'; } </code></pre> <h2 id="主キーのインクリメントをしないようにする"><a href="#%E4%B8%BB%E3%82%AD%E3%83%BC%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%AF%E3%83%AA%E3%83%A1%E3%83%B3%E3%83%88%E3%82%92%E3%81%97%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B">主キーのインクリメントをしないようにする</a></h2> <p><code>$incrementing</code>を定義して変更することが可能です。</p> <pre><code class="php"><?php use Illuminate\Database\Eloquent\Model; class Example extends Model { // デフォルトはtrueで定義されています。 protected $incrementing = false; } </code></pre> <h2 id="デフォルトのタイムスタンプを使用しないようにする"><a href="#%E3%83%87%E3%83%95%E3%82%A9%E3%83%AB%E3%83%88%E3%81%AE%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%97%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B">デフォルトのタイムスタンプを使用しないようにする</a></h2> <p><code>$timestamps</code>を定義することでデフォルトのタイムスタンプを使用しなくなります。</p> <pre><code class="php"><?php use Illuminate\Database\Eloquent\Model; class Example extends Model { // デフォルトはtrueで定義されています。 public $timestamps = false; } </code></pre> <p>詳細は<a target="_blank" rel="nofollow noopener" href="https://laravel.com/api/5.8/Illuminate/Database/Eloquent/Concerns/HasTimestamps.html"><code>Illuminate\Database\Eloquent\Concerns\HasTimestamps</code></a>を参照してください。</p> <h2 id="タイムスタンプのカラム名を変更する"><a href="#%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%97%E3%81%AE%E3%82%AB%E3%83%A9%E3%83%A0%E5%90%8D%E3%82%92%E5%A4%89%E6%9B%B4%E3%81%99%E3%82%8B">タイムスタンプのカラム名を変更する</a></h2> <p>モデルクラスに<code>CREATED_AT</code>、<code>UPDATED_AT</code>を定義することで変更できます。</p> <pre><code class="php"><?php use Illuminate\Database\Eloquent\Model; class Example extends Model { const CREATED_AT = 'created'; const UPDATED_AT = 'updated'; } </code></pre> <h2 id="タイムスタンプのプロパティからCarbonのメソッドを実行"><a href="#%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%B9%E3%82%BF%E3%83%B3%E3%83%97%E3%81%AE%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3%E3%81%8B%E3%82%89Carbon%E3%81%AE%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%92%E5%AE%9F%E8%A1%8C">タイムスタンプのプロパティからCarbonのメソッドを実行</a></h2> <p>次のようなマイグレーションを作成します。</p> <pre><code class="php"><?php use Illuminate\Support\Facades\Schema; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Migrations\Migration; class CreateSampleTable extends Migration { public function up() { Schema::create('sample', function (Blueprint $table) { $table->bigIncrements('id'); $table->string('text'); // created_at, updated_atカラムが追加されます。 $table->timestamps(); }); } public function down() { Schema::dropIfExists('sample'); } } </code></pre> <p>モデルクラスを<code>Sample</code>とした時、次のような実行が可能です。</p> <pre><code class="php"><?php namespace App\Http\Controllers; use App\Sample; class HomeController extends Controller { public function index() { /** @var App\Sample $sample */ $sample = Sample::find(1); // 時刻の差分を取得 $diff = $sample->created_at->diffForHumans(); } } </code></pre> <p><code>created_at</code>、<code>updated_at</code>にアクセスすると、<code>Carbon</code>オブジェクトに変換してくれています。<br /> そのため、<code>diffForHumans</code>などのメソッドが呼び出せます。</p> <p>詳細は<a target="_blank" rel="nofollow noopener" href="https://laravel.com/api/5.8/Illuminate/Database/Eloquent/Concerns/HasAttributes.html"><code>Illuminate\Database\Eloquent\Concerns\HasAttributes</code></a>を参照してください。</p> <p>また、独自に<code>Carbon</code>オブジェクトで受け取りたいカラムを設定したい場合は<code>$dates</code>を定義することで可能です。</p> <pre><code class="php"><?php use Illuminate\Database\Eloquent\Model; class Example extends Model { // created_at, updated_at以外のカラム名を追加します。 protected $dates = [ 'created', 'updated' ]; } </code></pre> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://laravel.com/docs/5.8/eloquent">Eloquent: Getting Started - Laravel - The PHP Framework For Web Artisans</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://laravel.com/docs/5.8/eloquent-mutators#accessors-and-mutators">Eloquent: Mutators - Laravel - The PHP Framework For Web Artisans</a></li> </ul> choco tag:crieit.net,2005:PublicArticle/14556 2018-09-29T18:37:56+09:00 2018-10-30T07:43:25+09:00 https://crieit.net/posts/DDD ボトムアップDDDを写経した <h2 id="まえがき"><a href="#%E3%81%BE%E3%81%88%E3%81%8C%E3%81%8D">まえがき</a></h2> <p>最近、通勤の合間などにIDDDを読んで少しづつDDDの知識を取り入れている。ユビキタス言語や境界づけられたコンテキストなど、概念的な定義が個人的に難しくて読むのに時間がかかっている。</p> <p>そんな時に<a target="_blank" rel="nofollow noopener" href="https://twitter.com/nrslib">nrsさん</a>のブログに書かれている、<a target="_blank" rel="nofollow noopener" href="https://nrslib.com/bottomup-ddd/">ボトムアップドメイン駆動設計</a>を読んだ。理解や実践が難しい箇所はひとまず置いておき、理解しやすく実践しやすい箇所からまず始めてみようという内容だ。</p> <p>自分にぴったりだと思って一通り読んだ後、せっかくなのでPHPとLaravelを使って写経をしてみた。一通り書いてみた感想としては、OOPの特性を活かしたコーディングとはこういうことなんだなとふんわり掴め、責務の所在が明確だとファイルが増えても処理が追いやすいなと感じた。</p> <p>参考にした記事で扱われているものは次の5つ。どれも技術的な要素なので、普段コードを書いている人にとっては読みやすいと思う。</p> <ul> <li>値オブジェクト</li> <li>エンティティ</li> <li>ドメインサービス</li> <li>リポジトリ</li> <li>アプリケーションサービス</li> </ul> <p>また、サンプルとは異なる実装をしている箇所を以下で補足する。</p> <h2 id="変更点"><a href="#%E5%A4%89%E6%9B%B4%E7%82%B9">変更点</a></h2> <h3 id="コンストラクタ"><a href="#%E3%82%B3%E3%83%B3%E3%82%B9%E3%83%88%E3%83%A9%E3%82%AF%E3%82%BF">コンストラクタ</a></h3> <p>PHPは<code>__construct()</code>を複数定義出来ない。そのため、今回はデフォルト引数を用いて実装を行った。</p> <pre><code class="php"><?php namespace BottomUpDDD\Domain\Users; use InvalidArgumentException; use BottomUpDDD\Common\Util; use BottomUpDDD\Domain\EquatableInterface; final class User implements EquatableInterface { /** @var UserId */ private $id; /** @var UserName */ private $userName; /** @var FullName */ private $fullName; public function __construct( UserName $userName, FullName $fullName, UserId $id = null ) { $this->id = $id === null ? new UserId(Util::guid()) : $id; $this->userName = $userName; $this->fullName = $fullName; } // 以下の処理は省略... } </code></pre> <p>ただ、必ず引数で受け取る<code>$userName</code>と<code>$fullName</code>を引数としたコンストラクタを定義し、2つの引数に合わせて<code>$id</code>と3つを引数に受け取る静的メソッドを定義すれば擬似的に複数定義することも出来なくはない。</p> <pre><code class="php"><?php namespace BottomUpDDD\Domain\Users; use InvalidArgumentException; use BottomUpDDD\Common\Util; use BottomUpDDD\Domain\EquatableInterface; final class User implements EquatableInterface { /** @var UserId */ private $id; /** @var UserName */ private $userName; /** @var FullName */ private $fullName; public function __construct( UserName $userName, FullName $fullName ) { $this->id = new UserId(Util::guid()); $this->userName = $userName; $this->fullName = $fullName; } public static function ctorWithId( UserName $userName, FullName $fullName, UserId $id ) { $instance = new self($userName, $fullName); $instance->id = $id; return $instance; } // 以下の処理は省略... } </code></pre> <p>個人的な意見としては、生成処理のパターンが増えたり、複雑であればファクトリを用意すれば良いのかなという解釈でいる。</p> <h3 id="等価性の判定"><a href="#%E7%AD%89%E4%BE%A1%E6%80%A7%E3%81%AE%E5%88%A4%E5%AE%9A">等価性の判定</a></h3> <p>C#やJavaのObjectクラスには<code>equals()</code>というメソッドが定義されており、等価の判別が出来る。これもPHPには用意されていないので、汎用的なメソッドとして用意し、インターフェースを実装した。</p> <pre><code class="php"><?php namespace BottomUpDDD\Common; final class Util { /** * @param object $objA * @param object $objB * @return boolean */ public static function classEquals($objA, $objB): bool { return get_class($objA) === get_class($objB); } // 以下の処理は省略... } </code></pre> <pre><code class="php"><?php namespace BottomUpDDD\Domain; interface EquatableInterface { public function equals(EquatableInterface $obj): bool; } </code></pre> <h3 id="リポジトリ"><a href="#%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA">リポジトリ</a></h3> <p>Laravelを使用したということもあり、学習も兼ねてEloquentを用いて実装した。</p> <pre><code class="php"><?php namespace BottomUpDDD\ProductionInfrastructure; use BottomUpDDD\Domain\Users\UserRepositoryInterface; use BottomUpDDD\Domain\Users\User; use BottomUpDDD\Domain\Users\UserId; use BottomUpDDD\Domain\Users\UserName; use BottomUpDDD\ProductionInfrastructure\Eloquents\UserEloquent; use BottomUpDDD\Domain\Users\FullName; final class UserRepository implements UserRepositoryInterface { /** @var UserEloquent */ private $userEloquent; public function __construct(UserEloquent $userEloquent) { $this->userEloquent = $userEloquent; } /** * @param UserId $userId * @return User|null */ public function findByUserId(UserId $userId) { $target = $this->userEloquent->find($userId->value()); if ($target === null) { return null; } return new User( new UserName($target->user_name), new FullName($target->first_name, $target->family_name), $userId ); } /** * @param UserName $userName * @return User|null */ public function findByUserName(UserName $userName) { $target = $this->userEloquent->findByUserName($userName); return $target; } /** * @return User[] */ public function findAll() { $users = $this->userEloquent ->all() ->map(function (UserEloquent $userEloquent) { return new User( new UserName($userEloquent->user_name), new FullName( $userEloquent->first_name, $userEloquent->family_name ), new UserId($userEloquent->id) ); })->toArray(); return $users; } public function save(User $user) { $this->userEloquent->persist($user); } public function delete(UserId $userId) { $this->userEloquent->deleteByUserId($userId); } } </code></pre> <h2 id="あとがき"><a href="#%E3%81%82%E3%81%A8%E3%81%8C%E3%81%8D">あとがき</a></h2> <p>正直なところ、読む前はリポジトリやエンティティを用いてDDDしてみたというような記事をみかけては、「それって〇〇アーキテクチャを適用しただけでは…?」と思っていた。でも実際書いてみると、かなり歯ごたえがあって実装したときの達成感のようなものがあったので、書きたくなるのもわかるなぁという感じ。こうして自分も記事にしているので。</p> <p>ただ参考記事や書籍にも書かれているように、ユビキタス言語や境界づけられたコンテキストなどの概念がより重要であり、技術的な側面だけを注力するといわゆる軽量DDDに陥ってしまうので、戦略的設計に関わる知識もインプットしていく。</p> <blockquote> <p>軽量DDDとは、DDDの戦術的パターンの一部だけをつまみ食いする方法で、ユビキタス言語を見つけ出して育てていこうなどという気は毛頭ない。おまけにこの手法は、境界づけられたコンテキストやコンテキストマッピングも使わずに済ませることが多い。技術面だけに注目して、技術的な問題だけを解決したがっているのだ。この方法にはメリットもあるが、戦略的モデリングを併用したときのような大きな見返りは得られない。(実践ドメイン駆動設計より)</p> </blockquote> <p>最後に写経したものはGitHubに置いているので、参考になれば。</p> <p>[https://github.com/chocol4t/bottom-up-ddd-php:embed]</p> <p>nrsさんのサンプルコードはこちら。(C#)</p> <p>[https://github.com/nrslib/BottomUpDDD:embed]</p> <h2 id="参考URL"><a href="#%E5%8F%82%E8%80%83URL">参考URL</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/ytake/valueobjects">ytake/valueobjects</a> <ul> <li>Utilクラスを参考にしました。</li> </ul></li> </ul> choco tag:crieit.net,2005:PublicArticle/14479 2018-07-11T13:04:02+09:00 2018-08-31T01:19:22+09:00 https://crieit.net/posts/Angular-Github-Pages AngularのプロジェクトをGithub Pagesに公開する <p>Crieit初投稿です。元記事は<a target="_blank" rel="nofollow noopener" href="https://chocol4t.hatenablog.com/entry/2018/07/07/144504">こちら</a></p> <p>AngularのプロジェクトをGithub Pagesにデプロイしたときのメモ。</p> <p><a target="_blank" rel="nofollow noopener" href="https://github.com/angular-schule/angular-cli-ghpages">angular-cli-ghpages</a>というパッケージを使用することで簡単にデプロイ出来た。</p> <h2 id="インストール"><a href="#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">インストール</a></h2> <p>コマンドの利用するには、次の条件を満たしておく必要がある。</p> <ul> <li>Node.js: 4.x以上</li> <li>Git: 1.7.6以上</li> <li>(オプション)angular-cliで作成されたプロジェクト</li> </ul> <p>今回実行した環境は次の通り。</p> <ul> <li>MacBook Air (Early 2015)</li> <li>macOS High Sierra (10.13.5)</li> <li>angular-cli: 6.0.7</li> <li>Node.js: 8.11.2</li> <li>Git: 2.17.1</li> </ul> <h2 id="使い方"><a href="#%E4%BD%BF%E3%81%84%E6%96%B9">使い方</a></h2> <p>angular-cli v6だと、ビルド時のディレクトリ構成が<code>dist/REPOSITORY_NAME</code>となっている。</p> <p>そのため、<code>ng build</code>もしくは<code>angular-cli-ghpages</code>でディレクトリを指定する必要がある。</p> <p>今回は<code>angular-cli-ghpages</code>のオプションを使用した。</p> <pre><code class="sh">ng build --prod --base-href "https://USERNAME.github.io/REPOSITORY_NAME/" angular-cli-ghpages --dir="dist/REPOSITORY_NAME" </code></pre> <p>もしくは、</p> <pre><code class="sh">ng build --prod --base-href "/REPOSITORY_NAME/" angular-cli-ghpages --dir="dist/REPOSITORY_NAME" </code></pre> <p>もしくは、</p> <pre><code class="sh"># &lt;base href=&quot;&quot;&gt;となる ng build --prod angular-cli-ghpages --dir="dist/REPOSITORY_NAME" </code></pre> <p>を実行すると、リモートへプッシュが行われる。</p> <p><code>angular-cli-ghpages</code>の代わりに<code>ngh</code>でも実行可能。</p> <h2 id="オプション"><a href="#%E3%82%AA%E3%83%97%E3%82%B7%E3%83%A7%E3%83%B3">オプション</a></h2> <p>コマンド実行時にいくつかオプション設定が可能。</p> <p>使用したものだけ記載しているので、他のオプションについては<a target="_blank" rel="nofollow noopener" href="https://github.com/angular-schule/angular-cli-ghpages/blob/master/README.md">README.md</a>を参照してください。</p> <h3 id="--message"><a href="#--message">--message</a></h3> <ul> <li>コミット時のメッセージを設定。デフォルトは<code>Auto-generated commit</code></li> <li>e.g. <code>ngh --message="New message"</code></li> </ul> <h3 id="--dir"><a href="#--dir">--dir</a></h3> <ul> <li>デプロイするディレクトリを設定。デフォルトは<code>dist</code></li> <li>angular-cli v6だと<code>"outputPath": "dist/REPOSITORY_NAME"</code>となっているので注意</li> <li>e.g. <code>ngh --dir="dist/REPOSITORY_NAME"</code></li> </ul> <h3 id="--branch"><a href="#--branch">--branch</a></h3> <ul> <li>プッシュ先のブランチ名を設定。デフォルトは<code>gh-pages</code></li> <li>e.g. <code>ngh --branch=other-branch</code></li> </ul> <h2 id="Gihub Pagesの設定"><a href="#Gihub+Pages%E3%81%AE%E8%A8%AD%E5%AE%9A">Gihub Pagesの設定</a></h2> <p><code>ngh</code>でプッシュされたのが確認出来れば以下を設定する。</p> <ol> <li>Githubのリポジトリの<code>Settings</code>タブをクリック。</li> <li><code>Github Pages</code>の項目までスクロールし、<code>Source</code>からプッシュしたブランチを設定。</li> <li>URLにアクセスしてページが表示されれば完了!</li> </ol> <h2 id="参考URL"><a href="#%E5%8F%82%E8%80%83URL">参考URL</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/angular-schule/angular-cli-ghpages">angular-schule/angular-cli-ghpages</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://qiita.com/kasaharu/items/29117827a1417fed50e6">Angular アプリケーションを GitHub Pages で公開する方法 - Qiita</a></li> </ul> choco