Laravel: get data from related tables (json array column) - json

I have 2 related tables
teams:
| id | name | game_id | user_id |
|----|----------|---------------|---------|
| 1 | EA Games | ["1","2"] | 1 |
| 2 | Nintendo | ["1"] | 2 |
| 3 | HoG | ["3","4","5"] | 1 |
games:
| id | name |
|----|----------|
| 1 | Cod MW |
| 2 | FIFA |
Controller:
public function showManage()
{
$teams = Teams::where('user_id', Auth::user()->id)->where('enabled', '!=', 0)->get();
return view('teams.manage.index', ['teams' => $teams]);
}
View:
#foreach ($teams as $item)
<div class="col-md-2 text-center">
<div class="team-item">
<div class="team-image">
<img src="/images/teams/logo/{{$item->logo}}" alt="{{$item->name}}">
</div>
<div class="team-text">
{{$item->name}}
</div>
<ul>
<li> Game Name 1 </li>
<li> Game Name 2 </li>
<li> Game Name 3 </li>
</ul>
</div>
</div>
#endforeach
Team Model:
<?php
namespace App;
use App\User;
use App\Games;
use Illuminate\Database\Eloquent\Model;
class Teams extends Model
{
protected $table = 'teams';
public function captain()
{
return $this->hasOne(User::class, 'id', 'user_id');
}
public function game()
{
return $this->hasMany(Games::class, 'id', 'game_id');
}
}
Each user can have many teams with different game_ids and i wan't to show game name for each team for my user
How can i join to my game table?
Sorry for my bad English

Having a json field make it impossible to do it with a database statement.
Note that JSON columns cannot have a default value, be used as a primary key, be referenced as a foreign key or have an index. You can create secondary indexes on generated virtual columns, but it’s possibly easier to retain an indexed value in a separate field.
With the current structure, your only solution is to loop the results and do another query for the games.
Changing the structure will be a better solution where you have another table game_team with ids of teams and games as composite key. Then it will be as easy as running this (with the right belongsToMany relation)
$teams = Auth::user()->teams()->with('games')->where('enabled', '!=', 0)->get();

I can fix it with foreach and for loops
Controller:
public function showManage()
{
$teams = Teams::where('user_id', Auth::user()->id)->where('enabled', '!=', 0)->get();
$array = array();
foreach ($teams as $v) {
$data = $v->game_id;
$array[$v->id] = array(
'games' => array(
)
);
$games = Games::whereIn('id', $data)->get();
foreach ($games as $k) {
array_push($array[$v->id]['games'], $k->name);
}
}
return view('teams.manage.index', ['teams' => $teams, 'data' => $array]);
}
View:
#foreach ($teams as $item)
<div class="col-md-2 text-center">
<div class="team-item">
<div class="team-image">
<img src="/images/teams/logo/{{$item->logo}}" alt="{{$item->name}}">
</div>
<div class="team-text">
{{$item->name}}
</div>
<ul>
#foreach ($data[$item->id] as $v)
#for ($i = 0; $i < count($v); $i++)
<li> {{$v[$i]}} </li>
#endfor
#endforeach
</ul>
</div>
</div>
#endforeach

Related

Updating table with multiple rows

