Export Relationship data using Laravel Excel - laravel

I'm using Laravel Excel to export data. I want to get all the reminders attached to a vet, which are accessed over a hasManyThrough relationship.
I have tried the following code
RemindersExport.php
public function collection()
{
$vets = Vet::where('is_active', 1)->get();
foreach($vets as $vet){
$reminders = $vet->reminders();
}
return $reminders;
}
Controller
public function reminders()
{
return Excel::download(new RemindersExport, 'reminders30days.xlsx');
}
I get the following message...
Method Illuminate\Database\Query\Builder::all does not exist.

The problem is that you're using the collection method but you should use the query method and laravel-excel excecutes the query for you so you don't have to use the get method at the end of your query, first you sould use the FromQuery concern, after that you should replace your collection method with the query method, write your query and DON'T add the get method at the end of your query
use Maatwebsite\Excel\Concerns\FromQuery;
class VetExport implements FromQuery{
public function query()
{
$vets = Vet::where('is_active', 1);
foreach($vets as $vet){
$reminders = $vet->reminders();
}
return $reminders;
}
}
I hope this helps

Related

How can add additional Attribute in my JSON response with dynamic value in laravel

In my app i have a Posts and a Reacts table both are connected with relationship.
In App user can react to a post(like or dislike) and for retrieve this i'm using this function :
public function feed()
{
$posts=Post::with('user')
->with('reacts')
->withCount('comments')
->orderBy('created_at', 'DESC')
->get();
return response()->json(["posts" => $posts]);
}
the response is:
i want to add one more field in Posts Object for isUserLiked and if the current authenticated user liked the post then value will be true or false for him something like this:
i can add a additional field but how can i set the value dynamically for that
this is what i am doing in my Post Model:
protected $appends = ['isUserLiked'];
public function getIsUserLikedAttribute($id)
{
$react=React::where('user_id',auth()->user()->id)->where('post_id',$id)->exists();
return $react;
}
this is returning false because i don't know any way to pass the arguments(Post id).
is there any better way i can get the desired response? Thanks!
public function getIsUserLikedAttribute($id)
{
return React::where('user_id',auth()->user()->id)->where('post_id',$this->id)->exists();
}
In your user model:
public function reacts(){
return $this->hasMany(React::class);
}
public function scopeReactOnPost($query, $post_id){
return $this->reacts()->where(function($query) use ($post_id){
$query->where('post_id',$post_id);
});
}
and in your controller:
$user->reactOnPost($post_id)->first();
or
$user->reactOnPost($post_id)->get()->count();
Will let you know if user had any reaction on the specified post.
and for adding this to your json output you can artisan make a resource for your post model. Laravel Resources

Relationship doesn't load data one to many Laravel 5.6

I declared relationship between two table.. one to many... but when I tried to load data the declared relationship is not viewed in the view console..
I have this in GL
public function parent_gl_sle(){
return $this->belongsTo('App\Sle_type','GLControlSLE_CODE','SLE_TypeCode');
}
then this is my SL
public function child_gl_sle(){
return $this->hasMany('App\Glcontrol','GLControlSLE_CODE','SLE_TypeCode');
}
Then, this is my controller.
$gl = Glcontrol::where('GLControlBR_CODE',$brcode)
->with('parent_glcontrol_br')
->with('parent_gl_sle')
->with('parent_cts')
->with('parent_coa')
->get();
But in my console parent_gl_sle is not included in the console.
enter image description here
What did I missed?
Try something like this
$gl = Glcontrol::with(['parent_glcontrol_br','parent_gl_sle','parent_cts','parent_coa'])->where('GLControlBR_CODE',$brcode)->get();
class Glcontrol extends Model
{
public function parent_gl_sle(){
return $this->belongsTo('App\Sle_type','foreign_key_name');
}
public function child_gl_sle(){
return $this->hasMany('App\Glcontrol','foreign_key_name');
}
}
$data = Glcontrol::with(['parent_glcontrol_br','parent_gl_sle','parent_cts','parent_coa'])
->where('GLControlBR_CODE',$brcode)->get();
dd($data);

Laravel oneToMany accessor usage in eloquent and datatables

