Web制作無料相談会(純喫茶LIG)
Web制作無料相談会(純喫茶LIG)
2019.07.19

【開発のススメ】フレームワークはひと手間かける心づかいが大事 〜Laravel編〜

やなさん

まいど。バックエンドエンジニアのやなさんです。

突然ですが、みなさんはWeb開発をするとき、フレームワークを使ってますか? おそらく、だいたいの人はWeb開発をする場合は使っていることでしょう。

今回はそんなフレームワークに関する私なりの使い方についてです。フレームワークを導入する前にちょっとした手間をかけることで、フレームワークをそのまま利用するより、品質・保守性・作業効率・拡張性が格段に上がります。

たくさんの人がすでに実践している内容かと思いますが、これからフレームワークを使った開発を始める人の参考になれば幸いです。

では、さっそくいってみましょう。

「フレームワーク」って?

フレームワークとは
フレームワークは直訳すると「枠組み」です。Web開発において呼ばれるフレームワークは、正しくは「Webアプリケーションフレームワーク」と呼ばれるものです。

Webアプリケーション、Webサービスを開発するための枠組みと、アプリケーションを開発する際によく利用される部品群(ライブラリ)で構成されるものが一般的です。部品群(ライブラリ)とは、DBアクセス機能や、認証機能、セッション管理やテンプレートエンジン機能などを指します。

Webアプリケーション構築で代表的なフレームワークは数多くあります。Microsoft系なら「.NetFramework」、Javaなら「Spring」「Play Framework」、PHPなら「Laravel」「CakePHP」、Rubyなら「Ruby on rails」、Pythonなら「Django」「Flask」など、言語ごとにさまざまなフレームワークが存在します。

今回はPHPのWebアプリケーションフレームワーク「Laravel」をベースに説明してみようと思います。

フレームワークを通常どおり使う場合

まずはフレームワークの通常の使い方から。以下サンプルコードをご覧ください。

コントローラークラス

<?php
namespace App\Http\Controllers; 
use Illuminate\Routing\Controller;
class HogeController extends Controller
{
    public function index()
    {
		// 何か処理を書く

		// hoge.hogeのbladeを表示
		return view('hoge.hoge');
    }
}

リクエストクラス

<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class HogeFormRequest extends FormRequest
{
	/**
	 * リクエストに適用するバリデーションルールを取得
	 * @return array
	 */
	public function rules()
	{
		return [
			'email' => 'required|email',
			'password' => 'required',
			'password_conf' => 'required_with:password|same:password',
		];
	}
}

モデル

<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
	// 必要に応じて処理を書く
	public function hoge()
	{
		// 必要に応じて処理を書く
	}
}

useでLaravel標準のクラスをインポートし、そのクラスを継承して使う場合の一般的な書き方はこんな感じだと思います。

私が推奨するフレームワークの使い方

私がおすすめしたいのは、

「フレームワークの標準クラスを継承したスーパークラス(基底クラス)を作成し、作成したスーパークラスを各機能で継承する」

方法です。

どんな使い方かというと、以下のような形です。まずはフレームワークを継承したスーパークラスの作り方から。

コントローラーのスーパークラス

<?php
namespace App\Base\Http\Controllers; 
use Illuminate\Routing\Controller;
class BaseController extends Controller
{
    /**
     * Viewに必ず渡す項目
     * @var array
     */
    protected $items = [
        'hoge1' => '',
        'hoge2' => [],
        'hoge3' => false,
    ];
	
	public function renderer($view_name)
	{
		$this->view = view($view_name);
		foreach ($this->items as $key => $item) {
			$data[$key] = $this->$key;
		}
		return $this->view->with($data);
    }
}

リクエストのスーパークラス

<?php
namespace App\Base\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class BaseFormRequest extends FormRequest
{
	// リクエストクラス共通で必要な処理を以下に書く

	public function rules()
    {
        // リクエスト前の共通処理。

        $this->method = $this->method();
        $rules = $this->requestRules();
        if ($this->method == 'PUT') {
            $rules = $this->updateChangeRules($rules);
        }
        return $rules;
    }

    protected function requestRules()
    {
        return [];
    }

    protected function updateChangeRules($rules)
    {
        // $rules['hoge'] = 'required';
        return $rules;
    }
}

モデルのスーパークラス

<?php
namespace App\Base\Models;
use Illuminate\Database\Eloquent\Model;
class BaseModel extends Model
{
	// モデル共通で必要な処理を以下に書く
	
    protected $guarded = ['id'];
    protected $append = ['created_id', 'updated_id'];

    public function getTableColumns()
    {
        return \Schema::getColumnListing($this->table);
    }
}

上記のようにLaravel標準のクラスを継承したスーパークラスを準備します(このクラスをラッパークラスとか呼ぶ人もいたりします)。

そして各機能は作成したスーパークラスを継承する形に修正します。

各機能のコントローラークラス

<?php
namespace App\Http\Controllers; 
use App\Base\Http\Controllers\BaseController; // インポートをスーパークラスに
class HogeController extends BaseController
{
    public function index()
    {
		// 何か処理を書く

		// hoge.hogeのbladeを表示
		return $this->renderer('hoge.hoge');
    }
}

各機能のリクエストクラス

<?php
namespace App\Http\Requests;
use App\Base\Http\Requests\BaseFormRequest; // インポートをスーパークラスに
class HogeFormRequest extends BaseFormRequest
{
	/**
	 * リクエストに適用するバリデーションルールを取得
	 * @return array
	 */
	public function requestRules()
	{
		return [
			'email' => 'required|email',
			'password' => 'required',
			'password_conf' => 'required_with:password|same:password',
		];
	}	
}

各機能のモデル

<?php
namespace App\Models;
use App\Base\Models\BaseModel; // インポートをスーパークラスに
class User extends BaseModel
{
	// 必要に応じて処理を書く
	public function hoge()
	{
		// 必要に応じて処理を書く
	}
}

継承しておくことのメリット

機能の共通化

共通的に必要な処理やプロパティなどをスーパークラスに実装しておくことで、各機能は実装せずとも処理を利用することが可能になり、バグのリスクや、生産性の向上を図ることが可能です。

システム全体の機能拡張や、保守が対応しやすくなる

Web開発では、開発途中に要件の追加が発生することがしばしば(というか、頻繁に?)あります。そして、最悪の場合、要件の追加内容によってはどうしてもシステム全体に対して修正しないといけない対応が発生することもあります。

そういった不測の事態をある程度想定してスーパークラスを準備しておくことで、各機能毎に修正をせず、スーパークラス内の修正をすることで対応可能なように備えておくことが可能です。

より厳密なコードの統一を図ることができる

システム規模が大きくなれば大きくなるほど、複数のエンジニアで開発が必要となります。フレームワークの標準クラスをそのまま利用するだけでも、ある程度のコードの統一を図ることは可能です。しかしフレームワークのままだと汎用的な作りとなっているため、各エンジニアの個性が出る可能性があります。つまり、エンジニアごとに違う作りになってしまう可能性があるのです。

そういったエンジニアの個性が出来る限り発生しないように厳密に制御することで、さらなるコードの統一化を図ることが可能です。

まとめ

フレームワークを利用することで、1から開発することを考えれば劇的な生産性で開発することができます。ただ、なにも考えずフレームワークを利用すると、新しい機能を組み込むときにフレームワークの制限により全体的な改修が必要となる場合も多々あります。

全体的な改修については、継承したクラスで吸収できるような「保守性・拡張性」を意識したフレームワークの利用を考えてみませんか?

システム開発は計画的に。

それではまた。やなさんでした。