I am working on a Laravel 8 app with users and posts.
I have a PostsController
and a FeaturedPostsController
.
I want to use the logic of the PostsController
inside the FeaturedPostsController
and only add to the child controller what is spaciffic to it. For this purpose, I have:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Post;
class PostsController extends Controller {
public function index(Request $request){
$viewData = $this->loadViewData();
$viewData['page_title'] = "Posts";
$viewData['posts'] = $this->posts($request);
return view('posts', $viewData);
}
}
namespace App\Http\Controllers;
use App\Http\Controllers\PostsController;
use Illuminate\Http\Request;
class FeaturedPostsController extends PostsController {
public function __construct(Request $request) {
parent::index($request);
}
public function index(Request $request){
$viewData['page_title'] = "Featured posts";
}
}
In the rotes file:
Route::get('/posts', [PostsController::class, 'index'])->name('posts');
Route::get('/featured-posts', [FeaturedPostsController::class, 'index']);
In the posts
view I have:
<h1 >{{ $page_title }}</h1>
The goal
The goal is to have "Featured posts" as page title page with on the /featured-posts
route.
In other words, I want $viewData['page_title'] = "Posts"
to be overwritten by $viewData['page_title'] = "Featured posts"
.
The problem
On the Featured posts page, I can't see the posts
view at all, unless I comment out the index
method of the FeaturedPostsController
.
Where is my mistake?
CodePudding user response:
1- You do not necessarily need two controllers. Since you have two routes, you can just point those to two different methods in the PostController. Also, you should not need to override the index method since featured posts would have a different logic, but if it does, you can move the repeating logic into another method. But, you most certainly do not need to have a constructor in the FeaturedController class and do not need to call parent's index class.
Suggested approach 1:
class PostsController extends Controller {
public function index(Request $request){
$viewData = $this->viewData($request, "Posts");
return view('posts', $viewData);
}
public function featuredPosts(Request $request){
$viewData = $this->viewData($request, "Featured Posts");
return view('posts', $viewData);
}
private function viewData($request, $pageTitle){
$viewData = $this->loadViewData(); //maybe you can use this existing function?
$viewData['page_title'] = $pageTitle;
$viewData['posts'] = $this->posts($request);
return $viewData;
}
}
//in route
Route::get('/posts', [PostsController::class, 'index'])->name('posts');
Route::get('/featured-posts', [PostsController::class, 'featuredPosts']);
2- If you must have two controllers, you could assign the title to a class variable in the PostController. So, suggestion 2:
class PostsController extends Controller {
public $title = "Posts";
public function index(Request $request){
$viewData = $this->loadViewData();
$viewData['page_title'] = $this->title;
$viewData['posts'] = $this->posts($request);
return view('posts', $viewData);
}
}
class FeaturedPostsController extends PostsController {
public function __construct(){
$this->title = "Featured Posts";
}
}
And since PostsController has an index method, you do not need to redeclare if no logic changes.