Laravel pass value from query to with() function - laravel

Here is my query:
$fix = Fixture::select('fixtures.*')
->whereDate('kickoff', '<', $date)
->with('competition')
->with('teamA')
->with(['teamA.standing' => function ($q) {
$q->whereColumn('standings.competition_id', '=', {{here i want the competition_id from competitions or fixtures table}} );
}])
->with('teamB')
->with(['teamB.standing' => function ($q) {
$q->whereColumn('standings.competition_id', '=', {{here i want the competition_id from competitions table or fixtures table}});
}])->get();
Code from Fixture model:
public function teamA()
{
return $this->belongsTo(Team::class,'team_a','id');;
}
public function teamB()
{
return $this->belongsTo(Team::class,'team_b','id');;
}
Code from Team model:
public function standing()
{
return $this->hasOne(Standing::class);;
}
Code from Standing model:
public function team(){
return $this->belongsTo(Team::class);
}
public function competition()
{
return $this->belongsTo(Competition::class);
}
Can someone help me to get this done or if I am doing it wrong what's the correct way?
->with(['teamA.standing' => function ($q) {
$q->whereColumn('standings.competition_id', '=', {{here i want the competition_id from competition table or fixtures table}} );
}])

Example:
Category::select('id', 'name')->whereHas('statuses', function($query) { $query(); })->with('courses')->get();

Related

creating a section for test where registered users can do it, but currently the test can be done many times and I wish they could only do it once

I'm using laravel 7
I need that if the user already took the test, load another different view
This is my test controller
public function index()
{
$categories = Category::with(['categoryQuestions' => function ($query) {
$query->orderBy('id')
->with(['questionOptions' => function ($query) {
$query->orderBy('id');
}]);
}])
->whereHas('categoryQuestions')
->get();
return view('client.test', compact('categories'));
}
public function store(StoreTestRequest $request)
{
$options = Option::find(array_values($request->input('questions')));
$result = auth()->user()->userResults()->create([
'total_points' => $options->sum('points')
]);
$questions = $options->mapWithKeys(function ($option) {
return [$option->question_id => [
'option_id' => $option->id,
'points' => $option->points
]
];
})->toArray();
$result->questions()->sync($questions);
return redirect()->route('client.results.show', $result->id);
}
}
This is the way the result table connects to the user table
This my migration to add relationship with a users table;
class AddRelationshipFieldsToResultsTable extends Migration
{
public function up()
{
Schema::table('results', function (Blueprint $table) {
$table->unsignedInteger('user_id');
$table->foreign('user_id', 'user_fk_773765')->references('id')->on('users');
});
}
}
Update your index method to check the results table. Assuming you have a Result model, for your results table.
public function index()
{
$existingTest = Result::where('user_id', Auth::user()->id)->first();
if(isset($existingTest->id)) {
//Return your other view or run logic specific to if the user has already done the test.
return view('client.test-complete');
}
$categories = Category::with(['categoryQuestions' => function ($query) {
$query->orderBy('id')
->with(['questionOptions' => function ($query) {
$query->orderBy('id');
}]);
}])->whereHas('categoryQuestions')
->get();
return view('client.test', compact('categories'));
}

Property [columns] does not exist on the Eloquent builder instance

i'm getting this error while trying to add a subquery select to a query builder. this error occurs when i try to get the product count for a given category.
addSubSelect Macro
Builder::macro('addSubSelect', function ($column, $query) {
if (is_null($this->columns)) {
$this->select($this->from.'.*');
}
return $this->selectSub($query, $column);
});
Category.php
public function scopeWithProductCount($query){
$query->addSubSelect('products_count', function($query) {
$query->whereHas('product', function ($query) {
$query->select('id')
->from('products')
->whereColumn('category_id', 'category.id')
->count();
});
});
}
Category Controller
public function index()
{
$categories = $this->user()->store->categories()
->withProductsSum()
->get();
return response()->json($categories);
}
i changed the scopedWithProductCount method to this to try and get more debugging options but i end up with the same error
public function scopeWithProductCount($query){
$query->addSubSelect('', function($query) {
});
}
The columns property is in the Illuminate\Database\Query\Builder Class and not Illuminate\Database\Eloquent\Builder. Your $this will refer to the Eloquent\Builder reference and not the Query\Builder.
So try changing your macro like this:
addSubSelect Macro
Builder::macro('addSubSelect', function ($column, $query) {
if (is_null($this->getQuery()->columns)) {
$this->select($this->from.'.*');
}
return $this->selectSub($query, $column);
});
Write join and the name of the table before the field:
public function scopeWithProductCount($query){
$query->addSubSelect('products_count', function($query) {
$query->whereHas('product', function ($query) {
$query->select('products.id')
->from('products')
->join('categories', 'categories.id', '=', 'products.category_id')
->count();
});
});
}

Scope always get the same relation

