I'm trying to display posts from the database, but i want to have the latest on top. This means I have to
do this inside of my HomeController.php:
$posts = Post::all()->sortByDesc('id');
return view('home', ['posts' => $posts]);
But when the site grows up, it might be complicated to find the particular post, so I decided to implement pagination. Unfortunately, pagination only works when I use this statement:
$posts = Post::paginate(10);
return view('home', ['posts' => $posts]);
When I'm trying to do things like that:
$posts = Post::all()->sortByDesc('id')->paginate(10);
My site throws an error, no matter what statement I use to display reversed posts and paginate them. Please help me and thank you guys for your every response.
You can use orderBy and pass 'DESC' to order the result in descending order.
$posts = Post::orderBy('id', 'DESC')->paginate(10);
Eloquent has a "latest" method that should help.
https://laravel.com/docs/7.x/queries#ordering-grouping-limit-and-offset
Related
Having Laravel 8 routing and controller issue
I'm bit new to laravel8 and got hang of it and I'm building a news portal as a project and learn at same time.
On the main index page I like to display some data such posts and categories and so on, where the data comes different tables in the db and from same controllers but different methods to the same route.
So I’m bit stuck here, the problem I’m having is that it’s not working
This is my code
Here are the routs
// main Index Page
Route::get('/','App\Http\Controllers\Home_pageController#categories);
// Index Latest Posts
Route::get('/','App\Http\Controllers\Home_pageController#homePageLatestPosts');
Methods in the Controllers
This is the method for displaying the latest posts in a sidebar
// Display latest limit by 10 the posts on home page
public function homePageLatestPosts(){
// $all_posts = Blogs::all();
$latest_posts = DB::table('blogs')->join('users', 'users.id', '=', 'blogs.added_by')->select('users.*','blogs.*')->orderBy('blogs.created_at', 'desc')->paginate(5);
// dd($latest_posts);
return view('welcome' , ['latest_posts'=>$latest_posts]);
}
// Show Categories
public function categories(){
$categories = DB::table('categories')->orderBy('category_name', 'desc')->get();
// dd($categories);
return view('welcome',['cats'=>$categories]);
}
I would like to know what the problem is and if there is a solution and if its the right approach that I', taking
I have googled around for a solution but not being able to solve it
thanks in advance
thanks for the responses.
i got a way around by fetching the data from DB in one method and passed them to the view for display.
use App\Models\Blog;
use App\Models\User;
use App\Models\Categories;
public function welcome(){
// Latest Posts
$latest_posts = DB::table('blogs')->join('users', 'users.id', '=', 'blogs.added_by')->select('users.*','blogs.*')->orderBy('blogs.created_at', 'desc')->paginate(10);
// Home Page Categories
$categories = DB::table('categories')->orderBy('category_name', 'desc')->get();
// Return
return view('welcome' , [ 'categories'=>$categories,'latest_posts'=>$latest_posts]);
}
I am trying to get a collection of categories only if they are in the products table. My categories table has 300 items. I only want a collection if a category is attached in the products table. The $categories collection should only result in about 10 categories because there are only about 10 products that have different category_ids
$products = DB::table('products')->groupBy('category_id')->get();
foreach($products as $product){
$categories[] = DB::table('categories')->where('id', '=', $product->category_id)->first();
}
$categories = collect($categories)->all();
Maybe I am going about this wrong and should use a different query builder method?
The end result $categories does get the results I am after but in my blade I get the "Trying to get property of non-object" error.
If using $categories in your blade file as a collection, you will need to remove the ->all() method.
->all() is converting the collection into an array after it is being created:
$categories = collect($categories);
You get Trying to get property of non-object because one of
DB::table('categories')->where('id', '=', $product->category_id)->first();
return null value.
You can fix it this way
$products = DB::table('products')->groupBy('category_id')->get();
$categories = collect();
foreach($products as $product){
$category = DB::table('categories')->where('id', '=', $product->category_id)->first();
if ($category) {
$categories->push($category);
}
}
If you want to get collection instance you must be use collect() helper method with array argument.
For example
collect($categories); // is_array(categories) is true
You are doing many request in foreach. That is not right way. Instead it you can achieve collection instance doing only 2 request.
$categoryIds = DB::table('products')->pluck('category_id')->toArray();
$categories = DB::table('categories')->whereIn('id', $categoryIds)->get();
See docs https://laravel.com/docs/5.8/queries#retrieving-results
This can be done with one simple eloquent query. There's no need to use query builder unless you're doing something overly complex (in my opinion).
whereHas() will only return Categories that have Products.
Categories::with('products')->whereHas('products')->get();
As long as the relationships are correct on the models the above is what you're looking for. As pointed out in the comments, you need models and relationships. Laravel uses the MVC pattern, and the first letter stands for model so I'm going to guess you're using them. If not let me know and I can help set those up because you should be using them.
And if you NEED to use the query builder clean that code up and use something like this so you don't have to worry about recollecting. Also check out the hydrate() method to change these generic class instances into instances of the Categories model.
DB::table('categories')->whereIn('id', function($q){
$q->select('category_id')->from('products');
})->get();
I am trying to make a filter in laravel. This following filter works
$posts= Post::where('category',$request->category)->orderBy('id','desc')->paginate(10);
But when I try to do something like this
public function index(Request $request)
{
$posts= Post::where('category',$request->category)->get();
$posts->latest()->paginate(10);
dd($posts);
It doesn't work. Can someone explain why is this and provide me the code that works. My project have multiple filter.
Error
Because $posts = Post::all(); already execute a query.
Post::where('category',$request->category)->latest()->paginate(10)->get();
would be what you want.
A note:latest requires the created_at column
You should go
$posts = Post::where('category',$request->category)->latest()->paginate(10);
the get request is unnecessary as the paginate will execute the query.
The first one makes the query by pagination i.e fetch 10 records per constructed page
For the second one, based on observation, you most likely have encountered at least 2 errors:
The first, on the line that used the get method because that method requires at least one parameter.
Type error: Too few arguments to function Illuminate\Support\Collection::get()
The other since its a collection, and since there is nothing like paginate or latest method on collection therefore throws other errors. You should check Collection's Available methods to have a glimpse of the methods allowed on collection.
One of the best solutions is to simply order the result when making the query:
Blog::where('category',$request->category)
->orderBy('created_at', 'desc') //you may use also 'updated_at' also depends on your need
->paginate(10);
This way you have the latest coming first int the pagination and also having not worrying about paginating a collection
I have been using the has method to query the existence of data in a related table and that is working just fine. Using the code example on the Laravel web site, you can do the following to get any post that has comments associated with it.
$posts = Post::has('comments')->get();
What I would like to be able to do, as an example, is query for any post which has comments from the last thirty days. Since the has method only has the ability to count related rows I am not sure of a good way to do this.
Ok, this is what I could come up with. It might not be the best solution, but it does work and doesn't seem too polluted. First, we'll need to add reference to Carbon and the Eloquent\Collection classes.
use \Carbon\Carbon;
use \Illuminate\Database\Eloquent\Collection;
Carbon does come with Laravel as a dependency, out of the box, but it would be smart to add it to your own project's dependencies anyway. Then, this code should do it:
// Gather all distinct 'post_id' from Comments made in the last 30 days
// along with its Post objects
$comments = Comment::with('Post')
->where('created_at', '>', Carbon::now()->subMonth())
->distinct()
->get(array('post_id'));
// Since we only want Posts, loop through the Comments collection and add
// the Posts to a new collection
$posts = new Collection;
foreach ($comments as $comment) {
$posts->add($comment->post);
}
From the Laravel 4 Documentation:
$posts= Post::with(array('comments' => function($query)
{
$query->where('published', '>=', 'date- 1 month'); //look date functions up
}))->get();
See Eager Load Constraints under laravel 4 documentation
I am Using Laravel 4:
I am trying to paginate an Eager Loaded Constraint, essentially I have a Topics Model which has a hasMany relationship to a Comments Model. This is all well and good and no problems with that. However I would like to be able to display a paginated table of the Comments (of which there will be hundreds) on the admins edit topic view. To do this I thought I would use the following code:
$topic = Topics::with( array( 'comments' => function($query)
{
$query->orderby('created_at', 'DESC');
$query->paginate(10);
} ) )
->where('id', $id)
->first();
Now this will provide me $topic with the correct object and inspecting $topic->comments shows it has the correct linked comments and is limited to 10 results. The pagination also responds to the GET page parameter and will paginate, however trying to echo $topic->comments->links() results in an error of method not found.
My work around for this is to have a second query which counts the attached comments and then using the following in my view:
$paginator = Paginator::make($topic->comments->toarray(), $commentCount, 10);
echo $paginator->appends(array('tab' => 'comments'))->links();
Is this a bug?
When you call paginate() on your eager constraint it is configuring the query for you (setting the skip and take). The paginator that is generated will actually be discarded.
Since you're just getting a single topic with its comments why not do this (same number of database calls)...
$topic = Topic::find($id);
$comments = $topic->comments()->order_by('created_at DESC')->paginate(10);
Admittedly, you won't be able to use $topic->comments to get the paginator, and will have to use $comments instead, but that's not a terrible thing.