Connection protected when I want to see my item in detail Laravel - laravel

I am on laravel 9, I have my database with my element that I want to see in detail but it shows me this when I want to see it, (I see it when I want to display all the elements)
error message
Controller
public function show(Tickets $tickets)
{
var_dump($tickets);
return view('tickets.show', ['ticket' => $tickets]);
}
Models
class Tickets extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = [
'title',
'description',
'status',
'priority',
'type',
'assigned_to',
];
}
Routes
Route::get('oauth', [gCalendarController::class, 'oauth']);

I think you returned the object of Tickets Model like #lagbox commented.
If you want to get all ticket when accessing to show() function, you need to do like this:
public function show(Tickets $tickets)
{
// Get all the ticket
$ticket = $tickets->all();
return view('tickets.show', compact('ticket'));
}
Hope this help.

Related

Laravel Backpack button that redirects to other Model's create view

So I have three models, Product, Sale and Code. Each Product belongs to a Code model (it's similar to a User) and each Sale has a field for the Code who is selling the Product and one for the Code who is buying it.
In the Product's list view I want to have a button called 'Sell' that redirects me to the Sale's create view with the Product's Code (basically the owner) passed in it so I can create a Sale with the Product and its Code already inserted.
I followed the documentation (https://backpackforlaravel.com/docs/3.4/crud-buttons) for creating a custom button, but when I get to the part inside the new function (in the guide it's 'moderate', for me it's 'sell') I can't redirect to the create view of the Sale model (the one I get by clicking Create in the Sale's CRUD) created when I ran
php artisan backpack:crud Sale
How can I do this?
N.B.: I already built all the model's relative CRUDs.
Button's code: sell.blade.php
#if($crud->hasAccess('update'))
<i class="las la-dollar-sign"></i>Vendi
#endif
sell method in the ProductCrudController
public function sell($id) {
// add redirect to Sale's create view with the product's id and owner
}
Sale model
class Sale extends Model {
//
use CrudTrait;
protected $guarded = [];
public function code() {
return $this->belongsToMany('App\Models\Code', 'code', 'code');
}
public function product() {
return $this->belongsTo('App\Models\Products');
}
}
Product model
class Product extends Model {
//
use CrudTrait;
protected $guarded = [];
public function productCode() {
return $this->belongsTo('App\Models\Code', 'code', 'code');
}
public function sales() {
return $this->hasMany('App\Models\Sale');
}
}
Code model
class Code extends Model {
//
use CrudTrait;
protected $guarded = [];
protected $primaryKey = 'code';
protected $keyType = 'string';
public function products() {
return $this->hasMany('App\Models\Product', 'code', 'code');
}
}
You could do the redirect in a method in the product's crud controller as you've started to, but I would actually do it directly in the button.
In sell.blade.php I'd do something like:
#if($crud->hasAccess('update'))
<i class="las la-dollar-sign"></i>Vendi
#endif
Note that assumes the path to your sale crud controller is admin/sales/, modify that if thats not the case.
Then, in your Sale crud controller where you set up your fields, set the field's default from the GET parameter if present something like:
$this->crud->addField([
'name' => 'code',
'label' => 'Code',
'type' => 'text',
'default' => request()->input('code', ''),
]);

Laravel : Can appends attributes lead to a n+1 problem?

Introduction
I start using appends attributes within models during fall 2019. At start, it was simply to run function that will join two column, but now, I use them to make some analysis on certain models before sending it to the frontend. Now, I'm suspecting this to lead to a n+1 problem. So, let check on some use of the appends attributes.
Basic usage
<?php
namespace App;
class User extends Authenticatable
{
protected $dates = ['deleted_at'];
protected $table = 'users';
protected $appends =
[
'full_name',
];
protected $fillable =
[
'username',
'first_name',
'last_name',
];
getFullNameAttribute()
{
return $this->first_name.' '.$this->last_name;
}
}
So, that let you append the full name, we know that, but under the hood?
$user = User::find($id);
Using appends with the above model retrieve is almost incensitive for any application. If we push it a little bit, what really happen?
$users = User::get();
Now, is the query to the database is the same as if we don't append anything? In other word, is the appending happen during the query to DB or after? Whatever, you need the full name and if it's not in the Database or the server, you will do it in the frontend, so that need to happen anyway. Which of the three is the fastest is for another question.
A bit more complexe usage
namespace App;
class User extends Authenticatable
{
protected $dates = ['deleted_at'];
protected $table = 'users';
protected $appends =
[
'full_name',
'last_post',
];
protected $fillable =
[
'username',
'first_name',
'last_name',
];
protected $hidden =
[
'password',
'remember_token',
];
public function posts()
{
return $this->hasMany('App\Post', 'user_id');
}
getFullNameAttribute()
{
return $this->first_name.' '.$this->last_name;
}
getLastPostAttribute()
{
return $this->posts()->last()
}
}
Now it's obvious that if I do $users->get(); it will result into a n+1 problem. But if I do this $users->with('posts')->get(); Do I have the n+1 problem or worst?
If your not use with n+1 problem
The n+1 problem is when you create a query that will need to make the initial call to DB and one call for each object into the array. $users->get() will get all users and then, since I append the last_post, since post where not retrieved, it will make a DB call for each of the models.
What I want to know, it's in the second case $users->with('posts')->get(), when Laravel will append last_post, will it know that it already have all the posts? So it doesnt need to load them a second time for each users?
So this attribute will cause n+1 queries no matter what you preload
getLastPostAttribute()
{
return $this->posts()->last()
}
By accessing posts() as a method you are creating a new query builder instance.
Replace it with return $this->posts->last() and then you can preload you posts relationship and avoid your extra queries
If you are unsure if you are getting n+1 issues you can require this great package from beyondcode beyondcode/laravel-query-detector which will inform you of any n+1's you have.
https://github.com/beyondcode/laravel-query-detector
To fix your n+1...
$users = Users::with(['posts'])->get();
public function getFullNameAttribute()
{
return $this->first_name.' '.$this->last_name;
}
public function getLastPostAttribute()
{
return $this->posts->last(); //update to not use builder instance
}

In Laravel - Add a variable to a model, without putting it in the database

I have a Team-model that has been used several places, and which returns the fields from the database in an API-endpoint.
It's currently accessed and returned like this:
$team = Team::find(1)
return $team;
I would like to add a calculated variable to that returned Collection. I imagined that I could add it to the constructor of the Model, and thereby get it with all the places where the Team-model is currently used, like this:
class Team extends Model
{
protected $table = 'teams';
protected $fillable = [
'id',
'created_at',
'updated_at',
'team_name'
];
public $number_of_players;
public function __construct( array $attributes = [] ){
$this->number_of_players = 3; //This number should be calculated
parent::__construct( $attributes );
}
}
But that doesn't work.
How do I add a variable to all the places, where the Team-model is fetched?
I also looked into API Resources. I looks like that that could be a solution, but I found it pretty verbose and a long-haired solution (plus, I couldn't get it to work either).
You can use accessor/mutator
Suppose you have a relationship
Team->Player (Team hasMany Players)
You can do like
in Team model
class Model extends Model {
public function players()
{
return $this->hasMany(Player::class, 'team_id', 'id');
}
}
now you can make it
<?php
class Model extends Model {
protected $appends = ['number_of_players'];
public function players()
{
return $this->hasMany(Player::class, 'team_id', 'id');
}
public function getNumberOfPlayersAttribute()
{
return $this->players->count();
}
}
And then access the players count of a team like App/Team::find(1)->number_of_players

Attach relation data directly to model

Article model
namespace App;
use Illuminate\Database\Eloquent\Model;
class Articles extends Model
{
protected $table = 'articles';
protected $primaryKey = 'idArticle';
protected $fillable = [
'idArticle', 'Topic', 'Image', 'Content', 'Views',
];
protected $hidden = [
'idCategory', 'idUser',
];
public function category()
{
return $this->hasOne(Categories::class, 'idCategory', 'idCategory');
}
}
So now when i call $article = Articles::find(1);, it will returns data from articles table, when i add $article->category;, it adds data $article->category->Name. I would like to have that Name directly inside $article - something like $article->category (so $article->category->Name into $article->category) is it possible to define that just using model class or i need to map it inside controller?
You can assign custom attributes to your Model classes. But you can't use the same property name as your category() method, because it's already accessed by $article->category.
An example giving you a property called category_name
class Articles extends Model
{
// attributes to append to JSON responses
protected $appends = ['category_name'];
// ... your other properties and methods
// your custom attribute
public function getCategoryNameAttribute()
{
if (!is_null($this->category)) {
return $this->category->Name;
}
return '';
}
}
Use as:
$article->category_name
You can use appends, as mentioned by #matticustard or just use the ->with() method while retrieving your model:
$article = Articles::find($id)->with('category');
Then, you can access the category name with:
$categoryName = $article->category->name;
Hope it helps.

Can eloquent ignore irrelevant data in Laravel 5.7

This is basically the same question as this here from 2013. Except the answer doesn't work for me.
I have a Model App\Post:
class Post extends Model
{
protected $fillable = ['title'];
// This Model doesn't contain an 'authorname' field
public function author()
{
return $this->belongsTo('App\Author');
}
}
and a Model App\Author:
class Author extends Model
{
protected $fillable = ['name'];
public function posts()
{
return $this->hasMany('App\Post');
}
}
And an array I want to save to that Model:
$posts = [
['title'=>'one post', 'authorname' => 'Mickey'],
['title'=>'another post', 'authorname' => 'Minny'],
];
foreach($posts as $post){
$authorModel=App\Author::firstOrCreate(['name'=>$post['authorname']]);
App\Post::create($post)->author()->associate($authorModel)->save();
}
According to this question, that should work, but I get an
SQL error 42522: Column not found: 1054 Unknown column 'authorname' in 'field list'
which suggests Laravel forwards the whole array to mySQL. Is there a way to make this work without unsetting the authorname key?
Obviously this is a simpified version of what I want to do and keeping track of what to unset seems unnecessary - as would be assigning all array keys to their respective database fields manually.
The only idea I have here is that you run this code in DatabaseSeeder (which automatically unguards models) or you somewhere manually call Eloquent::unguard() (or code similar to this). This would explain why any other fields are used when creating model no matter of $fillable property.

Resources