Corbee
Corbee

Reputation: 1009

Is there a proper way to cross join using yii2?

I'm doing a query for activedataprovider, which I'm going to use for the purpose of search. I need to use cross join. I used joinWith, but it complains about warehouse model not having relation with product. it was calling product. Are there any work around here so that it won't trigger the relation, since it's a cross join?

Other notes: Certain attributes like product_id, product.category, etc doesn't exist on the original model which is based on warehouse. Will it work on the fly if I just add public property/attribute variables or do I need a work around?

public function search($params)
    {               
        $query = Warehouse::find()->joinWith('product')
                ->select(['product_id' => 'product.id','warehouse.warehouse', 'product.category', 'product.product', 'min_stock' => 'coalesce(critical.min_stock, -1)'])
                ->leftJoin('critical', 'critical.product_id = product.id AND critical.warehouse_id = warehouse.id')
                ->where(['warehouse.id' => $this->_id]);

        $this->load($params);

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);        

        if (!$this->validate()) {
            // uncomment the following line if you do not want to return any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }

        $query->andFilterWhere(['category' => $this->category]);
        $query->andFilterWhere(['like', 'product', $this->product]);        

        return $dataProvider;
    }

Upvotes: 1

Views: 1155

Answers (3)

->joinWith('product', true,'cross join')

public function getProduct()
{
    return $this->hasOne(Product::className(), []);
}

Upvotes: -1

Yasin Patel
Yasin Patel

Reputation: 5731

Get Your Query record as array so you don't require to define relationship

public function search($params)
    {               
        $query = Warehouse::find()->joinWith('product')
                ->select(['product_id' => 'product.id','warehouse.warehouse', 'product.category', 'product.product', 'min_stock' => 'coalesce(critical.min_stock, -1)'])
                ->leftJoin('critical', 'critical.product_id = product.id AND critical.warehouse_id = warehouse.id')
                ->where(['warehouse.id' => $this->_id]);

        $query = Warehouse::find()
                ->select('product.id as id,warehouse.warehouse as warehouse, product.category as category, product.product as product, coalesce(critical.min_stock, -1) as min_stock ')
                ->leftJoin('product', 'warehouse.product_id = product.id')
                ->leftJoin('critical', 'critical.product_id = product.id')
                ->where(['warehouse.id' => $this->_id]);
                ->andWhere('critical.warehouse_id = warehouse.id')
                ->asArray();

        $this->load($params);

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);        

        if (!$this->validate()) {
            // uncomment the following line if you do not want to return any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }

        $query->andFilterWhere(['category' => $this->category]);
        $query->andFilterWhere(['like', 'product', $this->product]);        

        return $dataProvider;
    }

Now you will get record as Array not as object.

Second way is, Define relation between Warehouse and Product in model using hasOne() or hasMany()

Upvotes: 0

ScaisEdge
ScaisEdge

Reputation: 133380

For all the query that are difficult (or impossibile) to build using yii2 activeRecord or activeQuery functionalites you can use findBySql

$sql = "select 
          product.id as id
          , warehouse.warehouse as warehouse 
          , product.category as category
          , product.product as product
          , coalesce(critical.min_stock, -1) as min_stock 
          from Warehouse 
          cross join product  
          left join critical on ritical.product_id = product.id AND critical.warehouse_id = warehouse.id
          where warehouse.id' = " . $this->_id  

 $model =  Warehouse::findBySql($sql );

Upvotes: 1

Related Questions