【问题标题】:Invalid argument supplied for foreach() -- When trying to make a query on a SearchModel - Yii2为 foreach() 提供的参数无效 - 尝试在 SearchModel 上进行查询时 - Yii2
【发布时间】:2020-12-05 17:18:59
【问题描述】:

我正在尝试为迷你地理定位系统制作搜索模型。每当我尝试通过直接调用 GeoData 模型对数据进行排序时,除非我们尝试排序,否则它会起作用。

但是当我们尝试使用 CustomMade SearchModel 时,它会发送: 为 foreach() 提供的参数无效

这是 SearchModel:

<?php namespace app\models;
use Yii;
use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\GeoData;
/**
 * This is the ActiveQuery class for [[GeoData]].
 *
 * @see GeoData
 */
class GeoDataSearch extends GeoData
{
    const TODOS = 1;
    const FECHA = 2;
    const ENVIADO_POR = 3;

    public function rules()
    {
         return [
            [['latitude', 'longitude'], 'required'],
            [['latitude', 'longitude', 'accuracy', 'speed', 'betterlocation'], 'number'],
            [['device_id', 'active', 'sended', 'mobildate', 'created_at', 'updated_at', 'created_by'], 'integer'],
            [['created_by'], 'exist', 'skipOnError' => true, 'targetClass' => User::class, 'targetAttribute' => ['created_by' => 'id']],
        ];
    }
    /*public function active()
    {
        return $this->andWhere('[[status]]=1');
    }*/

    public function scenarios()
    {
        return Model::scenarios();
    }
    public function search($params)
    {
        $query = GeoData::find()->where(['created_by' => $params])->all();

            $dataProvider = new ActiveDataProvider([
                'query' => $query,
                'sort' => [
                    'defaultOrder' => [
                        'created_at' => SORT_DESC,
                    ]
                ]
                
            ]);
        
        $dataProvider->sort->attributes['created_at'] = [
            'asc' => ['created_at' => SORT_ASC],
            'desc' => ['created_at' => SORT_DESC]
        ];
        $dataProvider->sort->attributes['created_by'] = [
            'asc' => ['created_by' => SORT_ASC],
            'desc' => ['created_by' => SORT_DESC]
        ];
        $dataProvider->sort->attributes['geo_id'] = [
            'asc' => ['geo_id' => SORT_ASC],
            'desc' => ['geo_id' => SORT_DESC]
        ];

        $this->load($params);
   
        $query->andFilterWhere([
            'geo_id' => $this->geo_id,
            'latitude' => $this->latitude,
            'longitude' => $this->longitude,
            'accuracy' => $this->accuracy,
            'speed' => $this->speed,
            'device_id' => $this->device_id,
            'betterlocation' => $this->betterlocation,
            'active' => $this->active,
            'mobiledate' => $this->mobildate,
            'sended' => $this->sended,
            'updated_at' => $this->updated_at,
            'created_at' => $this->created_at,
            'created_by' => $this->created_by,
        ]);

        return $dataProvider;

    }

}

