I'm trying to return multiple views using the laravel framework. When I return the variable, it only makes it through the loop once, therefore only one comment is displayed on the page.
foreach($index_comments as $comments){
$commentComment = $comments->comment;
$index_children = NULL;
$getUser = DB::table('users')->where('id', '=', $comments->from_user_id)->get();
foreach ($getUser as $user) {
$firstName = $user->first_name;
$lastName = $user->last_name;
}
return View::make('feeds.comments')->with(array(
'firstName' => $firstName,
'lastName' => $lastName,
'commentComment' => $commentComment,
'index_children' => $index_children
));
}
I just need a way of returning multiple views.
Thanks for any help!
Toby.
It seems that you don't quite understand the concepts of Laravel and/or PHP yet. So let's start it from scratch: We want to fetch all comments, output the comment and the name of the user who wrote the comment.
At a very basic level, we can just grab it straight from the DB with the query builder:
public function showComments()
{
$commentData = DB::table('comments')
->join('users', 'users.id', '=', 'comments.from_user_id')
->get(['text', 'firstName', 'lastName']);
return View::make('feeds.comments')->with('commentData', $commentData)
}
And in your view:
#foreach($commentData as $comment)
{{ $comment->text }}
<br />
written by {{ $comment->firstName }} {{ $comment->lastName }}
<hr />
#endforeach
That's it. You don't return the view on each iteration, the iteration happens in the view. The return statement terminates the function execution immediately. If you return within in a loop, it will always exit upon the first iteration, that's why you're getting only one result.
In the next step, you should play around with Models and Eloquent for even more powerful and readable data handling.
Related
I'm working on a collection that needs to calculate some data for each row and it takes too much time to load into view. The problem is I defined an accessor and inside that accessor will perform some calculation and if the data is too big or when user retrieve too many row at once.
Example Model:
public function getCalculationAttribute()
{
$score_ids = Score::whereIn('id', $this->scores->pluck('score_id'))->pluck('id');
$count_score = $count_score->count();
$penalties = Penalty::whereIn('score_id', $score_ids->toArray())->count();
$balance = $count_score - $penalties;
$another_score = $count_score > 0 ? ($balance / $count_score) * 0.7 : 0;
return [
'field_a' => $count_score,
'field_b' => $penalties,
'field_c' => $balance,
'field_d' => $another_score
];
}
Example Controller
public function index(){
$data = ExampleModel::get();
return view('example', ['data' => $data]);
}
Example blade
#foreach($data as $row)
<p>{{ $row->calculation['field_a']}}</p>
<p>{{ $row->calculation['field_b']}}</p>
<p>{{ $row->calculation['field_c']}}</p>
<p>{{ $row->calculation['field_d']}}</p>
#endforeach
When I didn't need the calculation attribute it works perfectly fine, but when I do and I know each of them will be running query and calculation and it will take forever. Is there any good practice on retrieving data with calculation or any suggestion I can modify this to improve the performance? The code above is just an example. Thank you in advance!
You've got an N+1 query issue with this code. Each time you loop $data and call $row->calculation, you're executing 3 extra queries:
Score::whereIn(...);
$this->scores->pluck('score_id');
...
Penalty::whereIn(...);
You're calling $row->calculation 4 times... I'm pretty sure that means 12 additional queries per row in $data, since get{Whatever}Attribute() doesn't have any kind of caching/logic to know you've called it already.
If you save $row->calculations to a variable, you can reduce that a bit:
#foreach($data as $row)
#php $calculations = $row->calculations; #endphp
<p>{{ $calculations['field_a']}}</p>
<p>{{ $calculations['field_b']}}</p>
<p>{{ $calculations['field_c']}}</p>
<p>{{ $calculations['field_d']}}</p>
#endforeach
Additionally, you can eager load the scores relationship to reduce it a bit more:
$data = ExampleModel::with('scores')->get();
Including that will make $this->scores->pluck('score_id'); use the pre-loaded data, and not call an additional query.
Lastly, try to use relationships for your Score::whereIn() and Penalty::whereIn() queries. I'm not sure how you would define them, but if you did, then including those in your ->with() clause will hopefully completely remove this N+1 query issue.
I am new to laravel and using simple command to query from database.
I am trying to get multiple value from database with same id.
$id = 'P01';
//Get value from database
$fruitname = DB::table('fruits')->where('id', $id)->value('fruitname');
$fruitcolour = DB::table('fruits')->where('id', $id)->value('fruitcolour');
$fruitshape = DB::table('fruits')->where('id', $id)->value('fruitshape');
$updatedat = DB::table('fruits')->where('id', $id)->value('updated_at');
$data = array(
'fruitname' => $fruitname,
'fruitcolour' => $fruitcolour,
'fruitshape' => $fruitshape,
'updated_at' => $updatedat
);
As result, $data can store the value.
But i found out that it takes time to complete the process.
Is there any ways i can optimize the process?
I'm not sure why you're making it more hard than it is, but you can just simply use eloquent in this case:
Provided you already have created the necessary model and adding it in your controller:
use App\Fruits;
Just simply use it in the find method:
public function someMethodName()
{
$id = 'P01';
$fruit = Fruits::find($id);
echo $fruit->fruitname; // and others
}
$fruit = DB::table('fruits')->where('id', $id)->first();
$data = array(
'fruitname' => $fruit->fruitname,
'fruitcolour' => $fruit->fruitcolour,
'fruitshape' => $fruit->fruitshape,
'updated_at' => $fruit->updatedat
);
Or if you have a view, you could just do
$fruit = DB::table('fruits')->where('id', $id)->first();
return view('yourview', compact('fruit'));
And in the view, you can access each of the values like so:
{{ $fruit->fruitname }}
{{ $fruit->fruitcolor }}
In your controller add function
public function function_name(Fruit $fruit)
{
return view('your_view_name', compact('fruit'));
}
In web file set your route as
Route::get('/fruit/{fruit}','YourControllername#methodName')->name('show');
At the time of setting route
Show
in View file get data as
{{ $fruit->fruitname }}
{{ $fruit->fruitcolor }}
To make it with a single query with QueryBuilder since QueryBuilder can have better performance than Eloquent:
DB::table('fruits')->where('id', $id)
->select(['fruitname', 'fruitcolour', 'fruitshape', 'updated_at'])
->first();
This returns a associative array with the selected column names.
i created a search functionality within my Laravel project - the user can search for teamnames or usernames - the result is created and returned like this:
$teams_obj = Team::where('teamname', 'LIKE', '%'.Input::get('searchterm').'%')->get();
$persons_obj = User::where('name', 'LIKE', '%'.Input::get('searchterm').'%')->orWhere('vorname', 'LIKE', '%'.Input::get('searchterm').'%')->get();
return View::make("team.search-content", array('resp' => 'resultlist', 'teams_obj' => $teams_obj, 'persons_obj' => $persons_obj))->with('user', User::find(Auth::user()->id));
Now its getting a little more complicated. I have a database table "relation" which stores if a user is a member of a team via an entry containing user_id and team_id. Laravel knows this relation.
If the search result is displayed within the view, i have to make a distinction if the current user is already a member in the respective team which is displayed in the current row. If the user is already a member within the team he should not be able to apply, otherwise he should have the option to apply.
I solved it with this:
#foreach($teams_obj as $team_obj)
<li data-teamid="{{ $team_obj->id }}">
<span>{{ $team_obj->teamname }}</span>
<?php
$data = ['user_id' => $user->id, 'team_id' => $team_obj->id];
$res = $team_obj->whereHas('Relation', function($q) use ($data) {
$q->where('team_id', '=', $data['team_id']);
$q->where('user_id', '=', $data['user_id']);
})->get();
if (count($res) == 0) {
echo'apply fct available';
}
?>
</li>
#endforeach
I fetch the relation and check if the relation of team_id and user_id is existent. But i have a strange feeling doing this within my view template. What do you think? How can i improve this?
Additionally i think it is strange that i have to make $q->where('team_id'), as I already do $team_obj-> ... but otherwise it is not working correctly.
Any help is appreciated. Thanks!
Do you have any need to show teams that your user cannot apply ? if not you can simply modify your code to get teams that your user is not a member. If you need you can do some checkup in the controller in order to get that information.
I suggest making a foreach for the every team and checking if they have relationship with the user. You can set an attribute in a team to check in the view.
Controller:
foreach($teams_obj as $team_obj){
$res = $team_obj->whereHas('Relation', function($q) use ($data) {
$q->where('team_id', '=', $data['team_id']);
$q->where('user_id', '=', $data['user_id']);
})->get();
if(count($res) == 0)
$team_obj->isApplyableByUser = true;
else
$team_obj->isApplyableByUser = false;
// You can do the same code above in one line, but it's not that compreensive
$team_obj->isApplyableByUser = count($res) == 0;
}
View:
if($team_obj->isApplyableByUser) echo'apply fct available';
Yes, too much logic for a view (in terms of best practices)
Do you have relationships set up for these? Assuming Team hasMany('User')... Why not just eager load your User models?
$teams = Team::with(['users' => function($query){
$query->where('name', 'LIKE', '%'.Input::get('searchterm').'%')
->orWhere('vorname', 'LIKE', '%'.Input::get('searchterm').'%')
}])where('teamname', 'LIKE', '%'.Input::get('searchterm').'%')
->get();
return View::make('your.view', ['teams' => $teams]);
// And in your view.
#foreach($teams as $team)
<li data-teamid="{{ $team->id }}">
<span>{{ $team->teamname }}</span>
#if(!$team->users->count())
apply fct available
#endif
</li>
#endforeach
I am creating a search function in my Laravel 4 Application.
It is working great, in the fact that it is functioning well, the only thing that when I search for example in my postcode field and click search.
I want the value that I search to stay in the text input. Exactly like setting the value to be a php variable in standard PHP/HTML.
I have included my controller function and a text input field for you to see below. Any help would be greatly appreciated, thanks.
public function postSearch()
{
$search_order_from_date = Input::get('search_order_from_date');
$search_order_to_date = Input::get('search_order_to_date');
$search_order_type = Input::get('search_order_type');
$search_order_status = Input::get('search_order_status');
$search_order_agent = Input::get('search_order_agent');
$search_order_assessor = Input::get('search_order_assessor');
$search_order_postcode = Input::get('search_order_postcode');
$orders = DB::table('orders')
// ->where('order_date', '>=', $search_order_from_date, 'and', 'order_date', '<=', $search_order_to_date, 'or')
->orWhere('type', '=', $search_order_type)
->orWhere('epc_status', '=', $search_order_status)
->orWhere('agent', '=', $search_order_agent)
->orWhere('assessor', '=', $search_order_assessor)
->orWhere('postcode', '=', $search_order_postcode)
->orderBy('order_date', 'DESC')
->paginate();
Session::put('search', 'search query');
$users = User::all();
$userType = Session::get('type');
$perms = DB::table('permissions')->where('user_type', $userType)->first();
$this->layout->content = View::make('orders.index', compact('orders'), compact('perms'));
}
{{ Form::text('search_order_postcode', null, array('class'=>'form-control', 'placeholder'=>'Order Postcode')) }}
You can pass search_order_postcode to your view.
$this->layout->content = View::make('orders.index', compact('orders', 'search_order_postcode'), compact('perms'));
Add this in your index view or where ever the initial search form view is created, so you dont get an error if it does not exists.
Edit: Also pass it to your search view from you controller.
$search_order_postcode = (isset($search_order_postcode) && $search_order_postcode !== '') ? $search_order_postcode : null;
Then in your view:
// Search_order_postcode is either the value it was given or null
{{ Form::text('search_order_postcode', $search_order_postcode, array('class'=>'form-control', 'placeholder'=>'Order Postcode')) }}
Rinse repeat for other inputs, or store them in an array so you dont bloat your view::make, but this is personal preference.
I'm new to Laravel and I'm getting an error which I think has more to do with logic than anything else but I can't quite seem to grasp how to overcome it.
So, I have a page with a simple form to search for a particular string in my database. But I want to have the result show up on the same page.
Here's what I have so far:
This is my Route.php:
Route::get('/', 'HomeController#index');
Route::post('find', 'HomeController#find');
This is my HomeController:
public function index()
{
return View::make('index');
}
public function search()
{
return View::make('index');
}
public function find()
{
$match = Input::get('find');
if($match) {
$results = Book::where('title', 'like', '%'.$match.'%')
->orWhere('author', 'like', '%'.$match.'%')
->get();
return View::make('index', array('results', $results));
} else {
return Redirect::to('/')->with('flash_error', 'No string added!');
}
}
And my View (index.blade.php):
{{ Form::open(array('url' => 'find', 'method' => 'POST')) }}
{{ Form::text('find', '', array('class' => 'search-query', 'placeholder' => 'Search')) }}
{{ Form::submit('Submit', array('class' => 'btn btn-info')) }}
{{ Form::close() }}
#if (Session::has('flash_error'))
{{ Session::get('flash_error') }}
#endif
#foreach ($results as $result)
{{$result->title}}
#endforeach
(eventually the foreach will be replaced by some ajax loading to display each result)
And the error says "undefined variable: results" and shows the foreach.
I get why that error shows up since on the first pass to this page the results haven't been loaded yet but how can I overcome this? I really want the data to be shown on the same page without having to go to another page to display them.
Like I said, I think this is mostly logic related (although I'm very new to Laravel so it might be that too)
Any help would be greatly appreciated !
you need to pass an associative array as your second param of the make method
return View::make('index', array('results' => $results);
The problem here is that in your use of index.blade.php in multiple controllers, you forgot which controllers provide which variables (and as a result, which variables may be omitted).
When you request / (HomeController#index), index.blade.php is rendered, but since no $results are passed to the view, you see the Undefined Variable warning. This is not a problem in HomeController#find, because you define $results. To combat this, you'll need to do something along the lines of an isset() check on $results before you foreach over it. Like so:
#if(isset($results))
#foreach ($results as $result)
{{$result->title}}
#endforeach
#endif
Your logic may vary based on your page's layout (you might want to add an else and display some alternate placeholder content).
Also, if abstracting the call to View::make() with $results into index_gen() isn't keeping your code DRY, then I'd suggest replacing it in find() with the call to View::make().