On my User model I have the following:
public function isOnline()
{
return $this->hasMany('App\Accounting', 'userid')->select('rtype')->latest('ts');
}
The accounting table has activity records and I'd like this to return the latest value for field 'rtype' for a userid when used.
In my controller I am doing the following:
$builder = App\User::query()
->select(...fields I want...)
->with('isOnline')
->ofType($realm);
return $datatables->eloquent($builder)
->addColumn('info', function ($user) {
return $user->isOnline;
}
})
However I don't get the value of 'rtype' for the users in the table and no errors.
It looks like you're not defining your relationship correctly. Your isOnline method creates a HasMany relation but runs the select method and then the latest method on it, which will end up returning a Builder object.
The correct approach is to only return the HasMany object from your method and it will be treated as a relation.
public function accounts()
{
return $this->hasMany('App\Accounting', 'userid');
}
Then if you want an isOnline helper method in your App\User class you can add one like this:
public function isOnline()
{
// This gives you a collection of \App\Accounting objects
$usersAccounts = $this->accounts;
// Do something with the user's accounts, e.g. grab the last "account"
$lastAccount = $usersAccounts->last();
if ($lastAccount) {
// If we found an account, return the rtype column
return $lastAccount->rtype;
}
// Return something else
return false;
}
Then in your controller you can eager load the relationship:
$users = User::with('accounts')->get(['field_one', 'field_two]);
Then you can do whatever you want with each App\User object, such as calling the isOnline method.
Edit
After some further digging, it seems to be the select on your relationship that is causing the problem. I did a similar thing in one of my own projects and found that no results were returned for my relation. Adding latest seemed to work alright though.
So you should remove the select part at very least in your relation definition. When you only want to retrieve certain fields when eager loading your relation you should be able to specify them when using with like this:
// Should bring back Accounting instances ONLY with rtype field present
User::with('accounts:rtype');
This is the case for Laravel 5.5 at least, I am not sure about previous versions. See here for more information, under the heading labelled Eager Loading Specific Columns
Thanks Jonathon
USER MODEL
public function accounting()
{
return $this->hasMany('App\Accounting', 'userid', 'userid');
}
public function isOnline()
{
$rtype = $this->accounting()
->latest('ts')
->limit(1)
->pluck('rtype')
->first();
if ($rtype == 'Alive') {
return true;
}
return false;
}
CONTROLLER
$builder = App\User::with('accounting:rtype')->ofType($filterRealm);
return $datatables->eloquent($builder)
->addColumn('info', function (App\User $user) {
/*
THIS HAS BEEN SUCCINCTLY TRIMMED TO BE AS RELEVANT AS POSSIBLE.
ARRAY IS USED AS OTHER VALUES ARE ADDED, JUST NOT SHOWN HERE
*/
$info[];
if ($user->isOnline()) {
$info[] = 'Online';
} else {
$info[] = 'Offline';
}
return implode(' ', $info);
})->make();

Search with Relationship - Laravel 5.3

Im making a search functionality where users can type in a name. This is the query im doing:
public function api(Request $request)
{
$query = request()->get('query');
$results = Listing::searchAndCache($query);
return $results;
}
Which hits this:
public static function searchAndCache($query)
{
return self::where('name','like','%'.$query.'%')->where('live',true)->paginate(15);
}
I also need to search 'location' along with this query, the problem is its in a diffrent table. The models name is Location. My question is how would I attach the model Location to this query?
So ideally, I would want to do this for the query:
public static function searchAndCache($query)
{
return self::where('name','like','%'.$query.'%')->where('region','like','%'.$query.'%')->where('live',true)->paginate(15);
}
For search you can use searchable trait. so you can do this :
Listing::where('live',true)->search($query)->paginate(15);
if there is a relation between Listing And Location, you can use Laravel realations to do something like this
Listing::where('live',true)
->search($query)
->location
->search($query2)
->paginate(15);

Nested Eager loading relationships in Laravel

I am creating a forum software using Laravel and I'm trying to access the most recent posts made within a specific topic using latestPost as defined in my model below
public function latestPost() {
return $this->hasOne('App\Post')->with('thread')->with('author')->latest();
}
Here is how the nested relationships are defined in App\Post.php
public function author()
{
return $this->belongsTo('App\User', 'author_id');
}
public function thread()
{
return $this->belongsTo('App\Thread', 'thread_id');
}
public function topic() {
return $this->belongsTo('App\Topic');
}
I have been able to access posts of threads, authors etc no problem, and when I have {{ $topic->latestPost }} in my views, it will list the object including relationships successfully. But as soon as I try to display a specific part such as {{ $topic->latestPost->author->username }} I am getting the following error: Trying to get property of non-object
In this specific view, topics is yet another relationship pulled from Categories like so in the Controller and getting $topics using a #foreach on $categories->topics:
public function index() {
$categories = Category::orderBy('order', 'asc')->get();
return view('welcome', compact('categories'));
}
Here is a dump of $categories: http://dumptext.com/H8Nq16ea
Maybe you want to use nested eager loading.
Change: return $this->hasOne('App\Post')->with('thread')->with('author')->latest();
To this: return $this->hasOne('App\Post')->with('thread.author')->latest();
Also i never heard about latest() and the end of your return statement. Maybe you can try it with orderBy as shown below.
`return $this->hasOne('App\Post')->with('thread.author')->orderBy('id')->first;`
I guess you can use the orderBy('id')->reverse() function if the result is not in the order you want. Let me know if it helped you out.
You should make sure you have author for latest post you want to display. Otherwise if you expect not to have one for each record, you should try:
{{ $topic->latestPost->author ? $topic->latestPost->author->username : 'No author' }}
In addition instead of:
return $this->hasOne('App\Post')->with('thread')->with('author')->latest();
you can use
return $this->hasOne('App\Post')->with('thread','author')->latest();

Resources