Yii2 framework backup
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

8.9 KiB

データプロバイダ

Note|注意: この節はまだ執筆中です。

データプロバイダは、 yii\data\DataProviderInterface によってデータセットを抽象化し、ページネーションと並べ替えを処理します。 グリッドやリストなどのデータウィジェット で使用することが出来ます。

Yii は三つのデータプロバイダを内蔵しています。すなわち、yii\data\ActiveDataProvideryii\data\ArrayDataProvider そして yii\data\SqlDataProvider です。

アクティブデータプロバイダ

ActiveDataProvideryii\db\Query および yii\db\ActiveQuery を使って DB クエリを実行して、データを提供します。

次のコードは、これを使って、ActiveRecord のインスタンスを提供する例です。

$provider = new ActiveDataProvider([
    'query' => Post::find(),
    'pagination' => [
        'pageSize' => 20,
    ],
]);

// 現在のページの投稿を取得する
$posts = $provider->getModels();

そして次の例は、ActiveRecord なしで ActiveDataProvider を使う方法を示すものです。

$query = new Query();
$provider = new ActiveDataProvider([
    'query' => $query->from('post'),
    'sort' => [
        // デフォルトのソートを name ASC, created_at DESC とする
        'defaultOrder' => [
            'name' => SORT_ASC, 
            'created_at' => SORT_DESC
        ]
    ],
    'pagination' => [
        'pageSize' => 20,
    ],
]);

// 現在のページの投稿を取得する
$posts = $provider->getModels();

配列データプロバイダ

ArrayDataProvider はデータの配列に基づいたデータプロバイダを実装するものです。

yii\data\ArrayDataProvider::$allModels プロパティが、並べ替えやページネーションの対象となるデータの全てのモデルを含みます。 ArrayDataProvider は、並べ替えとページネーションを実行した後に、データを提供します。 yii\data\ArrayDataProvider::$sort および yii\data\ArrayDataProvider::$pagination のプロパティを構成して、並べ替えとページネーションの動作をカスタマイズすることが出来ます。

yii\data\ArrayDataProvider::$allModels 配列の要素は、オブジェクト (例えば、モデルのオブジェクト) であるか、連想配列 (例えば、DAO のクエリ結果) であるかの、どちらかです。 yii\data\ArrayDataProvider::$key プロパティには、必ず、データレコードを一意的に特定出来るフィールドの名前をセットするか、そのようなフィールドがない場合は false をセットするかしなければなりません。

ActiveDataProvider と比較すると、ArrayDataProvider は、yii\data\ArrayDataProvider::$allModels を準備して持たなければならないため、効率が良くありません。

ArrayDataProvider は次のようにして使用することが出来ます。

$query = new Query();
$provider = new ArrayDataProvider([
    'allModels' => $query->from('post')->all(),
    'sort' => [
        'attributes' => ['id', 'username', 'email'],
    ],
    'pagination' => [
        'pageSize' => 10,
    ],
]);
// 現在のページの投稿を取得する
$posts = $provider->getModels();

Note|注意: 並べ替えの機能を使いたいときは、どのカラムがソート出来るかをプロバイダが知ることが出来るように、sort プロパティを構成しなければなりません。

SQL データプロバイダ

SqlDataProvider は、素の SQL 文に基づいたデータプロバイダを実装するものです。 これは、各要素がクエリ結果の行を表す配列の形式でデータを提供します。

他のプロバイダ同様に、SqlDataProvider も、並べ替えとページネーションをサポートしています。 並べ替えとページネーションは、与えられた yii\data\SqlDataProvider::$sql 文を "ORDER BY" 句および "LIMIT" 句で修正することによって実行されます。 yii\data\SqlDataProvider::$sort および yii\data\SqlDataProvider::$pagination のプロパティを構成して、並べ替えとページネーションの動作をカスタマイズすることが出来ます。

SqlDataProvider は次のようにして使用することが出来ます。

$count = Yii::$app->db->createCommand('
    SELECT COUNT(*) FROM user WHERE status=:status
', [':status' => 1])->queryScalar();

$dataProvider = new SqlDataProvider([
    'sql' => 'SELECT * FROM user WHERE status=:status',
    'params' => [':status' => 1],
    'totalCount' => $count,
    'sort' => [
        'attributes' => [
            'age',
            'name' => [
                'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
                'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
                'default' => SORT_DESC,
                'label' => 'Name',
            ],
        ],
    ],
    'pagination' => [
        'pageSize' => 20,
    ],
]);

// 現在のページの user のレコードを取得する
$models = $dataProvider->getModels();

Note|注意: ページネーションの機能を使いたい場合は、yii\data\SqlDataProvider::$totalCount プロパティに (ページネーション無しの) 総行数を設定しなければなりません。 そして、並べ替えの機能を使いたい場合は、どのカラムがソート出来るかをプロバイダが知ることが出来るように、yii\data\SqlDataProvider::$sort プロパティを構成しなければなりません。

あなた自身のカスタムデータプロバイダを実装する

Yii はあなた自身のカスタムデータプロバイダを導入することを許容しています。 そうするためには、下記の protected メソッドを実装する必要があります。

  • prepareModels - 現在のページで利用できるデータモデルを準備して、それを配列として返します。
  • prepareKeys - 現在利用できるデータモデルの配列を受け取って、それと関連付けられるキーの配列を返します。
  • prepareTotalCount - データプロバイダにあるデータモデルの総数を示す値を返します。

下記は、CSV ファイルを効率的に読み出すデータプロバイダのサンプルです。

<?php
class CsvDataProvider extends \yii\data\BaseDataProvider
{
    /**
     * @var string 読み出すファイルの名前
     */
    public $filename;
    
    /**
     * @var string|callable キーカラムの名前またはそれを返すコーラブル
     */
    public $key;
    
    /**
     * @var SplFileObject
     */
    protected $fileObject; // ファイルの特定の行までシークするのに SplFileObject が非常に便利
    
 
    /**
     * @inheritdoc
     */
    public function init()
    {
        parent::init();
        
        // ファイルを開く
        $this->fileObject = new SplFileObject($this->filename);
    }
 
    /**
     * @inheritdoc
     */
    protected function prepareModels()
    {
        $models = [];
        $pagination = $this->getPagination();
 
        if ($pagination === false) {
            // ページネーションが無い場合、全ての行を読む
            while (!$this->fileObject->eof()) {
                $models[] = $this->fileObject->fgetcsv();
                $this->fileObject->next();
            }
        } else {
            // ページネーションがある場合、一つのページだけを読む
            $pagination->totalCount = $this->getTotalCount();
            $this->fileObject->seek($pagination->getOffset());
            $limit = $pagination->getLimit();
 
            for ($count = 0; $count < $limit; ++$count) {
                $models[] = $this->fileObject->fgetcsv();
                $this->fileObject->next();
            }
        }
 
        return $models;
    }
 
    /**
     * @inheritdoc
     */
    protected function prepareKeys($models)
    {
        if ($this->key !== null) {
            $keys = [];
 
            foreach ($models as $model) {
                if (is_string($this->key)) {
                    $keys[] = $model[$this->key];
                } else {
                    $keys[] = call_user_func($this->key, $model);
                }
            }
 
            return $keys;
        } else {
            return array_keys($models);
        }
    }
 
    /**
     * @inheritdoc
     */
    protected function prepareTotalCount()
    {
        $count = 0;
 
        while (!$this->fileObject->eof()) {
            $this->fileObject->next();
            ++$count;
        }
 
        return $count;
    }
}