Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

MoFish's avatar

Get Page and Comments

Hi,

How can I get all data from a 'pages' table, along with data from a 'sections' table?

I have the following code which has a hadMany relationship.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Page extends Model
{
    // Table Name
    protected $table = 'page';

    public function sections(){
        return $this->hasMany('App\Section');
    }

}

I am then using the following to try to get the 'pages' data, along with the sections data.

        // get pages
        $data = Page::find(1)->sections;
        print_r($data);

The page sections table has a page with a 'page_id' with the same id.

Thanks,

MoFish

0 likes
30 replies
tykus's avatar

Since you have the relationship defined on the Page model, you can eager-load the sections using with:

$page = Page::with('sections')->find(1);

Now, you have a $page model instance with a sections property containing a Collection of Section instances.

$page->sections // Collection
MoFish's avatar

Hi tykus, thanks for taking the time to reply.

I now have the following code which works fine and spits out everything I need.

$data = Page::with('sections')->find(1);
echo "<pre>";
print_r($data);
echo "</pre>";

How do I access the 'page' data in my view? i'm passing in $data to my view and have tried accessing $data->name which should have a value from my pages table.

Thanks,

MoFish

tykus's avatar

Assuming you have a controller which handles a request to the particular URI:

// web.php
Route::get('/pages/{id}', 'PageController@show');
// PageController.php
public function show($id)
{
    $page = Page::with('sections')->find($id);

    return view('pages.show', ['page' => $page]);
}

And the view:

// resources/views/pages/show.blade.php

{{ $page->name }}
MoFish's avatar

Sorry to make it a little more complicated, I previously used the following in my RouteServiceProvider which worked well, but didn't get all the data back from the other table.

        $data = Page::all();
        foreach ($data as $d){
            Route::view($d->uri, 'web.masterpage', [
                'data' => $d, 
            ]);
        }

I have now amended this to try to use the code you provided.

        $data = Page::all()->with('sections'); // doesnt work
        $data = Page::with('sections')->all(); // doesnt work
        $data = Page::with('sections')->find(1); // hard coded finds the data - but isn't ideal

However the following bit $d->uri throws an error in this case, as i'm not sure how best to access it.

