structure-models.md 27.7 KB
Newer Older
Nobuo Kihara committed
1 2 3 4 5 6 7 8 9
モデル
======

モデルは [MVC](http://ja.wikipedia.org/wiki/Model_View_Controller) アーキテクチャの一部を成すものです。
これは、業務のデータ、規則、ロジックを表現するオブジェクトです。

モデルクラスは、[[yii\base\Model]] またはその子クラスを拡張することによって作成することが出来ます。
基底クラス [[yii\base\Model]] は数多くの有用な機能をサポートしています。

10
* [属性](#attributes): 業務のデータを表現する。通常のオブジェクトプロパティや配列要素のようにしてアクセス出来る。
Nobuo Kihara committed
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
* [属性のラベル](#attribute-labels): 属性の表示ラベルを規定する。
* [一括代入](#massive-assignment): 一回のステップで複数の属性にデータを投入することをサポートしている。
* [検証規則](#validation-rules): 宣言された検証規則に基いて入力されたデータを確認する。
* [データのエクスポート](#data-exporting): カスタマイズ可能な書式を使ってモデルのデータを配列の形式にエクスポートすることが出来る。

`Model` クラスは、[アクティブレコード](db-active-record.md) のような、更に高度なモデルの基底クラスでもあります。
そういう高度なモデルについての詳細は、関連するドキュメントを参照してください。

> Info|情報: あなたのモデルクラスの基底クラスとして [[yii\base\Model]] を使うことは必須の条件ではありません。
  しかしながら、Yii のコンポーネントの多くが [[yii\base\Model]] をサポートするように作られていますので、
  通常は [[yii\base\Model]] がモデルの基底クラスとして推奨されます。


## 属性<a name="attributes"></a>

モデルは業務のデータを *属性* の形式で表現します。
全ての属性はそれぞれパブリックにアクセス可能なモデルのプロパティと同様なものです。
28
[[yii\base\Model::attributes()]] メソッドが、モデルがどのような属性を持つかを規定します。
Nobuo Kihara committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59

属性に対しては、通常のオブジェクトプロパティにアクセスするのと同じようにして、アクセスすることが出来ます。

```php
$model = new \app\models\ContactForm;

// "name" は ContactForm の属性
$model->name = 'example';
echo $model->name;
```

また、配列の要素にアクセスするようして、属性にアクセスすることも出来ます。
これは、[[yii\base\Model]] が [ArrayAccess インターフェイス](http://php.net/manual/ja/class.arrayaccess.php)[ArrayIterator クラス](http://jp2.php.net/manual/ja/class.arrayiterator.php) をサポートしているおかげです。

```php
$model = new \app\models\ContactForm;

// 配列要素のように属性にアクセスする
$model['name'] = 'example';
echo $model['name'];

// 属性に反復アクセスする
foreach ($model as $name => $value) {
    echo "$name: $value\n";
}
```


### 属性を定義する<a name="defining-attributes"></a>

あなたのモデルが [[yii\base\Model]] を直接に拡張するものである場合、既定によって、全ての *static でない public な* メンバ変数は属性となります。
60
例えば、次に示す `ContactForm` モデルは4つの属性、すなわち、`name``email``subject`、そして、`body` を持ちます。
Nobuo Kihara committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
この `ContactForm` モデルは、HTML フォームから受け取る入力データを表現するために使われます。

```php
namespace app\models;

use yii\base\Model;

class ContactForm extends Model
{
    public $name;
    public $email;
    public $subject;
    public $body;
}
```


[[yii\base\Model::attributes()]] をオーバーライドして、属性を異なる方法で定義することが出来ます。
このメソッドはモデルの中の属性の名前を返さなくてはなりません。
80 81 82
例えば、[[yii\db\ActiveRecord]] は、関連付けられたデータベーステーブルのコラム名を属性の名前として返すことによって、属性を定義しています。
これと同時に、定義された属性に対して通常のオブジェクトプロパティと同じようにアクセスすることが出来るように、
`__get()``__set()` などのマジックメソッドをオーバーライドする必要があるかもしれないことに注意してください。
Nobuo Kihara committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103


### 属性のラベル <a name="attribute-labels"></a>

属性の値を表示したり、入力してもらったりするときに、属性と関連付けられたラベルを表示する必要があることがよくあります。
例えば、`firstName` という名前の属性を考えたとき、入力フォームやエラーメッセージのような箇所でエンドユーザに表示するときは、もっとユーザフレンドリーな `First Name` というラベルを表示したいと思うでしょう。

[[yii\base\Model::getAttributeLabel()]] を呼ぶことによって属性のラベルを得ることが出来ます。例えば、

```php
$model = new \app\models\ContactForm;

// "Name" を表示する
echo $model->getAttributeLabel('name');
```

既定では、属性のラベルは属性の名前から自動的に生成されます。
ラベルの生成は [[yii\base\Model::generateAttributeLabel()]] というメソッドによって行われます。
このメソッドは、キャメルケースの変数名を複数の単語に分割し、各単語の最初の文字を大文字にします。
例えば、`username``Username` となり、`firstName``First Name` となります。

104
自動的に生成されるラベルを使用したくない場合は、[[yii\base\Model::attributeLabels()]] をオーバーライドして、属性のラベルを明示的に宣言することが出来ます。例えば、
Nobuo Kihara committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130

```php
namespace app\models;

use yii\base\Model;

class ContactForm extends Model
{
    public $name;
    public $email;
    public $subject;
    public $body;

    public function attributeLabels()
    {
        return [
            'name' => 'Your name',
            'email' => 'Your email address',
            'subject' => 'Subject',
            'body' => 'Content',
        ];
    }
}
```

複数の言語をサポートするアプリケーションでは、属性のラベルを翻訳したいと思うでしょう。
131
これも、以下のように、[[yii\base\Model::attributeLabels()|attributeLabels()]] の中で行うことが出来ます。
Nobuo Kihara committed
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148

```php
public function attributeLabels()
{
    return [
        'name' => \Yii::t('app', 'Your name'),
        'email' => \Yii::t('app', 'Your email address'),
        'subject' => \Yii::t('app', 'Subject'),
        'body' => \Yii::t('app', 'Content'),
    ];
}
```

さらに進んで、条件に従って属性のラベルを定義しても構いません。例えば、モデルが使用される
[シナリオ](#scenarios) に基づいて、同じ属性に対して違うラベルを返すことことが出来ます。

> Info|情報: 厳密に言えば、属性のラベルは [ビュー](structure-views.md) の一部を成すものです。
149
  しかし、たいていの場合、モデルの中でラベルを宣言する方が便利が良く、結果としてクリーンで再利用可能なコードになります。
Nobuo Kihara committed
150 151 152 153 154 155 156 157 158 159 160


## シナリオ<a name="scenarios"></a>

モデルはさまざまに異なる *シナリオ* で使用されます。
例えば、`User` モデルはユーザログインの入力を収集するために使われますが、同時に、ユーザ登録の目的でも使われます。
異なるシナリオの下では、モデルが使用する業務のルールとロジックも異なるでしょう。
例えば、`email` 属性はユーザ登録の際には必須とされるかも知れませんが、ログインの際にはそうではないでしょう。

モデルは [[yii\base\Model::scenario]] プロパティを使って、自身が使われているシナリオを追跡します。
既定では、モデルは `default` という単一のシナリオのみをサポートします。
161
次のコードは、モデルのシナリオを設定する二つの方法を示すものです。
Nobuo Kihara committed
162 163 164 165 166 167

```php
// プロパティとしてシナリオをセットする
$model = new User;
$model->scenario = 'login';

168
// シナリオは設定情報でセットされる
Nobuo Kihara committed
169 170 171 172
$model = new User(['scenario' => 'login']);
```

既定では、モデルによってサポートされるシナリオは、モデルで宣言されている [検証規則](#validation-rules) によって決定されます。
173
しかし、次のように、[[yii\base\Model::scenarios()]] メソッドをオーバーライドして、この動作をカスタマイズすることが出来ます。
Nobuo Kihara committed
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201

```php
namespace app\models;

use yii\db\ActiveRecord;

class User extends ActiveRecord
{
    public function scenarios()
    {
        return [
            'login' => ['username', 'password'],
            'register' => ['username', 'email', 'password'],
        ];
    }
}
```

> Info|情報: 上記の例と後続の例では、モデルクラスは [[yii\db\ActiveRecord]] を拡張するものとなっています。
  というのは、複数のシナリオの使用は、通常、[アクティブレコード](db-active-record.md) クラスで発生するからです。

`seanarios()` メソッドは、キーがシナリオの名前であり、値が対応する *アクティブな属性* である配列を返します。
アクティブな属性とは、[一括代入](#massive-assignment) することが出来て、[検証](#validation-rules) の対象になる属性です。
上記の例では、`login` シナリオにおいては `username``password` の属性がアクティブであり、一方、
`register` シナリオにおいては、`username``password` に加えて `email` もアクティブです。

`scenarios()` の既定の実装は、検証規則の宣言メソッドである [[yii\base\Model::rules()]] に現れる全てのシナリオを返すものです。
`scenarios()` をオーバーライドするときに、デフォルトのシナリオに加えて新しいシナリオを導入したい場合は、
202
次のようなコードを書きます。
Nobuo Kihara committed
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227

```php
namespace app\models;

use yii\db\ActiveRecord;

class User extends ActiveRecord
{
    public function scenarios()
    {
        $scenarios = parent::scenarios();
        $scenarios['login'] = ['username', 'password'];
        $scenarios['register'] = ['username', 'email', 'password'];
        return $scenarios;
    }
}
```

シナリオの機能は、主として、[検証](#validation-rules)[属性の一括代入](#massive-assignment) によって使用されます。
しかし、他の目的に使うことも可能です。例えば、現在のシナリオに基づいて異なる [属性のラベル](#attribute-labels) を宣言することも出来ます。


## 検証規則<a name="validation-rules"></a>

モデルのデータをエンドユーザから受け取ったときは、データを検証して、それが一定の規則 (*検証規則*、あるいは、いわゆる *ビジネスルール*) を満たしていることを確認しなければなりません。
228
`ContactForm` モデルを例に挙げるなら、全ての属性が空ではなく、`email` 属性が有効なメールアドレスを含んでいることを確認したいでしょう。
Nobuo Kihara committed
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
いずれかの属性の値が対応するビジネスルールを満たしていないときは、ユーザがエラーを訂正するのを助ける適切なエラーメッセージが表示されるべきです。

受信したデータを検証するために、[[yii\base\Model::validate()]] を呼ぶことが出来ます。
このメソッドは、[[yii\base\Model::rules()]] で宣言された検証規則を使って、該当するすべての属性を検証します。
エラーが見つからなければ、メソッドは true を返します。そうでなければ、[[yii\base\Model::errors]]
にエラーを保存して、false を返します。例えば、

```php
$model = new \app\models\ContactForm;

// モデルの属性にユーザの入力を代入する
$model->attributes = \Yii::$app->request->post('ContactForm');

if ($model->validate()) {
    // すべての入力値は有効である
} else {
    // 検証が失敗: $errors はエラーメッセージを含む配列
    $errors = $model->errors;
}
```


251 252
モデルに関連付けられた検証規則を宣言するためには、[[yii\base\Model::rules()]] メソッドをオーバーライドして、モデルの属性が満たすべき規則を返すようにします。
次の例は、`ContactForm` モデルのために宣言された検証規則を示します。
Nobuo Kihara committed
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

```php
public function rules()
{
    return [
        // name、email、subject、body の属性が必須
        [['name', 'email', 'subject', 'body'], 'required'],

        // email 属性は、有効なメールアドレスでなければならない
        ['email', 'email'],
    ];
}
```

一個の規則は、一個または複数の属性を検証するために使うことが出来ます。
また、一個の属性は、一個または複数の規則によって検証することが出来ます。
269
検証規則をどのように宣言するかについての詳細は [入力を検証する](input-validation.md) の節を参照してください。
Nobuo Kihara committed
270

271 272
時として、特定の [シナリオ](#scenarios) にのみ適用される規則が必要になるでしょう。
そのためには、下記のように、規則に `on` プロパティを指定することが出来ます。
Nobuo Kihara committed
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289

```php
public function rules()
{
    return [
        // "register" シナリオでは、username、email、password のすべてが必須
        [['username', 'email', 'password'], 'required', 'on' => 'register'],

        // "login" シナリオでは、username と password が必須
        [['username', 'password'], 'required', 'on' => 'login'],
    ];
}
```

`on` プロパティを指定しない場合は、その規則は全てのシナリオに適用されることになります。
現在の [[yii\base\Model::scenario|シナリオ]] に適用可能な規則は *アクティブな規則* と呼ばれます。

290 291
属性が検証されるのは、それが `scenarios()` の中でアクティブな属性であると宣言されており、かつ、その属性が `rules()`
の中で宣言されている一つまたは複数のアクティブな規則と結び付けられている場合であり、また、そのような場合だけです。
Nobuo Kihara committed
292 293 294 295 296 297 298


## 一括代入<a name="massive-assignment"></a>

一括代入は、一行のコードを書くだけで、ユーザの入力したデータをモデルに投入できる便利な方法です。
一括代入は、入力されたデータを [[yii\base\Model::$attributes]] に直接に代入することによって、モデルの属性にデータを投入します。
次の二つのコード断片は等価であり、どちらもエンドユーザから送信されたフォームのデータを `ContactForm` モデルの属性に割り当てようとするものです。
299
明らかに、一括代入を使う前者の方が、後者よりも明瞭で間違いも起こりにくいでしょう。
Nobuo Kihara committed
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317

```php
$model = new \app\models\ContactForm;
$model->attributes = \Yii::$app->request->post('ContactForm');
```

```php
$model = new \app\models\ContactForm;
$data = \Yii::$app->request->post('ContactForm', []);
$model->name = isset($data['name']) ? $data['name'] : null;
$model->email = isset($data['email']) ? $data['email'] : null;
$model->subject = isset($data['subject']) ? $data['subject'] : null;
$model->body = isset($data['body']) ? $data['body'] : null;
```


### 安全な属性<a name="safe-attributes"></a>

318 319
一括代入は、いわゆる *安全な属性*、すなわち、[[yii\base\Model::scenarios()]] においてモデルの現在の [[yii\base\Model::scenario|シナリオ]]
のためにリストされている属性に対してのみ適用されます。
Nobuo Kihara committed
320 321 322 323 324 325 326 327 328 329 330 331
例えば、`User` モデルが次のようなシナリオ宣言を持っている場合において、現在のシナリオが `login` であるときは、`username``password` のみが一括代入が可能です。その他の属性はいっさい触れられません。

```php
public function scenarios()
{
    return [
        'login' => ['username', 'password'],
        'register' => ['username', 'email', 'password'],
    ];
}
```

332 333
> Info|情報: 一括代入が安全な属性に対してのみ適用されるのは、どの属性がエンドユーザの入力データによって修正されうるかを制御する必要があるからです。
  例えば、`User` モデルに、ユーザに割り当てられた権限を決定する `permission` という属性がある場合、
Nobuo Kihara committed
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
  この属性が修正できるのは、管理者がバックエンドのインターフェイスを通じてする時だけに制限したいでしょう。

[[yii\base\Model::scenarios()]] の既定の実装は [[yii\base\Model::rules()]] に現われる全てのシナリオと属性を返すものです。
従って、このメソッドをオーバーライドしない場合は、アクティブな検証規則のどれかに出現する限り、その属性は安全である、ということになります。

このため、実際に検証することなく属性を安全であると宣言できるように、`safe` というエイリアスを与えられた特別なバリデータが提供されています。例えば、次の規則は `title``description` の両方が安全な属性であると宣言しています。

```php
public function rules()
{
    return [
        [['title', 'description'], 'safe'],
    ];
}
```


### 安全でない属性<a name="unsafe-attributes"></a>

353
上記で説明したように、[[yii\base\Model::scenarios()]] メソッドは二つの目的を持っています。
Nobuo Kihara committed
354 355 356
すなわち、どの属性が検証されるべきかを決めることと、どの属性が安全であるかを決めることです。
めったにない場合として、属性を検証する必要はあるが、安全であるという印は付けたくない、ということがあります。
そういう時は、下の例の `secret` 属性のように、`scenarios()` の中で宣言するときに属性の名前の前に感嘆符
357
`!` を前置することが出来ます。
Nobuo Kihara committed
358 359 360 361 362 363 364 365 366 367 368

```php
public function scenarios()
{
    return [
        'login' => ['username', 'password', '!secret'],
    ];
}
```

このモデルが `login` シナリオにある場合、三つの属性は全て検証されます。しかし、`username`
369
`password` の属性だけが一括代入が可能です。`secret` 属性に入力値を割り当てるためには、下記のように明示的に代入を実行する必要があります。
Nobuo Kihara committed
370 371 372 373 374 375 376 377 378 379 380 381

```php
$model->secret = $secret;
```


## データのエクスポート <a name="data-exporting"></a>

モデルを他の形式にエクスポートする必要が生じることはよくあります。例えば、一群のモデルを JSON や
Excel 形式に変換したい場合があるでしょう。
エクスポートのプロセスは二つの独立したステップに分割することが出来ます。
最初のステップで、モデルは配列に変換されます。そして第二のステップで、配列が目的の形式に変換されます。
382 383
あなたは最初のステップだけに注力しても構いません。と言うのは、第二のステップは汎用的なデータフォーマッタ、例えば [[yii\web\JsonResponseFormatter]]
によって達成できるからです。
Nobuo Kihara committed
384 385 386 387 388 389 390 391 392 393 394 395 396

モデルを配列に変換する最も簡単な方法は、[[yii\base\Model::$attributes]] プロパティを使うことです。
例えば、

```php
$post = \app\models\Post::findOne(100);
$array = $post->attributes;
```

既定によって、[[yii\base\Model::$attributes]] プロパティは [[yii\base\Model::attributes()]] で宣言されている *全て* の属性の値を返します。

モデルを配列に変換するためのもっと柔軟で強力な方法は、[[yii\base\Model::toArray()]] メソッドを使うことです。
このメソッドの既定の動作は [[yii\base\Model::$attributes]] のそれと同じものです。
397 398
しかしながら、このメソッドを使うと、どのデータ項目 (*フィールド* と呼ばれます)
を結果の配列に入れるか、そして、その項目にどのような書式を適用するかを選ぶことが出来ます。
399
実際、[レスポンス形式の設定](rest-response-formatting.md) で説明されているように、RESTful
400
ウェブサービスの開発においては、これがモデルをエクスポートする既定の方法となっています。
Nobuo Kihara committed
401 402 403 404


### フィールド<a name="fields"></a>

405
フィールドとは、単に、モデルの [[yii\base\Model::toArray()]] メソッドを呼ぶことによって取得される配列に含まれる名前付きの要素のことです。
Nobuo Kihara committed
406

407 408 409 410 411
既定では、フィールドの名前は属性の名前と等しいものになります。しかし、この既定の動作は、[[yii\base\Model::fields()|fields()]]
および/または [[yii\base\Model::extraFields()|extraFields()]] メソッドをオーバーライドして、変更することが出来ます。
どちらのメソッドも、フィールド定義のリストを返します。
`fields()` によって定義されるフィールドは、デフォルトフィールドです。すなわち、`toArray()` はデフォルトでこれらのフィールドを返す、ということを意味します。
`extraFields()` メソッドは、`$expand` パラメータによって指定する限りにおいて `toArray()` によって返される追加のフィールドを定義するものです。
Nobuo Kihara committed
412 413 414 415 416 417 418 419
例として、次のコードは、`fields()` で定義された全てのフィールドと、
(`extraFields()` で定義されていれば) `prettyName``fullAddress` フィールドを返すものです。

```php
$array = $model->toArray([], ['prettyName', 'fullAddress']);
```

`fields()` をオーバーライドして、フィールドを追加、削除、リネーム、再定義することが出来ます。
420 421
`fields()` の返り値は配列でなければなりません。配列のキーはフィールド名であり、配列の値は対応するフィールド定義です。
フィールドの定義には、プロパティ/属性 の名前か、または、対応するフィールドの値を返す無名関数を使うことが出来ます。
Nobuo Kihara committed
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
フィールド名がそれを定義する属性名と同一であるという特殊な場合においては、配列のキーを省略することが出来ます。
例えば、

```php
// 明示的に全てのフィールドをリストする方法。(API の後方互換性を保つために) DB テーブルやモデル属性の
// 変更がフィールドの変更を引き起こさないことを保証したい場合に適している。
public function fields()
{
    return [
        // フィールド名が属性名と同じ
        'id',

        // フィールド名は "email"、対応する属性名は "email_address"
        'email' => 'email_address',

        // フィールド名は "name"、その値は PHP コールバックで定義
        'name' => function () {
            return $this->first_name . ' ' . $this->last_name;
        },
    ];
}

444
// いくつかのフィールドを除去する方法。親の実装を継承しつつ、公開すべきでないフィールドは
Nobuo Kihara committed
445 446 447 448 449
// 除外したいときに適している。
public function fields()
{
    $fields = parent::fields();

450
    // 公開すべきでない情報を含むフィールドを削除する
Nobuo Kihara committed
451 452 453 454 455 456 457
    unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']);

    return $fields;
}
```

> Warning|警告: 既定ではモデルの全ての属性がエクスポートされる配列に含まれるため、データを精査して、
458
> 公開すべきでない情報が含まれていないことを確認すべきです。そういう情報がある場合は、
Nobuo Kihara committed
459 460 461 462
> `fields()` をオーバーライドして、除去すべきです。上記の例では、`auth_key`、`password_hash`
> および `password_reset_token` を選んで除去しています。


463
## ベストプラクティス<a name="best-practices"></a>
Nobuo Kihara committed
464 465

モデルは、業務のデータ、規則、ロジックを表わす中心的なオブジェクトです。
466
モデルは、さまざまな場所で再利用される必要がよくあります。
Nobuo Kihara committed
467 468 469 470
良く設計されたアプリケーションでは、通常、モデルは [コントローラ](structure-controllers.md) よりもはるかに重いものになります。

要約すると、モデルは、

471 472 473
* ビジネスデータを表現する属性を含むことが出来ます。
* データの有効性と整合性を保証する検証規則を含むことが出来ます。
* ビジネスロジックを実装するメソッドを含むことが出来ます。
474
* リクエスト、セッション、または他の環境データに直接アクセスするべきではありません。
475 476
  これらのデータは、[コントローラ](structure-controllers.md) によってモデルに注入されるべきです。
* HTML を埋め込むなどの表示用のコードは避けるべきです -  表示は [ビュー](structure-views.md) で行う方が良いです。
477
* あまりに多くの [シナリオ](#scenarios) を単一のモデルで持つことは避けましょう。
Nobuo Kihara committed
478 479 480 481

大規模で複雑なシステムを開発するときには、たいてい、上記の最後にあげた推奨事項を考慮するのが良いでしょう。
そういうシステムでは、モデルは数多くの場所で使用され、それに従って、数多くの規則セットやビジネスロジックを含むため、非常に大きくて重いものになり得ます。
コードの一ヶ所に触れるだけで数ヶ所の違った場所に影響が及ぶため、ついには、モデルのコードの保守が悪夢になってしまうこともよくあります。
482
モデルのコードの保守性を高めるために、以下の戦略をとることが出来ます。
Nobuo Kihara committed
483 484

* 異なる [アプリケーション](structure-applications.md)[モジュール](structure-modules.md)
485 486
  によって共有される一連の基底モデルクラスを定義します。
  これらのモデルクラスは、すべてで共通に使用される最小限の規則セットとロジックのみを含むべきです。
487 488
* モデルを使用するそれぞれの [アプリケーション](structure-applications.md) または [モジュール](structure-modules.md)
  において、対応する基底モデルクラスから拡張した具体的なモデルクラスを定義します。
489
  この具体的なモデルクラスが、そのアプリケーションやモジュールに固有の規則やロジックを含むべきです。
Nobuo Kihara committed
490

491 492 493
例えば、[アドバンストアプリケーションテンプレート](tutorial-advanced-app.md) の中で、基底モデルクラス `common\models\Post`
を定義することが出来ます。次に、フロントエンドアプリケーションにおいては、`common\models\Post` から拡張した具体的なモデルクラス
`frontend\models\Post` を定義して使います。また、バックエンドアプリケーションにおいても、同様に、`backend\models\Post` を定義します。
Nobuo Kihara committed
494 495
この戦略を取ると、`frontend\models\Post` の中のコードはフロントエンドアプリケーション固有のものであると保証することが出来ます。
そして、フロントエンドのコードにどのような変更を加えても、バックエンドアプリケーションを壊すかもしれないと心配する必要がなくなります。