控制器(注释的代码有效,但不允许我使用 GridView 也不允许过滤或排序:

public function actionView($id)
    {
        $title = "Ver Historial";
        $id = $_GET['id'];
        $searchModel = new GeoDataSearch;
        
        $dataProvider = $searchModel->search($id);
        return $this->render(
            'view',
            [
                'title' => $title,
                'searchModel' => $searchModel,
                'dataProvider' => $dataProvider
        ]);
/*
        if (Yii::$app->user->can(AuthItem::ROLE_ADMINISTRATOR))
        {
        $id = $_GET['id'];
        $title = "Ver Historial";
        $model = new GeoData;
        $dataProvider = $model::findAll(['created_by'=> $id]); 
        return $this->render(
            'view',
            [
                'title' => $title,
                'dataProvider' => $dataProvider,
            ]
            );
        } else {
            throw new ForbiddenHttpException('Access denied for user '.Yii::$app->user->identity->id);
        }
   */
    }

任何建议将不胜感激!

【问题讨论】:

  • 我认为您在搜索功能中使用参数是不正确的。 params 应该是一个 'attributes' => 'value' 对的数组。你应该相应地更新你的代码。
  • 使用ActiveDataProvider,您的$query 不应调用all(),因为它不再是Query 对象(它将是模型数组)。

标签: php model yii2 yii2-model cactivedataprovider


【解决方案1】:

首先你的 GeoDataSearch search() 函数应该是这样的:

public function search($params)
{
    $query = GeoData::find();

    $dataProvider = new ActiveDataProvider([
        'query' => $query,
        'sort' => [
            'defaultOrder' => [
                'created_at' => SORT_DESC,
            ]
        ]
        
    ]);

    $this->load($params);

    if (!$this->validate())
        return $dataProvider;

    $query->andFilterWhere([
        'geo_id' => $this->geo_id,
        'latitude' => $this->latitude,
        'longitude' => $this->longitude,
        'accuracy' => $this->accuracy,
        'speed' => $this->speed,
        'device_id' => $this->device_id,
        'betterlocation' => $this->betterlocation,
        'active' => $this->active,
        'mobiledate' => $this->mobildate,
        'sended' => $this->sended,
        'updated_at' => $this->updated_at,
        'created_at' => $this->created_at,
        'created_by' => $this->created_by,
    ]);

    return $dataProvider;
}

GeoDataSearch模型添加第二个函数:

/**
 * @param int $creator_id ID of the creator
 * @param mixed $params
 * @return ActiveDataProvider
 */
public function searchByCreator($creator_id, $params)
{
    // This will verify if the $params['GeoDataSearch'] index exists
    if ( isset( $params['GeoDataSearch'] ) ) {
        $params['GeoDataSearch']['created_by'] = $creator_id;
    } else {
        // Create the index if it doesn't exist
        $params['GeoDataSearch'] = ['created_by' => $creator_id];
    }

    return $this->search($params);
}

更新您的actionView

public function actionView($id)
{
    $title = "Ver Historial";
    $searchModel = new GeoDataSearch;
    // The $id param is already receiving the $_GET['id']
    $dataProvider = $searchModel->searchByCreator($id, Yii::$app->request->queryParams);

    return $this->render(
        'view',
        [
            'title' => $title,
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider
    ]);
}

不要在actionView 中设置用户验证,而是使用AccessControl


解释

DataProvider 用于方便的数据分页和排序 (View docs)。

查询过滤 DataProvider 操作的数据。

search 方法是一种约定,用于将查询过滤器附加到单个位置的 DataProvider 以便更好地重用。因此,您应该寻找一种可以在多个场景中重复使用的通用搜索方法。

在此示例中,GeoDataSearch-&gt;search() 方法用于通过传递所需的任何参数来搜索多个 GeoData 模型,因此您将向其传递一个数组,很可能是来自前端的数据。

如果您在前端使用 Yii2 ActiveForm 输入(设置了 GET 方法),则在 GeoDataSearch 字段上。例如:

<?= $form->field($searchModel, 'speed')->textInput(); ?>

这将允许通过speed 属性过滤结果。当用户提交此表单时,您的后端将从Yii::$app-&gt;request-&gt;queryParams 获取以下内容:

[
    'GeoDataSearch' => [
        'speed' => '10.00'
    ]
]

您应该在 search 方法上使用它,它将按速度过滤所有 GeoData。

重要的是要注意speed 属性将是GeoDataSearch 上的索引。这就是 Yii2 使用其核心表单方法构建参数并影响模型 load() 方法的方式,以及在 searchByCreator 上的实现似乎有些复杂的原因。

回到你的情况,

您需要按创建者过滤。由于这需要始终附加到搜索查询参数,我建议您创建一个新方法 (searchByCreator),它使用已经存在的 search 方法,强制 created_by 属性,同时保留其他过滤器活着。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-17
    • 2011-02-07
    相关资源
    最近更新 更多