Yii 2 Fields function in Active Record Models - php

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));
}
}

Related

Getting parent parents data in a pivot table in Laravel

What Eloquent model would you use to:
Get all Pages that its Company brand color is red/slug.
Where brand color is a pivot table and stored as an ID on the Company table.
So you have brand_colors id, name, slug, hex
Have company where it has brand_color_id
And Pages that has just the company ID.
I want to grab all pages whose company brand color is X.
How would you go about it?
This table has the company_id
class WebsitePage extends Model
{
use HasFactory;
public function scopeFilter($query, array $filters) {
// Get all pages with a color that the company has
$query->when($filters['color'] ?? false, fn($query, $color) =>
$query->whereHas('color', fn ($query) =>
$query->where('name', $color)
)
);
}
// Where URL slug 'red' color, associated with company brand_color_id matches brandColor slug
// or just simpley call $company->color() ?
public function color()
{
// return $this->with(Company::class, 'brand_color_id');
// return $this->belongsTo(Company::class, 'company_id');
// dd($this->with())
// return Company::with('color.red');
}
This table has brand_color_id, etc.
class Company extends Model
{
use HasFactory;
protected $fillable = [
'user_id',
'name',
'slug',
'description'
];
public function pages() {
return $this->hasMany(WebsitePage::class);
}
public function color() {
return $this->belongsTo(BrandColor::class, 'brand_color_id');
}
}
This table has: id | name | slug | hex
class BrandColor extends Model
{
use HasFactory;
}
So knowing this, how would you get all pages whose company color is the one filtered?
In terms of the page controller, this is what I'm doing:
class PageController extends Controller
{
public function index(WebsitePage $websitePage)
{
// return view('web.inspiration.pages.index', [
// 'pages' => WebsitePage::latest()->paginate(30)
// ]);
return view('web.inspiration.pages.index', [
'pages' => WebsitePage::latest()->filter(
request(['color'])
)->paginate(30)->withQueryString()
]);
}
}
Your model layout isn't described that well, but I think you just want to define a HasOneThrough relationship to join WebsitePage to BrandColor:
class WebsitePage extends Model
{
public function company(): BelongsTo
{
return $this->belongsTo(Company::class);
}
public function color(): HasOneThrough
{
return $this->hasOneThrough(BrandColor::class, Company::class);
}
}
class Company extends Model
{
public function color(): BelongsTo
{
return $this->belongsTo(BrandColor::class);
}
}
class BrandColor extends Model
{
public function company(): HasOne
{
return $this->hasOne(Company::class);
}
}
Then in your controller, just use a condition on your whereHas() and with() calls:
class PageController extends Controller
{
public function index(): View
{
$color = request("color");
$pages = WebsitePage
::whereHas("color", fn ($q) => $q->where("color", $color))
->with(["color" => fn ($q) => $q->where("color", $color)])
->paginate(30)
->withQueryString();
return view("web.inspiration.pages.index", compact($pages));

Laravel Resource - Get data from relation

I'm trying to use Laravel's resources & Collection to build a small API.
I would like to recover all the posts of the categories
My relation on my model :
/*
|--------------------------------------------------------------------------
| RELATIONS
|--------------------------------------------------------------------------
*/
public function posts()
{
return $this->belongsToMany(Post::class, 'post_category');
}
Category controller :
public function index()
{
$categories = Category::all();
return (new CategoryCollection(CategoryResource::collection($categories)));
}
My categoryResource :
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'slug' => $this->slug
];
}
My CategoryCollection
public function toArray($request)
{
return [
'data' => $this->collection,
'posts' => PostResource::collection($this->whenLoaded('posts')),
];
}
I try to recover the posts of a category first. When I make the following command I get an error: Method ... relationLoaded does not exist
'posts' => PostResource::collection($this->whenLoaded('posts'))
What did I not understand?
I also created two PostCollection and PostResource files (basic, I did not modify them)
public function toArray($request)
{
return parent::toArray($request);
}
public function index()
{
$categories = Category::all();
return (CategoryResource::collection($categories));
}
this is might help , try this
and if you want to use posts resource
you need make posts resources
and inside the CategoryResource
'posts'=>PostResource::collection($this->posts)
cannot use Resource in Collection.
Use this
public function index()
{
$categories = Category::all();
return (new CategoryCollection($categories));
}

Laravel Eloquent method updateOrCreate exceeds execution time when updating

So the problem is that when I try to update my entity it finds it updates it but gets stuck in a loop probably and doesn't exit. When I check the database, even before the 60 seconds of execution time that I have expires, the values that I have changed are updated.
If i constantly refresh (and here is where it gets crazy) the updated at values for other lectures starts to change every second while it executes this loop.
When creating (not finding the id on the condition It creates it without a problem)
I have Lectures which looks like this:
class Lecture extends Model
{
use Searchable;
use SoftDeletes;
protected $primaryKey = 'id';
protected $touches = ['themes', 'educationTypes', 'subjects'];
protected $fillable= [
'name', 'description', 'user_id', 'field_id', 'approved'
];
public static function boot()
{
parent::boot();
static::saved(function ($model) {
$model->themes->filter(function ($item) {
return $item->shouldBeSearchable();
})->searchable();
});
}
public function user(){
return $this->belongsTo('App\User')->with('companies');
}
public function geographies(){
return $this->belongsToMany('App\Geography');
}
public function educationTypes(){
return $this->belongsToMany('App\EducationType', 'lecture_education_type')->withTimestamps();;
}
public function themes(){
return $this->belongsToMany('App\Theme','lecture_theme', 'lecture_id', 'theme_id')->withTimestamps();;
}
public function subjects(){
return $this->belongsToMany('App\Subject', 'lecture_subject')->withTimestamps();;
}
public function cases(){
return $this->belongsToMany(
'App\CompanyCase' ,
'case_company_lecture',
'lecture_id',
'case_id',
'id',
'id')->withTimestamps();
}
public function companies(){
return $this->belongsToMany(
'App\Company' ,
'case_company_lecture',
'lecture_id',
'company_id',
'id',
'id'
);
}
public function field(){
return $this->belongsTo('App\Field');
}
public function toSearchableArray()
{
$this->themes;
$this->user;
$this->educationTypes;
$this->subjects;
$this->geography;
return $this->toArray();
}
}
This is the controller:
public function storeLecture(Request $request) {
$lecture_id = $request->get('lecture_id');
// It gets stuck between the comments
$lecture = Lecture::updateOrCreate(['id' => $lecture_id],
[
'name'=> request('name'),
'description'=> request('description'),
'user_id'=> request('user_id')]
);
// and doesn't update the themes, edu types subjects and etc.
$company_id = $request->get('company_id');
$company = Company::find(request('company_id'));
$lecture->companies()->sync([$company->id]);
$eduTypes= $request->get('education_types');
$themes= $request->get('themes');
$subjects = $request->get('subjects');
$geographies = $request->get('geographies');
$lecture->themes()->sync($themes);
$lecture->educationTypes()->sync($eduTypes);
$lecture->subjects()->sync($subjects);
$lecture->geographies()->sync($geographies);
$n1 = new Notification();
$n1->send(request('user_id'), 1, 'new_lecture', $lecture->id);
$user = User::where('id', $request->id)->first();
$user_with_companies = $user->load('companies');
$slug = $user_with_companies->companies->first()->slug;
return response(['success' => true]);
}
This is the frontend method sending the request (in between I have a middleware checking if the user is admin (possible to create a lecture) based on the this.selectedExpert.id, which doesn't interfere).
createUpdateLecture() {
const url = `${window.location.origin}/lecture/create/${
this.selectedExpert.id
}`;
this.$http
.post(url, {
education_types: this.allEducationTypes
.filter(el => el.checked)
.map(a => a.id),
themes: this.allThemes.filter(el => el.checked).map(a => a.id),
geographies: this.allGeographies
.filter(el => el.checked)
.map(a => a.id),
subjects: this.allSubjects.filter(el => el.checked).map(a => a.id),
name: this.lecture.name,
description: this.lecture.description,
user_id: this.selectedExpert.id,
company_id: this.company.id,
lecture_id: this.lecture.id
})
.then(res => {
console.log(res);
this.$parent.showLectureCreateModal = false;
// window.location.reload();
});
}
As I can see what is happening I probably use the method really badly but I just want to understand it better for further usage.
After a few days of researching and testing it turns out that it is not the updateOrCreate method causing the problem because I tried with two different functions for creating and updating and the update function was still having the same problem.
The problem is created from Algolia which is used for searching based on different fields in the platform. Fx. in Themes
class Theme extends Model
{
use SoftDeletes;
use Searchable;
protected $touches = ['lectures'];
public function lectures(){
return $this->belongsToMany('App\Lecture');
}
public function toSearchableArray()
{
$this->lectures;
return $this->toArray();
}
}
Removing the searchable from the models did the trick!

Display table data without user auth

I'm studying event message board. I can display table data by every Users own post. however I would like to display All post too. I wrote this as $tasksall but it didn't work. Could someone teach me what is wrong?
AController.php
public function index()
{
$tasks = Auth::user()
->tasks()
->orderBy('is_complete')
->orderByDesc('created_at')
->paginate(5);
$tasksall =
->tasks()
->orderBy('is_complete')
->orderByDesc('created_at')
->paginate(5);
return view('tasks', [
'tasks' => $tasks, 'tasksall' => $tasksall
]);
}
Task.php (model)
class Task extends Model
{
protected $casts = [
'is_complete' => 'boolean',
];
protected $fillable = [
'title',
'is_complete',
];
public function user()
{
return $this->belongsTo(User::class);
}
}
AController.php I add this code
public function person()
{
return $this->belongsTo('App\Models\Task');
}
public function getData()
{
return $this->id . ':'/ $this->person->name.')';
}
index.blade.php I add this code
{{ $task2->getData() }}
You can just write a query to get all the task using eloquent to get all the tasks.
$tasksall = Task::all();
Have a look at this link.
Also for you case I think the problem is you are getting task from the User model so you $task will contain only task related to that particular user as you have a belongsTo relation of task with user.
For Your case to get name of User from task.
//Task model
class Task {
public function user()
{
return $this->belongsTo(User::class, 'user_id');
}
}
Then you can query like this in your controller.
$task = Task::find($id);
$name = $task->user->name;

One to Many Relationship - Laravel & Mysql

In my application, Users can have many products. Now, i am trying to display the users phone number for a every displayed products.
In my products table, there is a column user_id for the respective users.
This is how my model looks like
User Model
public function products()
{
return $this->belongsTo('Models\Database\User','user_id');
}
Product Model
class Product extends BaseModel
{
protected $fillable = ['user_id','type', 'name', 'slug', 'sku', 'description',
'status', 'in_stock', 'track_stock', 'qty', 'is_taxable', 'page_title', 'page_description'];
// protected $guarded = ['id'];
public static function getCollection()
{
$model = new static;
$products = $model->all();
$productCollection = new ProductCollection();
$productCollection->setCollection($products);
return $productCollection;
}
public function users()
{
return $this->hasMany('\Models\Database\Product');
//->withTimestamps();
}
public function categories()
{
return $this->belongsToMany(Category::class);
}
public function reviews()
{
return $this->hasMany(Review::class);
}
public function prices()
{
return $this->hasMany(ProductPrice::class);
}
public function orders()
{
return $this->hasMany(Order::class);
}
public function users()
{
return $this->hasMany('Models\Database\Product');
}
And in my view, this is how i try to get the respective user's phone number
<p>{{$product->users->phone}}</p>
But i get an error like
SQLSTATE[42S22]: Column not found: 1054 Unknown column
'products.product_id' in 'where clause' (SQL: select * from products
where products.product_id = 1 and products.product_id is not
null)
You should do:
User Model
public function products()
{
return $this->hasMany('Models\Database\Product');
}
Product Model
public function user()
{
return $this->belongsTo('Models\Database\User');
}
In your blade:
{{ $product->user->phone }}
You have got your relationship models inverted,
change them:
In your User model:
public function products()
{
return $this->hasMany('Models\Database\Product');
}
In your Product model:
public function user()
{
return $this->belongsTo('Models\Database\User','user_id');
}
And then you could access the properties like:
<p>{{$product->user->phone}}</p>
Link to the Docs

Categories