I want to make a relation ship bt condition...
I'm try like this:
Model:
public function page_link()
{
return $this->belongsTo(Link::class, 'page_id', 'user_id')->inRandomOrder()->Select('links.id', 'links.title', 'links.photo', 'links.country', 'links.friendly_url', 'links.clicks', 'links.description', 'links.suggestions', 'links.count_comments', 'links.url', 'links.shares', 'links.page_id', 'links.tag_id', 'links.created_at')->where('sponsored', 0)->where('scheduled', 0)>where('status', 1)->take(3)->orderBy('id','desc');
}
public function user_share()
{
return $this->belongsTo(Share::class, 'user_id', 'user_id')->inRandomOrder()->Select('id', 'link_id', 'user_id', 'shared_in', 'content', 'created_at')->take(3)->orderBy('id', 'desc')->where('type', '=', 0);
}
public function user(){
return $this->belongsTo(User::class, 'user_id', 'id');
}
public function scopeProfile($query)
{
return $query
->when($this->type == 0, function($q)
{
return $q->with('user_share.link.page')->with('user')->with('user_share.link.tag');
})
->when($this->type == 1, function($q)
{
return $q->with('page_link');
})
->when($this->type == 2, function($q)
{
return $q->with('group_link');
});
}
Controller:
$feed = Feed::Profile()->where('follower_id', auth()->user()->id)
->take(10)
->get();
But ALL the results, even the type 1 or 2 returns "user_links" relation. I don't know whats happening.
Someone can help me?

Nested "with()" laravel

I'm having issues with some relationships. I have the following situation
Product:
public function catalogues()
{
return $this->belongsToMany('App\Catalogue');
}
public function category()
{
return $this->belongsTo('App\Category');
}
Category:
public function products()
{
return $this->hasMany('App\Product');
}
Catalogue:
public function products()
{
return $this->belongsToMany('App\Product');
}
With a single query, I need to get all the categories that have products belonging to a certain catalogue. How can I achieve it?
Use whereHas():
Category::whereHas('products.catalogues', function($q) use($catalogueId) {
$q->where('catalogues.id', $catalogueId);
})
->get();
Or:
Category::whereHas('products', function($q) use($catalogueId) {
$q->whereHas('catalogues', function($q) use($catalogueId) {
$q->where('id', $catalogueId);
})
})
->get();
You need whereHas and
Category::whereHas('products')
->with(['products' => function($query) use ($id){
$query->with('catalogues' => function($query) use ($id){
$query->where('catalogues.id',$id);
});
}])
->get();
Hope this helps.

Laravel: Combining multiple query scopes on nested relationships without overriding the previous ones

I've got the following database structure for an online learning platform: A course consists of modules. A module consists of lessons and tasks. There are user specific information for each of these elements with the respective relationships defined on each model:
class Course extends Model {
public function user() {
return $this->belongsToMany(User::class)->withPivot('start_at', 'end_at');
}
public function modules() {
return $this->hasMany(Module::class);
}
// ...
}
class Module extends Model {
public function user() {
return $this->belongsToMany(User::class)->withPivot('start_at', 'end_at');
}
public function lessons() {
return $this->hasMany(Lesson::class);
}
public function tasks() {
return $this->hasMany(Lesson::class);
}
}
class Lesson extends Model {
public function user() {
return $this->belongsToMany(User::class)->withPivot('favourite', 'completed_at');
}
}
class Task extends Model {
public function user() {
return $this->belongsToMany(User::class)->withPivot('completed_at');
}
}
My goal is to load a complete course with the following scopes on the course model:
class Course extends Model {
// ...
public function scopeWithModules($query) {
return $query->with(['modules' => function ($q) {
$q->with(['user' => function ($q) { $q->where('user_id', auth()->user()->id); }])
->whereHas('user', function ($q) { $q->where('user_id', auth()->user()->id); });
}]);
}
public function scopeWithLessons($query) {
return $query->with(['modules.lessons' => function ($q) {
$q->with(['user' => function ($q) { $q->where('user_id', auth()->user()->id); }])
->whereHas('user', function ($q) { $q->where('user_id', auth()->user()->id); });
}]);
}
public function scopeWithTasks($query) {
return $query->with(['modules.tasks' => function ($q) {
$q->with(['user' => function ($q) { $q->where('user_id', auth()->user()->id); }])
->whereHas('user', function ($q) { $q->where('user_id', auth()->user()->id); });
}]);
}
// ...
}
Each of these scopes alone is working fine. But combining them will override the previous ones, so only the last of these scopes will be executed.
Executing this
$course = Course::whereSlug('learning-abc')
->withModules()
->withLessons()
->withTasks()
->firstOrFail();
will give me the course with modules and tasks (but no lessons and user information for the modules).
Of course I can write one single bulky scope like withModulesLessonsTasks() but I hope there is a more elegant solution to this. Any ideas?
Before I had:
$course = Course::whereSlug('learning-abc')
->with([
'modules.user',
'modules.lessons.user',
'modules.tasks.user'
])
->firstOrFail();
which was working fine except for filtering the auth()->user().

Resources