Extracting relational data in laravel - php

I'm trying to build a small application in laravel 5.4 where I'm having a contacts table, companies table, interactions table and users table each with their respective models. An Interaction is being created by the User where there are client_contact, contact, user participating. Each client_contact and contact shares the same model and belongs to a company which have type in their column for example Investor, Research, Corporate etc. Now I'm trying to generate a report where interaction done by a user with Investors. First of all let me show you my models:
User Model:
class User extends Authenticatable
{
use HasApiTokens, Notifiable, SoftDeletes;
public function interactions()
{
return $this->hasMany('App\Interaction');
}
public function clients()
{
//Each user has been assigned a particular client
return $this->belongsToMany('App\Company', 'company_user', 'user_id', 'company_id');
}
}
Contacts Model:
class Contact extends Model
{
use SoftDeletes, DataViewer;
public function company()
{
return $this
->belongsToMany('App\Company', 'company_contact','contact_id', 'company_id')->withTimestamps();
}
public function interactions()
{
return $this->belongsToMany('App\Interaction', 'contact_interaction','contact_id', 'interaction_id');
}
public function clientInteractions()
{
return $this->belongsToMany('App\Interaction', 'contact_client_interaction','contact_id', 'interaction_id');
}
}
Company Model:
class Company extends Model
{
use SoftDeletes, DataViewer;
public function contacts()
{
return $this->belongsToMany('App\Contact', 'company_contact', 'company_id','contact_id');
}
public function users()
{
return $this->belongsToMany('App\User', 'company_user', 'company_id', 'user_id')->withTimestamps();
}
}
Interaction Model:
class Interaction extends Model
{
use SoftDeletes;
public function stellarParticipants()
{
return $this->belongsToMany('App\User')->withTimestamps();
}
public function clientsAssociation()
{
return $this->belongsToMany('App\Contact', 'contact_client_interaction', 'interaction_id', 'contact_id')->withPivot('company_id')->withTimestamps();
}
public function contactsAssociation()
{
return $this->belongsToMany('App\Contact', 'contact_interaction', 'interaction_id', 'contact_id')->withPivot('company_id')->withTimestamps();
}
public function user()
{
return $this->belongsTo('App\User');
}
}
Now in my ReportController: I'm doing something like this:
public function getAnalystInvestor(Request $request)
{
$user = User::find($request->id);
$interactions = Interaction::whereHas('contactsAssociation', function ($query3) {
$query3->whereHas('company', function ($query4) {
$query4->where('type', 'like', '%'.'Investor'.'%');
});
})->whereHas('user', function ($query1) use($user) {
$query1->where('name', '=', $user->name);
})->orWhereHas('stellarParticipants', function ($query2) use($user) {
$query2->where('name', '=', $user->name);
})
->orderBy('created_at', 'desc')
->take(50)
->with(['contactsAssociation', 'clientsAssociation', 'stellarParticipants'])
->get();
return response()->json(['interactions' => $interactions], 200);
}
But I'm unable to get the desired results, still some of the data are displaying which is not investors. I also tried:
$interactions = Interaction::whereHas('user', function ($query1) use($user) {
$query1->where('name', '=', $user->name);
})->orWhereHas('stellarParticipants', function ($query2) use($user) {
$query2->where('name', '=', $user->name);
})->whereHas('contactsAssociation', function ($query3) {
$query3->whereHas('company', function ($query4) {
$query4->where('type', 'like', '%'.'Investor'.'%');
});
})
Where user filters are assigned first but its not displaying as desired. Help me out with this.

You should be able to chain your query, similar to this:
$cfs = \App\Service::with('items', 'required_services', 'supported_services')
->where(function ($query) {
$query->where('stm', 11)
->orWhere('stm', 17)
->orWhere('stm', 31);
})
->where('lifecycle_id', '!=', 12)
->where('type', 'Customer Facing')
->orderBy('service_full_name')
->get();
I don't really understand the report you are developing, but hopefully this helps you.

Related

How can I make this method in Eloquent ORM?

Hlw! I am a new comer in php , laravel can you explain that How Can I Creat this is isAuthorized()method with laravel Elouquet by replacing this query builder
class User extends Authenticatable
{
public function isAuthorized($object, $operation)
{
return Db::table('role_permissions')
->where('object', $object)
->where('operation', $operation)
->join('user_roles', 'user_roles.role_id', '=', 'role_permissions.role_id')
->where('user_roles.user_id', $this->id)
->exists();
}
}
Create your Models like so.
public class RolePermission {
public function UserRoles() {
return $this->hasMany(UserRole::class, 'role_id', 'role_id');
}
}
public class UserRole {
}
WhereHas can query relationships and is the cornerstone to replacing joins.
RolePermission::where('object', $object)
->where('operation', $operation)
->whereHas('UserRoles', function ($query) {
$query->where('user_roles.user_id', $this->id)
})
->exists();