Route::view($d->uri, 'web.masterpage', [

Trying to get property 'uri' of non-object

tykus's avatar

Not sure what exactly you are trying to achieve in the RouteServiceProvider; dynamic route registration?

If you wanted to get all of the page records along with the associated sections, then this is the query you would run.

Page::with('sections')->get();
MoFish's avatar

That worked perfect thank you.

Yes, I'm trying to do some automatic routing for the front-end of the website based on the uri path in the database. I did a bit of reading and seen that it was a popular way to do it, so went down that path.

In theory i could have created a route as you suggested

Route::get('/pages/{id}', 'PageController@show');

However would want it to route based on the route being something like '/{id}'

I need to re-visit this if you feel my method is a bit of an overhead.

        // get pages
        $data = Page::with('sections')->get();       
        foreach ($data as $d){
            Route::view($d->uri, 'web.masterpage', [
                'data' => $d, 
            ]);
        }

Thanks for your help.

tykus's avatar

You are having to register routes on the fly, which wouldn't necessarily be efficient, and it is hiding your API - most devs will go straight to the web.php and api.php files to see the public API for your app, but yours is hidden in the RouteServiceProvider.

As an alternative, you could simply have a catch-all route for pages:

// all other route

Route::get('{page}', 'PageController@show');

You would basically be passing any unmatched URIs into thePageController's show method. You could change the key for finding a Page model to uri:

// Page.php

public function getRouteKeyName()
{
    return 'uri';
}

Now, your show action can Route-Model bind a Page instance based on the uri (which as a result should be unique on the pages table):

// PageController.php

public function show(Page $page)
{
    // since you already have the page, you can lazy-load the related sections
    $page->load('sections');

    return view('pages.show', ['page' => $page]); 
}

Note: this has the limitation that a Page uri cannot be the same as another URI defined in your routes, because the other URI will be matched first, but you will suffer from that with your existing solution in any case.

MoFish's avatar

Hello tykus,

Thanks again for taking the time to respond to me.

I'll look into this later on tonight and let you know how I get on.

I take your guidance on-board, as this does appear to be a better way forward.

Thanks again,

MoFish

MoFish's avatar

Hi tykus,

"As an alternative, you could simply have a catch-all route for pages:"

Adding the following into the routes/web.php doesn't work for me. Should {page} be inside single quotes? e.g '{page}'

// all other route

Route::get({page}, 'PageController@show');
Cronix's avatar

Yes it should. It should also be the very last route in your routes file since it will match everything.

Route::get('{page}', 'PageController@show');
MoFish's avatar

Hello,

I have put that into the routes file and commented out my previous nasty'ness outlined above. A 'php artisan route:list' shows the following which appears correct, however when hitting any URL such as http://lara/homepage it does not appear to hit my show function in my PageController.

 GET|HEAD | {page}   |      | App\Http\Controllers\Web\PageController@show | web  
<?php

namespace App\Http\Controllers\Web;

use App\Page;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PageController extends Controller
{
    public function getRouteKeyName()
    {
        return 'uri';
    }

    public function show(Page $page)
    {

        return "here";
        
        // since you already have the page, you can lazy-load the related sections
        // $page->load('sections');
        // return view('pages.show', ['page' => $page]); 
    }

}
tykus's avatar

This should be in the Page model

    public function getRouteKeyName()
    {
        return 'uri';
    }

Perhaps you have gotten a ModelNotFoundException instead, or, do you have another route which matches /homepage?

MoFish's avatar

Hi tykus,

I don't have any other routes defined which would match this.

PageController

<?php

namespace App\Http\Controllers\Web;

use App\Page;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PageController extends Controller
{
    public function show(Page $page)
    {
        return "here";
        // since you already have the page, you can lazy-load the related sections
        //$page->load('sections');
        //return view('pages.show', ['page' => $page]); 
    }
}

Page Model

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Page extends Model
{
    // Table Name
    protected $table = 'page';

    // Primary Key
    protected $primaryKey = 'id';

    // TimeStamps
    public $timestamps = true;

    public function getRouteKeyName()
    {
        return 'uri';
    }

    public function sections(){
        return $this->hasMany('App\Section');
    }

}

Web.php

<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

//Route::resource('/', 'Web\PageController');


Route::get('{page}', 'Web\PageController@show');
Cronix's avatar

try running composer dumpautoload and php artisan route:clear

MoFish's avatar

Hi cronix, that didn't help unfortunately.

Cronix's avatar

Try changing to

public function show($page)

for testing, so it doesn't try to load the actual model

Cronix's avatar

Ok, so now change to

public function show($page) {
    return $page;
}

compare that result to what the data in the uri column in the page table looks like.

It's trying to match that value to the uri column because you have this:

public function getRouteKeyName()
{
    return 'uri';
}

So if they don't match exactly, it can't load the model.

MoFish's avatar

Looks like the problem is due to my uri for the homepage being '/' as the contact page appears correct which is '/contact'.

Cronix's avatar

What does $page show when you go to the homepage, just an empty string, or is it "/"? If it's an empty string, you could try making that the uri for the homepage in the db?

MoFish's avatar

Hi Cronix,

When visiting 'http://lara/contact' i get a response from $page to the browser with the uri appearing as '/contact' from the db which is correct and receiving the data OK.

When I visit 'http://lara' to get the homepage, i get the following message.

'Sorry, the page you are looking for could not be found. '.

I have tried entering '/' and '' into the DB without success.

MoFish

Cronix's avatar

Not sure, I haven't tried to do what you're doing with a single catch-all route. You didn't say what the result of $page was when going to the homepage (like just return $page in the controller and not trying to load the model). I'd probably just make a separate route for the homepage and the catch-all route for everything else.

Route::get('/', 'PageController@home');
Route::get('{page}', 'PageController@show');

or something, and then just make a "home" method to show the homepage, without using route-model-binding on that home method.

MoFish's avatar

I can't seem to get the result of $page to appear in the browser from the controller, it pushes me to a 404 page not found message without displaying the result. I'm happy to have another route for the homepage for the time being.

Thanks to both yourself and tykus for your help.

Cronix's avatar

It's probably showing a 404 instead of the returned value for $page because you put the Page model back in the method parameters instead of just $post? So it's actually trying to load the model? Like

public function show(Page $page) {

instead of

public function show($page) {

If it's using (Page $page), and it can't find the model associated with the $page variable being passed in from {page} in the route, it will 404.

MoFish's avatar

Hi Cronix,

I'm not referencing the page model. When you hit the root website it throws the 404 page not found. It must be something with the route in particular which needs a value specified in the url?

<?php

namespace App\Http\Controllers\Web;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PageController extends Controller
{
    public function show($uri)
    {
        return $uri;
    }
}
<?php

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('{page}', 'Web\PageController@show');
tykus's avatar

What URI are you requesting?

tykus's avatar
tykus
Best Answer
Level 104

Ok... I see, so the page wildcard should be optional in that case.

Route::get('{page?}', 'Web\PageController@show');

and make sure it is optional in the action parameter also:

public function show(Page $page = null)
{
    // since $page is null, you know you need the home page
}
MoFish's avatar

Hi tykus,

Thanks very much.

Changing the route to include the question mark and adding a '/' as the uri parameter fixed it.

public function show($uri = '/')
Shahrukh4's avatar

Try this,

public function yourFunction(){
   $data = Page::where('id', $request->id)
   ->with('section')
   ->first();
}

Please or to participate in this conversation.