How can I update multiple rows at the same time by their report_id? My Inventory table looks like this:
| id | report_id | product_id | shelf_quantity | display_quantity |
|----|-----------|------------|----------------|------------------|
| 1 | 2 | 12 | 1 | 5 |
| 2 | 2 | 13 | 2 | 6 |
| 3 | 2 | 14 | 3 | 23 |
My attempt to solve the problem:
My controller:
function update($id, Request $request) {
$report = Report::find($id);
$inputs = $request->input('display');
$report->user_id = $user_id;
$report->save();
//Updating inventory table
$inventory = Inventory::where('report_id', $report->id)->get();
foreach($inputs as $key => $value) {
$inventory->display = $request->input('display')[$key] ?: 0;
$inventory->storage = $request->input('storage')[$key] ?: 0;
$inventory->save();
}
My web route:
Route::put('/reports/{id}', 'ReportController#update');
The problem here is that it is only saving the last value that I input.
Additional information
I'm also using the same code in storing new rows and it's working fine. Please see code below:
public function store(Request $request) {
//Adding inventory table
$new_inventories = new Inventory();
foreach($inputs as $key => $value) {
$data[] = [
'user_id' => $user_id,
'report_id' => $new_report->id,
'display' => $request->input('display')[$key] ?: 0,
'storage' => $request->input('storage')[$key] ?: 0,
'product_id' => $request->product_id[$key],
'created_at' => $now,
'updated_at' => $now,
// 'remark' => $request->remark[$key] ?? null,
];
}
Inventory::insert($data);
//End of inventory table
}
Any form of help would be appreciated. Thank you!
EDIT:
My form looks like this:
<form action="/reports/{{$report->id}}" method="post">
#csrf
{{method_field('PUT')}}
#foreach($products as $product)
<input type="number" name="product_id[]" value="{{ $product->id}}" hidden>
<input type="number" name="storage[]">
<input type="number" name="display[]">
#endforeach
</form>
You cannot update multiple rows in one shot. In this case the best way is to get one by one the items in inventory and update them. So you loop through $request->input('product_id'), get the Inventory model for that product_id and $report->id, update and save.
for($i=0; $i<count($request->input('product_id');$i++) {
$inventory = Inventory::where('report_id', $report->id)->where('product_id', $request->input('product_id')[$i])->first();
$inventory->display = $inventory->display = $request->input('display')[$i];
$inventory->storage = $inventory->storage = $request->input('storage')[$i];
$inventory->save();
}

How to handle Many To Many relationship with three or more classes with Laravel and MySQL

I'm working on a project with Laravel and Eloquent/MySQL.
I'd like to know how to handle a many-to-many relationship with three tables (users, merchants, roles).
Any user can have one or more merchant.
Any merchant can be shared between users.
Any user have a specific role for a merchant.
Is there a best practice to follow?
How can I get all the merchants by a user having a specific role?
Thanks for helping
This is my current structure:
Users
-------------------------------
| id | first_name | last_name |
-------------------------------
Merchants
-------------------
| id | trade_name |
-------------------
Roles
-------------------------
| id | name | hierarchy |
-------------------------
merchant_user_role
-----------------------------------
| merchant_id | user_id | role_id |
-----------------------------------
Merchant Model
<?php
class Merchant extends Model
{
public function users()
{
return $this->belongsToMany('App\User', 'merchant_user_role')
->withPivot('role_id')
->withTimestamps()
->orderBy('first_name', 'asc');
}
}
User Model
<?php
class User extends Model
{
public function merchants()
{
return $this->belongsToMany('App\Merchant', 'merchant_user_role')
->withPivot('role_id')
->withTimestamps()
->orderBy('trade_name', 'asc');
}
public function roles()
{
return $this->belongsToMany('App\Role', 'merchant_user_role')
->withTimestamps();
}
}
Role Model
<?php
class Role extends Model
{
public function users()
{
return $this->belongsToMany('App\User')->withTimestamps();
}
}
$merchants = $user->merchants()->where('role_id', $some_role_id)->get();

How to show Json field value in laravel

I have a json field in my database name is permissions {"read": true, "create": true}. Now, I want to show this in my blade view. I had try this way but it's show an error.
#foreach($users as $user)
<tr>
<td>{{$user->roles->permissions}}</td>
</tr>
#endforeach
show this Error Message.
Property [permissions] does not exist on this collection instance.
User Model
public function roles()
{
return $this->belongsToMany(Role::class,'user_roles');
}
I tested this scenario and was OK . i hope usefull for you :
my route :
Route::get('/test', function (Request $request) {
$users=\App\User::with('roles')->get();
return view('welcome',compact('users'));
});
define roles method inside user model :
public function roles()
{
return $this->belongsToMany(Role::class,'user_roles');;
}
and get permissions in view :
#foreach($users as $user)
#foreach($user->roles as $role)
<tr>
<td>{{$role}}</td>
</tr>
#endforea
#endforeach
I test with these tables
user_roles
user_id | role_id
-----------------
1 | 2
1 | 2
roles:
id | permissions
-----------------
1 | {"read": true, "create": true}
2 | {"read": true, "create": false}
users:
id | name | email | password | remember_token | created_at|updated_at
----------------------------------------------------------------------
1 | alihossein|ali#gmail.com|XXXXX|UIWKK67ei5CCuiv1OXilKY2aRkTfSqGLpqJch0F9YmenGSorsQGHVvWiX6kP| 2018-05-28 22:25:14 | 2018-05-28 22:25:14

Laravel 4.2 Multiple Query in date range

I'm trying to get data for each date in range from 3 tables: Main table which is connected with 2 other tables using hasMany method.
Data stored as in example:
Main Table:
id | article title | url | created_at | updated_at |
----------------------------------------------------------------
14 | Some Title | www.example.com | TIMESTAMP | TIMESTAMP |
Views table (there is written count of views for each hour):
id | article_id | views | created_at | updated_at |
---------------------------------------------------
1 | 14 | 317 | TIMESTAMP | TIMESTAMP | (01:00:00)
2 | 14 | 186 | TIMESTAMP | TIMESTAMP | (02:00:00)
Clicks Table (there is written every click on this article):
id | article_id | ip_adress | created_at | updated_at |
---------------------------------------------------------
1 | 14 | 192.168.1.1 | TIMESTAMP | TIMESTAMP |
For example:
I need to get Articles from 01-02-2016 to 01-03-2016.
For every article I need to sum views and clicks for each day.
So in result i need to get something like this:
ID: 14, Title: Some Title, Views: 503, Clicks: 27
First, I wrote this code, but it makes lots of requests to database:
$dates = new DatePeriod($start, new DateInterval('P1D'), $stop);
foreach ($dates as $i => $date) {
$articles = Articles::with(['views' => function ($query) use ($date) {
$query->where('created_at', $date);
}, 'clicks' => function ($query) use ($date) {
$query->where('created_at', $date);
}])->get();
foreach ($articles as $article) {
foreach ($views->countOfViews as $i) {
// Code
}
foreach ($clicks->countOfClicks as $i) {
// Code
}
// Code
}
}
Then I found solution, to get exact same result as I'm getting in first example, but making only three requests:
$dates = new DatePeriod($start, new DateInterval('P1D'), $stop);
$articles = Articles::with(['views' => function ($query) use ($start, $stop) {
$query->whereBetween('created_at', array($start, $stop));
}, 'clicks' => function ($query) use ($start, $stop) {
$query->whereBetween('created_at', array($start, $stop));
}])->get();
foreach ($dates as $date) {
foreach ($articles as $article) {
foreach ($views->countOfViews as $i) if ($date->format('Y-m-d') === $i->created_at->toDateString()) {
// Code
}
foreach ($clicks->countOfClicks as $i) if ($date->format('Y-m-d') === $i->created_at->toDateString()) {
// Code
}
// Code
}
}
It solves problem with too many queries, but it takes to much time. Is it possible to do same thing faster?
Final Code:
$dates = new DatePeriod($start, new DateInterval('P1D'), $stop);
$articles = Articles::with(['views' => function ($query) use ($start, $stop) {
$query->whereBetween('created_at', array($start, $stop))
->groupBy('campaign_id', DB::raw('DATE(created_at)'))
->selectRaw('*, sum(views) as views');
}, 'clicks' => function ($query) use ($start, $stop) {
$query->whereBetween('created_at', array($start, $stop))
->groupBy('campaign_id', DB::raw('DATE(created_at)'))
->selectRaw('*, sum(clicks) as clicks');
}])->get();
foreach ($dates as $date) {
foreach ($articles as $article) {
foreach ($views->countOfViews as $i) if ($date->format('Y-m-d') === $i->created_at->toDateString()) {
// Code
}
foreach ($clicks->countOfClicks as $i) if ($date->format('Y-m-d') === $i->created_at->toDateString()) {
// Code
}
// Code
}
}

Can I build a Model for two Tables on PhalconPHP?

I have one games table and two tables to store their scores, game_scores and thirdparty_game_scores with exactly the same structure, something like that:
-------------------------GAMES-------------------------
slug | title | technology | (other non-relevant fields)
-------------------------------------------------------
----------------------GAME SCORES----------------------
id (PK) | game_slug | user | team | score | timestamp
-------------------------------------------------------
----------------THIRDPARTY GAME SCORES-----------------
id (PK) | game_slug | user | team | score | timestamp
-------------------------------------------------------
And their Models like:
class GameScores extends BaseGamesModel {
public function initialize() {
parent::initialize();
$this->belongsTo( 'game_slug', 'Games', 'slug' );
$this->skipAttributes(array('creation_time', 'last_modified'));
}
}
I'm building a weekly ranking with game scores stored only on game_scores:
$ranking = GameScores::sum(
array(
"column" => "score",
"conditions" => $conditions,
"group" => "team",
"order" => "sumatory DESC"
)
);
Is there any way to create a Model that concatenates all data from game_scores and thirdparty_game_scores to create the same ranking without any extra effort?
Thank you so much!
You can set the source table dynamically in your model. See Can I build a Model for two Tables on PhalconPHP?
You should use the setSource() method and put your condition in there, e.g.:
$source = 'default_table';
if (class_name($this) === 'A') {
$source = 'A_table';
}
return $source;