Search bar with two inputs and a search button Laravel5

I'm working on a jobber search project online using Laravel 5.5.
In my project I want to make a search to find jobbers who live in a certain area and who perform a certain service, or where only one criteria matches.
I use three models: User, Area and Service.
Here is my search bar: I want to use this search bar to do it
This is the User model:
class User extends Authenticatable
{
use Notifiable, EntrustUserTrait;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'surname', 'email', 'phone',
'password','type',];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [ 'password', 'remember_token',];
public function area(): BelongsTo
{
return $this->belongsTo(Area::class);
}
public function service(): BelongsTo
{
return $this->belongsTo(Service::class);
}
}
This is the Service model:
class Service extends Model
{
protected $fillable = ['category_id','name','description'];
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function users(): BelongsTo
{
return $this->belongsToMany(User::class, 'service_id');
}
public function jobs()
{
return $this->hasMany('App\Job');
}
}
And this is the Area model:
class Area extends Model
{
protected $fillable = ['town_id', 'name', 'description'];
public function town(): BelongsTo
{
return $this->belongsTo(Town::class);
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class, 'area_id');
}
}
Here is the controller code that did not work for me so far:
public function search(Request $request) {
$service = $request->get('service');
$area = Input::get('area');
if (!(empty($service)) && !(empty($area))) {
$results = User::with(['area', 'service'])
->where('area_id', 'like', "%$area%")
->whereHas('service', function ($query) use ($service) {
$query->where('category_id', $service);
})
->paginate(10);
return view('Search.search', compact('results'));
} elseif (!(empty($service)) && empty($area)) {
$results = User::with(['area', 'service'])
->whereHas('service', function ($query) use ($service) {
$query->where('category_id', $service);
})
->paginate(10);
return view('Search.search', compact('results'));
} elseif (empty($service) && !empty($area)) {
$results = User::with(['area', 'service'])
->where('area_id', 'like', "%$area%")
->paginate(10);
return view('Search.search', compact('results'));
}
}
I would advice you to build your query dynamically depending on the available input. This reduces your code and makes sure you will not have to add new code in multiple places should you extend your search in future.
public function search(Request $request)
{
$query = User::with(['area', 'service']);
if ($request->filled('service')) {
$query = $query->whereHas('service', function ($q) use ($request) {
$q->where('category_id', $request->get('service'));
});
}
if ($request->filled('area')) {
$query = $query->where('area_id', $request->get('area'));
}
$results = $query->paginate(10);
return view('Search.search', compact('results'));
}
As long as you don't call get(), paginate() or find() on the $query, it will be a Illuminate\Database\Eloquent\Builder object. This means you can add additional conditions on the query which will all be included in the actual SQL query and are not performed in-memory (which you clearly don't want).
The method $request->filled('service') will check both of the following two conditions:
$request->has('service')
!empty($request->get('service'))
If you want to be able to search Areas by name, you might need to change the if($request->filled('area')) { ... } part to the following:
if ($request->filled('area')) {
$query = $query->whereHas('area', function ($q) use ($request) {
$q->where('name', 'like', '%'.$request->get('area').'%');
});
}

Laravel "nested" with()

I have 3 models: Article, Comment, Reaction.
Each article has many comments, and each comment has many reactions:
App\Article:
class Article extends Model
{
public function comments() {
return $this->hasMany('App\Comment');
}
}
App\Comment:
class Comment extends Model
{
public function article() {
return $this->belongsTo('App\Article');
}
public function reactions() {
return $this->hasMany('App\Reactions');
}
}
App\Reaction:
class Reaction extends Model
{
public function comment() {
return $this->belongsTo('App\Comment');
}
}
In my ArticleController#index I want to fetch comments and their reactions:
ArticleController:
public function index()
{
$articles = Article::with('comments')
->select('articles.*')
->leftjoin('comments', 'comments.article_id', '=', 'articles.id')
->get();
return view('wiki')->withArticles($articles);
}
I can loop through the comments ($article->comments), however I'm not sure how to do a with('reactions') for the comments? i.e.,
#foreach($article->comments as $comment)
#foreach($comment->reactions)
// something like this...
#endforeach
#endforeach
you can do Nested Eager Loading
$article = Article::with('comments.reactions')
->leftjoin('comments', 'comments.article_id', '=', 'articles.id')
->select('articles.*')
->get();
You can also do this way
ArticleController:
public function index()
{
$articles = Article::with('comments')
->select('articles.*')
->get();
return view('wiki')->withArticles($articles);
}
App\Article:
class Article extends Model
{
public function comments() {
return $this->hasMany('App\Comment')->with('reactions');
}
}
App\Comment:
class Comment extends Model
{
public function article() {
return $this->belongsTo('App\Article');
}
public function reactions() {
return $this->hasMany('App\Reactions');
}
}

