I am new to Laravel & working on my first project. A small issue I am having is when I build a collection (array) and insert results into Laravel Form Select, and export to Excel, my results are wrapped in ["array"] brackets and quotes.
Code to build the collection:
$p3 = DB::table('players')
->where ('id', $player3)
->selectRaw('id, CONCAT(fname," ",lname) as full_name')
->pluck('full_name', 'id');
$played['p'] .= $p3;
$p4 = DB::table('players')
->where ('id', $player4)
->selectRaw('id, CONCAT(fname," ",lname) as full_name')
->pluck('full_name', 'id');
Note, there are 16 above (grabbing names from associated table)... I then build the collection:
$played = collect([$p1, $p2, $p3, $p4, $p5, $p6, $p7, $p8, $p9, $p10, $p11, $p12, $p13, $p14, $p15, $p16]);
and pass to view:
return view('grades.matchcard.edit', compact('data','data1', 'played', 'mid'));
As per image, the results are wrapped in brackets/quotes... Same when I export to Excel... I tried join & implode (get errors). Tried using
str_replace (kind of worked - but not great...
Any sugggestions would be greatly appreciated. thanks
Each of your DB queries generates a collection of one element, and then you collect those collections into your final $played variable. So iterating over it, each item is actually another collection. You want to flatten the collections, like so:
$played = collect([$p1, $p2, ...])->flatten();
BTW, I don't see the rest of your code but the chunk you've shown is quite inefficient, and might be better written:
$played = DB::table('players')
->whereIn('id', [$player3, $player4, $player5 .... all your ids ...])
->selectRaw('id, CONCAT(fname," ",lname) as full_name')
->pluck('full_name', 'id');
Here you are doing just one DB query, instead of many, and the query returns your collection, no need for further collecting and flattening. More info in the docs.
UPDATE to clarify based on comments:
The pluck() method above keys the resulting collection by the second parameter. So $played should be a collection of correctly matched id => full_name elements. To display the player with id 3's full name, you should be able to use $played[3].
BTW: do you have a Player model? If not, to do things the neat Laravel way you probably should, and it would make things a lot simpler. For eg:
In your model
Define an accessor, to make getting full name easier.
public function getFullNameAttribute($value) {
return $value->fname . ' ' . $value->lname;
}
More info about accessors in the docs.
In your controller
$players = App\Player::find([$player3, $player4, $player5 .... all your ids ...]);
return view('whatever.your.view.is', ['players' => $players]);
More info about retrieving models in the docs.
In your view
<select>
#foreach ($players as $player)
<option value='{{ $player->id }}'>{{ $player->full_name }}</option>
</select>
#endforeach
If you want players to be listed in a particular order, you should either define that order in your model/database (eg a players.ranking field?), or, if the order is based on something derivable you could order it on the fly. Eg if you need them alphabetical you can add ->orderBy('lname') to the $players query in your controller.
try
$p4 = DB::table('players')
->where ('id', $player4)
->selectRaw('id, CONCAT(fname," ",lname) as full_name')
->get();
And in blade
{{$p4->id}}
{{$p4->full_name}}
EDIT
Sorry i didnt see the hole question
you can do something like this
$p4 = DB::table('players')
->where ('id', $player4)
->selectRaw('id, CONCAT(fname," ",lname) as full_name')
->get();
$played = new Collection();
$played.push($p4);
And in blade this should work
#foreach($played as $object)
{{$object->id}}
{{$object->full_name}}
#endforeach
Related
I am trying to retrieve symbols with their comments using hasMany in laravel 5.3
Symbol.php
public function comments() {
return $this->hasMany('App\Comment');
}
Comment.php
public function symbol() {
return $this->belongsTo('App\Symbol');
}
when I run:
$symbols = Symbol::with('comments')->paginate(100);
I get the correct output (lists all symbols with their comments)
#foreach ($symbols as $s)
{{ $s->name }}
#foreach ($s->comments as $c)
{{ $c->body }}
#endforeach
#endforeach
but when I add a join to the statement:
$symbols = Symbol::with('comments')
->join('ranks', 'symbols.id', '=', 'ranks.symbol_id')
->join('prices', 'symbols.id', '=', 'prices.symbol_id')
->paginate(100);
The foreach loop has no comments for every symbol. Any idea why the join would be causing this?
When you are doing joins like this, attributes with the same names will be overwritten if not selected. So select the attributes you need for your code, and nothing else. As shown below.
$symbols = Symbol::with('comments')
->join('ranks', 'symbols.id', '=', 'ranks.symbol_id')
->join('prices', 'symbols.id', '=', 'prices.symbol_id')
->select('symbols.*', 'ranks.importantAttribute', 'prices.importantAttribute')
->paginate(100);
Basicly i think your ids are being overwritten, by the two joins because they also have id fields, i have had a similar problem doing joins, and it breaks relations if the id is overwritten.
And you have to be carefull, all fields who shares names can be overwritten and parsed wrong into the models.
In my controller I return a view with a ?collection $programs? from an eloquent query to the view.
Controller
$programs = ScheduledProgram::where('registration_start_date', '<=', $today)
return View::make('admin/register_users/show', compact(programs));
I wan to do something like this without it running a new query from the view...
VIEW
{{$program->find(id)}}
I know that $programs is a dataset that already has the record, but I don't know the way to access the element by ID this way.
How do I do this?
(sorry, seems like an obviously searchable question but my search terms aren't comming up with the answer)
in that case you need to make a #foreach in $programs to access the data. Like this:
#foreach($programs as $key => $value)
{{$value->id}}
#endforeach
If the return is only one line you can do this:
{{$programs[0]->id}}
1.You have to add the method get (converts the "dataset " in a Laravel collection) to iterate the collection.
$programs = ScheduledProgram::where('registration_start_date', '<=', $today)
->get()
2.If you want to get a single record:
ScheduledProgram::where('registration_start_date', '<=', $today)->where('id', 5)->get();
I have tried various methods to resolve this issue, but none worked for me.
1st method:
$title = Character::find($selected_char->id)->title()->where('title', '=', 'Castle');
$title = $title->where('title', '=', 'City');
$title = $title->get();
2nd method:
$title = Character::find($selected_char->id)->title()->where('title', '=', 'Castle')->where('title', '=', 'City')->get();
3rd method:
$title = DB::select(DB::raw("select * from titles where titles.char_id = 5 and title = 'Castle' and title = 'City'"));
None of the above methods work. If I take only one where clause it works perfectly. Example:
$title = Character::find($selected_char->id)->title()->where('title', '=', 'City')->get();
$title = Character::find($selected_char->id)->title()->where('title', '=', 'Castle')->get();
I even tried to take another column than title, but it doesn't work with a second where function. I want to retreive the rows from titles table where the title is City AND Castle I have used multiple where clauses before in a single select statement and it worked. Not now. Any suggestions? Thanks in advance.
You said:
I want to retreive the rows from titles table where the title is City AND Castle
You may try this:
$rowCOllection = DB::table('titles')
->whereIn('title', array('City', 'Castle'))->get();
Using multiple where:
$rowCOllection = DB::table('titles')
->where('title', 'City')
->where('title', 'Castle')->get();
If you want to add another where clause for titles.char_id then you may use it like:
$rowCOllection = DB::table('titles')
->where('title', 'City')
->where('title', 'Castle')
->where('char_id', 5)->get();
You may chain as much where as you need before you call get() method. You can add the where('char_id', 5) after the whereIn like whereIn(...)->where('char_id', 5) and then call get().
If you have a Title model then you may do the same thing using:
Title::where(...)->where(...)->get();
Same as using DB, only replace the DB::table('titles') with Title, for example:
$rowCOllection = Title::where('title', 'City')
->where('title', 'Castle')
->where('char_id', 5)->get();
What about Character here ?
I don't really know how work your double ->where( in php, but in sql here is the mistake :
When you say where title = 'a' and title = 'b', it's like you say : ok give me something where 0=1 it returns nothing.
You can do :
select * from titles where titles.char_id = 5 and (title = 'Castle' or title = 'City')
Retrieve all data where title equals castle or city
Or
select * from titles where titles.char_id = 5 and title IN ('Castle','City')
Retrieve all data where title equals castle or city using IN
I'm pretty sure you will find a way to do that in PHP too.
Assuming you are using Laravel 4
And Character is your model extended from Eloquent
don't mix FIND and WHERE.
Find is for single usage find AND sorting afterward (so order by, and etc)
So if you want to chain up your query
Character::where()->where()->where()-get() (don't forget the get or else you wont get a result)
this way you respect eloquent's features.
Note your first method with ->title() is flawed because your calling a function that you custom created inside your model - thats why it wouldn't have worked.
Note: WereWolf Alpha's method will also work IF you don't want to use Eloquent because the code that he presented will work but thats Fluent notation...so take your pick.
How to merge this two queries ?
$data = DB::table('category_to_news')
->where('category_to_news.name', ucwords($category))
->remember(1440)
->count();
and
$data = DB::table('category_to_news')
->where('category_to_news.name', ucwords($category))
->remember(1440)
->get();
So, as far as I understand from your comment, you simply want to get all records from the table category_to_news and you want to know how many records are in there, right?
MySQL's count is an aggregate functions, which means: It takes a set of values, performs a calculation and returns a single value. If you put it into your names-query, you get the same value in each record. I'm not sure if that has anything to do with 'optimization'.
As already said, you simply run your query as usual:
$data = DB::table('category_to_news')
->where('name', ucwords($category))
->remember(1440)
->get(['title']);
$data is now of type Illuminate\Support\Collection which provides handy functions for collections, and one them is count() (not to be confused with the above mentioned aggregate function - you're back in PHP again, not MySQL).
So $data->count() gives you the number of items in the collection (which pretty much is an array on steroids) without even hitting the database.
Hi DB class dont return collection object it give error "call member function on array" but eloquent return collection object. for above code we can use collect helper function to make it collection instance then use count and other collection methods https://laravel.com/docs/5.1/collections#available-methods .
$data = DB::table('category_to_news')
->where('name', ucwords($category))
->remember(1440)
->get();
$data = collect($data);
$data->count();
You my get it using:
$data = DB::table('category_to_news')
->where('name', ucwords($category))
->remember(1440)
->get();
To get the count, try this:
$data->count();
Why you are using DB::table(...), instead you may use Eloquent model like this, create the model in your models directory:
class CategoryToNews extends Eloquent {
protected $table = 'category_to_news';
protected $primaryKey = 'id'; // if different than id then change it here
}
Now, you may easily use:
$data = CategoryToNews::whereName(ucwords($category))->get();
To get the count, use:
$data->count();
Of course I can use order_by with columns in my first table but not with columns on second table because results are partial.
If I use 'join' everything works perfect but I need to achieve this in eloquent. Am I doing something wrong?
This is an example:
//with join
$data = DB::table('odt')
->join('hdt', 'odt.id', '=', 'hdt.odt_id')
->order_by('hdt.servicio')
->get(array('odt.odt as odt','hdt.servicio as servicio'));
foreach($data as $v){
echo $v->odt.' - '.$v->servicio.'<br>';
}
echo '<br><br>';
//with eloquent
$data = Odt::get();
foreach($data as $odt){
foreach($odt->hdt()->order_by('servicio')->get() as $hdt){
echo $odt->odt.' - '.$hdt->servicio.'<br>';
}
}
In your model you will need to explicitly tell the relation to sort by that field.
So in your odt model add this:
public function hdt() {
return $this->has_many('hdt')->order_by('servicio', 'ASC');
}
This will allow the second table to be sorted when using this relation, and you wont need the order_by line in your Fluent join statement.
I would advise against including the order by in the relational method as codivist suggested. The method you had laid is functionally identical to codivist suggestion.
The difference between the two solutions is that in the first, you are ordering odt ( all results ) by hdt.servicio. In the second you are retrieving odt in it's natural order, then ordering each odt's contained hdt by servico.
The second solution is also much less efficient because you are making one query to pull all odt, then an additional query for each odt to pull it's hdts. Check the profiler. Considering your initial query and that you are only retrieving one column, would something like this work?
HDT::where( 'odt_id', '>', 0 )->order_by( 'servico' )->get('servico');
Now I see it was something simple! I have to do the query on the second table and get contents of the first table using the function odt() witch establish the relation "belongs_to"
//solution
$data = Hdt::order_by('servicio')->get();
foreach($data as $hdt){
echo $hdt->odt->odt.' - '.$hdt->servicio.'<br>';
}
The simple answer is:
$data = Odt::join('hdt', 'odt.id', '=', 'hdt.odt_id')
->order_by('hdt.servicio')
->get(array('odt.odt as odt','hdt.servicio as servicio'));
Anything you can do with Fluent you can also do with Eloquent. If your goal is to retrieve hdts with their odts tho, I would recommend the inverse query for improved readability:
$data = Hdt::join('odt', 'odt.id', '=', 'hdt.odt_id')
->order_by('hdt.servicio')
->get(array('hdt.servicio as servicio', 'odt.odt as odt'));
Both of these do exactly the same.
To explain why this works:
Whenever you call static methods like Posts::where(...), Eloquent will return a Fluent query for you, exactly the same as DB::table('posts')->where(...). This gives you flexibility to build whichever queries you like. Here's an example:
// Retrieves last 10 posts by Johnny within Laravel category
$posts = Posts::join('authors', 'authors.id', '=', 'posts.author_id')
->join('categories', 'categories.id', '=', 'posts.category_id')
->where('authors.username', '=', 'johnny')
->where('categories.name', '=', 'laravel')
->order_by('posts.created_at', 'DESC')
->take(10)
->get('posts.*');