Virtual Pages, CSV, and blank rendering

I have a CSV file with about 100 rows and 8 columns. I want to create a “user” for each row. I am attempting to follow this virtual pages guide, and it seems to mostly be going OK aside from the students aren’t being listed.

content -> home -> home.txt
-> home.csv

/site/plugins/helpers/index.php

    <?php
        function csv(string $file, string $delimiter = ','): array
        {
        $lines = file($file);
    
        $lines[0] = str_replace("\xEF\xBB\xBF", '', $lines[0]);
    
         $csv = array_map(function($d) use($delimiter) {
            return str_getcsv($d, $delimiter);
             }, $lines);
    
         array_walk($csv, function(&$a) use ($csv) {
            $a = array_combine($csv[0], $a);
        });
     
        array_shift($csv);
    
        return $csv;
    }

/site/models/home.php

    <?php
    
    class StudentPage extends Page
    {
    
        public function children()
        {
            $csv      = csv($this->root() . '/home.csv', ';');
            $children = array_map(function ($student) {
                 return [
                    'slug'     => Str::slug($student['csenetid']),
                    'template' => 'home',
                    'model'    => 'home',
                    'num'      =>  $student->indexOf($students),
                    'content'  => [
                        'fname'     => $student['fname'],
                        'lname'     => $student['lname'],
                        'nickname'  => $student['nickname'],
                        'csenetid'  => $student['csenetid'],
                        'cohort_yr' => $student['cohort_yr'],
                    ]
                ];
            }, $csv);
    
            return Pages::factory($children, $this);
        }
    
    }

/site/templates/home.php

    <?php snippet('header') ?>
    
    <main>
      <h1><?= $page->title() ?></h1>
    
      <ul class="students">
        <?php foreach ($page->children() as $student): ?>
        <li>
          <a href="<?= $student->url() ?>">
            <?= $student->csenetid() ?>
          </a>
        </li>
        <?php endforeach ?>
      </ul>
    
    </main>
    
    <?php snippet('footer') ?>

/site/templates/student.php

    <?php snippet('header') ?>
    
    <article class="student">
      <h1 class="student-csenetid"><?= $page->title() ?></h1>
      <p class="student-fname">first name: <?= $page->fname() ?></p>
      <p class="student-lname">last name: <?= $page->lname() ?></p>
      <p class="student-nickname">nickname: <?= $page->nickname() ?></p>
      <p class="student-cohort_yr">cohort_yr: <?= $page->cohort_yr() ?></p>
    </article>
    
    <?php snippet('footer') ?>

I am just getting a blank home where the list of children pages should be. What do I have wrong?

If you want to create model for the home page witth a template called home, you model must also be called HomePage, not StudentPage. Note that the template and model for the children should be student not home.

1 Like

Thank you for your help!

I changed my model to:

class HomePage extends Page
{

    public function children()
    {
        $csv      = csv($this->root() . '/home.csv', ';');
        $children = array_map(function ($student) {
            return [
                'slug'     => Str::slug($student['csenetid']),
                'template' => 'student',
                'model'    => 'student',
                'num'      =>  0,
                'content'  => [
                    'fname'     => $student['fname'],
                    'lname'     => $student['lname'],
                    'nickname'  => $student['nickname'],
                    'csenetid'  => $student['csenetid'],
                    'cohort_yr' => $student['cohort_yr'],
                ]
            ];
        }, $csv);

        return Pages::factory($children, $this);
    }

}

I am still receiving a blank screen. :expressionless:

Your students don’t have a title field. Better try one of the fields you have defined in your model. Or do a

dump($page->children());

outside the loop to see if you get any results.

1 Like

I appreciate your patience. I keep trying to follow the logic to fix things, but I am not having any success.

templates/home.php

<main>
  <h1><?= $page->title() ?></h1>

  <ul class="students">
    <?php foreach ($page->children() as $student): ?>
    <li>
      <a href="<?= $student->url() ?>">
        <?= $student->csenetid() ?>
      </a>
    </li>
    <?php endforeach ?>
  </ul>

</main>

templates/student.php

<article class="student">
  <p class="student-csenetid">csenetid: <?= $page->csenetid() ?><p>
  <p class="student-fname">first name: <?= $page->fname() ?></p>
  <p class="student-lname">last name: <?= $page->lname() ?></p>
  <p class="student-nickname">nickname: <?= $page->nickname() ?></p>
  <p class="student-cohort_yr">cohort_yr: <?= $page->cohort_yr() ?></p>
</article>

Ia it the student-url()? I thought the slut item in the model home.php, but maybe not?

What do you get on the frontend home page if you put

dump($csv);

into your home.php page model directly after defining the $csv variable in the children() method?

1 Like

I tried the dump($page->children()); you suggested earlier. Thinking it very well could be my csv file isn’t being read correctly.

class HomePage extends Page
{

    public function children()
    {
        $csv      = csv($this->root() . '/home.csv', ';');
        $children = array_map(function ($student) {
            return [
                'slug'     => Str::slug($student['csenetid']),
                'template' => 'student',
                'model'    => 'student',
                'num'      =>  0,
                'content'  => [
                    'fname'     => $student['fname'],
                    'lname'     => $student['lname'],
                    'nickname'  => $student['nickname'],
                    'csenetid'  => $student['csenetid'],
                    'cohort_yr' => $student['cohort_yr'],
                ]
            ];
        }, $csv);

        dump($page->children());

        return Pages::factory($children, $this);
    }

}

I received the following error ‘Call to a member function children() on null’. To me, that says that yes the csv file is not being read right, would you agree?

You can’t use $page in this context (should be $this), as I said you should have put this in the home template, not inside the children method. What I said in my last post is to dump $csv to make sure it returns an array of items from the csv file.

My apologies for misunderstanding! On the homepage I get the following with a correct number of additional rows, edited to keep real info hidden:

Array
(
    [0] => Array
        (
            [fname,lname,nickname,csenetid,cohort_yr] => Fat,Mushroom,,fatmushroom,2019
        )

That’s what I thought, it is not the expected output. Looks like your csv file uses a comma as separator, while you tell the csv function you want to use a semi-colon.

$csv      = csv($this->root() . '/home.csv', ';');

Is debugging set to true in your config? Your model should actually throw an error.

1 Like

OMG! I tried to change that earlier, but it didn’t work so I changed it back. :rofl:

I so appreciate your help. I have the array list output, and then all the student-csenetid links.

I am sure you will see me around here often, as I am working on a project! :crossed_fingers:

this is very helpful!
I’m just wondering if this model does also add the csv in the content folder as subpages. is there any way to do this?

Do you mean to have children of the site, i.e. first level pages instead of children of a given page?

I mean if the content folder is also add this information. Meaning if I take out this CSV file would the pages be still there?

If you use virtual pages, the pages will only be there as long as the file is there.

The alternative would be to actually create pages in the file system from data in the csv file. Then you can remove the csv file and the pages will still be there.