Laravel Eloquent - list of parent from a collection

I can get the list of Likes that User 1 did on a Media from Store 1
$medias = User::find(1)->likes()->with('media')->whereHas('media', function($q) {
$q->where('store_id', '=', 1);
})->get();
But i need to retrieve the list of medias, so i tried
$medias = User::find(1)->likes()->with('media')->whereHas('media', function($q) {
$q->where('store_id', '=', 1);
})->get()->media;
But then i get
Undefined property: Illuminate\Database\Eloquent\Collection::$media
class User extends Model
{
public function likes()
{
return $this->hasMany('App\Like');
}
}
class Media extends Model
{
public function store()
{
return $this->belongsTo('App\Store');
}
public function likes()
{
return $this->hasMany('App\Like');
}
}
class Like extends Model
{
public function user()
{
return $this->belongsTo('App\User');
}
public function media()
{
return $this->belongsTo('App\Media');
}
}
This is because you get media separate for each like. You should use:
$likes = User::find(1)->likes()->with('media')->whereHas('media', function($q) {
$q->where('store_id', '=', 1);
})->get();
foreach ($likes as $like) {
$media = $like->media;
// now you can do something with your media
}
EDIT
If you want to get only media, you should add to your User model the following relationship:
public function medias()
{
return $this->hasManyThrough('App\Media','App\Like');
}
Now to get your media, you should do :
$medias = User::find(1)->medias()->where('store_id', '=', 1)->get();
Made it work with
$store->medias()->whereHas('likes', function($q) use($user) {
return $q->where('user_id', '=', $user->id);
});

Laravel 4.1 eager loading

I'm having trouble on the eager loading.
Let's say I have models of Members, TrainingCategory, TrainingCategoryResult and Registration
Member Model:
public function registration() {
return $this->hasMany('Registration', 'member_id');
}
public function trainingResults(){
return $this->hasMany('trainingResult', 'member_id');
}
public function trainingCategoryResults() {
return $this->hasMany('TrainingCategoryResult', 'member_id');
}
TrainingCategory Model:
public function trainings() {
return $this->hasMany('Training', 'id');
}
public function trainingCategoryResults() {
return $this->hasMany('trainingCategoryResult', 'category_id');
}
TraningCategoryResult Model:
public function category() {
return $this->belongsTo('TrainingCategory', 'id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
Registration Model:
public function course() {
return $this->belongsTo('Course', 'course_id');
}
public function member() {
return $this->belongsTo('Member', 'id');
}
I am trying to eager load all the registration info and its related info including the TraningCategoryResult info but I not sure how to get that TraningCategoryResult which required two foreign keys (category_id and member_id), is there any way to do that?
Here is my code atm:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
});
$members= $members
->with('registration.course',
'registration.course.traningCategories',
->get(['member.id']);
Thank you.
This will not work Member::with('categoryResult')->with('registration')->get()
You can make a new relation in Member Model
public function categoryResult()
{
return $this->belongsTo('Category')->with('Registration');
}
//and then call
Member::with('categoryResult')->get();
You could use a few options to achieve that:
OPTION 1: create a variable relationship
Change your relation in the Member model
public function trainingCategoryResults($category_id = null) {
if(empty($category_id))
return $this->hasMany('TrainingCategoryResult', 'member_id');
else
return $this->hasMany('TrainingCategoryResult', 'member_id')
->where('category_id', $category_id);
}
The code above might have limitations and it doesn't take advantage of many laravel features, but it will work.
OPTION 2: Access from relationship
You can keep everything as is, and load as follow:
$members= Member::where(function($query) use ($id, $site) {
$query
->where('id', '=', $id)
->where('site', '=', $site);
})
->where('id', $member_id) // set the id of the memeber
->with(array(
'traningCategoryResults' => function($q)use($category_id){
$q->where('category_id', $category_id); // This makes sure you get only desired results
}
))
In this way you will have only what you need, assuming you know the $category_id

Categories