Yii2 get data with join table - php

I want to get all data from main table with left join relation with its own conditions
MainTableSearch.php
class MainTableSearch extends MainTable
{
public $table_two;
public $table_three
public function search($params)
{
$query = MainTable::find();
$query->joinWith(['table_two']);
$query->joinWith(['table_three']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
]);
....
MainTable.php
class MainTable extends \yii\db\ActiveRecord
{
public static function tableName()
{
return 'main_table';
}
public function getTableTwo()
{
return $this->hasOne(TableTwo::className(), [main_id' => 'id'])->andWhere(['table_two.something' => 2]);
}
public function getTableThree()
{
return $this->hasOne(TableThree::className(), ['main_id' => 'id'])->andWhere(['table_three.something' => 2]);
}
I want to see all data from main table in grid view and if table_two.something or table_three.something doesn't meet requirement to return null in that field.
I also tried
return $this->hasOne(TableThree::className(), ['main_id' => 'id'])->andWhere(['table_three.something' => 2])->orWhere(['table_three.something' => NULL]);

[SOLVED]
$query->leftJoin('table_two','main_table.id = table_two.main_id
AND (table_two.something=1 OR table_two.something IS NULL)');

Related

Property [id] does not exist on the Eloquent builder instance in Laravel 8 and Livewire 2.7

My users can create multiple usercar's when selecting from a database of car's. I need to grab the selected car values, but when I dd the values, I get a Property [id] does not exist on the Eloquent builder instance. error. wire:model="car_id" is the select input value used in the code below.
AddUserCar.php
...
class AddUserCar extends Component
{
public $showAnotherModel = false;
// Steps
public $totalSteps = 8;
public $step = 1;
// User
public $super;
public $first_name;
public $last_name;
public $email;
public $status = 1;
public $role = 'Driver';
// Usercar
public $car_id;
public $calc_date;
public $year;
public $model;
// Form Function
public $car_year;
//public $cars;
//public $modelId;
...
public function moveAhead()
{
if($this->step == 1) {
$newCar = Car::where('id', '=', $this->car_id)->get();
dd($newCar->id); // This is where I get error
$this->usercarCreated = Usercar::create([
'year' => $newCar->start_year,
'model' => $newCar->model,
'car_id' => $this->car_id,
'user_id' => Auth::user()->id,
'tenant_id' => Auth::user()->tenant_id,
'calc_date' => now()->format('m-d-Y'),
]);
$this->resetErrorBag();
$this->resetValidation();
}
...
public function render()
{
return view('livewire.add-user-car',
['pageTitle' => 'Add Driver Car']);
}
}
Use ->get() to retrieving all rows from a table :
$cars = Car::where('id', '=', $this->car_id)->get();
foreach($cars as $car){
echo $car->id;
}
// ERROR, because $cars isn't a single row
dd($cars->id);
Use ->first() to retrieving a single row / column from a table.
$car = Car::where('id', '=', $this->car_id)->first();
// or
$car = Car::find($this->car_id);
// WORK
dd($car->id);
$newCar = Car::where('id', '=', $this->car_id)->get();
This statement does not find any data, so $newcar is empty, and an empty object has no ID

Laravel created event returning the wrong record

I'm currently using Laravel observers to implement events in my project, however, I ran into some problem where the created event returns a wrong record, for example, I create a record called Like that has post_id set to 2 and user_id set to 1, so the laravel created event should return this record right? except it returns a record where post_id is set to 0 and user_id set to 1.
my LikeObserver class:
class LikeObserver
{
/**
* Handle the like "created" event.
*
* #param \App\Like $like
* #return void
*/
public function created(Like $like)
{
dd($like);
$postId = $like->post_id;
Post::find($postId)->increment('likes_count');
}
}
as you can see whenever i dump the newly created record it returns this:
my LikeController class:
class LikeController extends Controller
{
public function insert(Request $request)
{
if(Like::where('user_id','1')->find($request->post_id))
{
return;
}
$like = Like::create(['post_id'=>$request->post_id,'user_id' => '1']);
}
public function remove(Request $request)
{
Like::where('user_id',auth()->user()->id)->findOrFail($request->post_id)->delete();
}
}
I pass post_id set to 2, however, Laravel returns the newly created record with post_id set to 0.
class LikeController extends Controller
{
public function insert(Request $request)
{
$like = Like::firstOrCreate([
'user_id' => '1',
'post_id' => $request->post_id,
]);
if(! $like->wasRecentlyCreated) {
return;
}
}
public function remove(Request $request)
{
Like::where([
'user_id' => auth()->user()->id,
'post_id' => $request->post_id,
])->first()->delete();
}
}
okay so apparently the fix was to use the creating event instead of the created event... this does return the correct record
public static function boot()
{
parent::boot();
static::creating(function ($like){
//returns the correct record.
dd($like);
});
}

Yii 2 Fields function in Active Record Models

I am working on REST API under Yii2, however I have an issue with what the model should return per different actions.
For example in listing actions I need to for example to return 4 attributes and for the details action I need to return 10 attributes from the same model.
What is the best or standard way in Yii2 to implement this.
Example:
/articles
return [id, title, image, date]
/articles/7
return [id, title, image, date, author, likes, last_review]
Thank you
for /article/7 :
public function actionView($id)
{
return User::findOne($id);
}
or
public function actionView($id)
{
return User::find()->select([id, title, image, date, author, likes,last_review])->one();
}
for /articles :
public function actionIndex()
{
return User::find()->select([id, title, image, date])->all();
}
Just write methods in your model.
class MyModel extends ActiveRecord
{
private static $fieldset_1 = [
'id', 'title', 'image', 'date'
];
private static $fieldset_2 = [
'id', 'title', 'image', 'date', 'author', 'likes', 'last_review'
];
public static function get(int $id)
{
if($id > 0) {
return static::find()
->select(self::$fieldset_1)
->where(['id' => $id])
->asArray()
->one();
}
}
public static function getList()
{
return static::find()
->select(self::$fieldset_2)
->asArray()
->all();
}
}
In Controller
class MyController extends Controller{
public function actionListing(){
return $this->asJson(MyModel::getList());
}
public function actionDetails($id){
return $this->asJson(MyModel::get((int)$id));
}
}

yii active record via issue

Please help;
i have models:
class Service extends \yii\db\ActiveRecord{
public function getCategory()
{
return $this->hasOne(ServiceCategory::className(), ['id' => 'service_category_id']);
}
}
class ServiceOffer extends \yii\db\ActiveRecord
{
public function getService()
{
return $this->hasOne(Service::className(), ['id' => 'service_id']);
}
public function getCategory()
{
return $this->hasOne(ServiceCategory::className(), ['id' => 'service_category_id'])->via('service');
}
public function getProperties()
{
return $this->hasMany(ServiceProperty::className(), ['service_category_id' => 'id'])
->via('category');
}
}
When i do query:
$query = ServiceOffer::find()->with(['properties'])->all();
or:
$query = ServiceOffer::find()->joinWith(['properties'])->all();
i have error:
Getting unknown property: app\models\ServiceOffer::service_category_id
but if i do this for see query sql:
$query = ServiceOffer::find()->joinWith(['properties']);
echo $query->prepare(\Yii::$app->db->queryBuilder)->createCommand()->rawSql;
sql:
SELECT "service_offer".* FROM "service_offer"
LEFT JOIN "service" ON "service_offer"."service_id" = "service"."id"
LEFT JOIN "service_category" ON "service"."service_category_id" = "service_category"."id"
LEFT JOIN "service_property" ON "service_category"."id" = "service_property"."service_category_id"
query without problem and execute
Why ActiveRecord find service_category_id property in ServiceOffer model?

How to avoid ambiguous field while reusing query shorthand in Yii2?

I have table like below.
CREATE TABLE A (
id INT,
relationId INT,
status INT
)
CREATE TABLE B (
id INT,
status INT
)
The class file is like below
class A extends \yii\db\ActiveRecord {
public function getB() {
return $this->hasOne(B::class, ['id' => 'relationId']);
}
public function find() {
return new AQuery(__CLASS__);
}
}
class AQuery extends \yii\db\Query {
public function isActive() {
return $this->andWhere(['status' => 1]);
}
public function isNotActive() {
return $this->andWhere(['status' => 0]);
}
}
class B extends \yii\db\ActiveRecord {
public function find() {
return new BQuery(__CLASS__);
}
}
class BQuery extends \yii\db\Query {
public function isActive() {
return $this->andWhere(['status' => 1]);
}
public function isNotActive() {
return $this->andWhere(['status' => 0]);
}
}
I'm doing something like this
$model = A::find()
->joinWith([
'b' => function(BQuery $query) {
$query->isNotActive();
}
])
->isActive()
->one();
This will produce error
Column 'status' in where clause is ambiguous"
The only way I know is to manually add alias to $query->from and rewrite the $query->andWhere. But is there any easier way to reuse the query shorthand?
Use ActiveRecord::tableName() instead of aliasing (which doesn't seem to be an active record feature in Yii2). The tableName() can be accessed through the modelClass property of \yii\db\ActiveQuery.
public function isActive() {
$modelClass = $this->modelClass;
return $this->andWhere([$modelClass::tableName().'.status' => 1]);
}
You can enhance your isActive() method to accept aliases with an optionnal parameter. You can try something like this:
class AQuery extends \yii\db\Query {
protected function getAlias($alias = null) {
return $alias !== null ? $alias : A::tableName();
}
public function isActive($alias = null) {
$alias = $this->getAlias($alias);
return $this->andWhere(["{$alias}.status" => 1]);
}
public function isNotActive($alias = null) {
$alias = $this->getAlias($alias);
return $this->andWhere(["{$alias}.status" => 0]);
}
}

Categories