Database demo, add new page and change page url/slug does not work

Hi all,

i have a problem with the demo database tutorial:
https://getkirby.com/docs/guide/virtual-pages/content-from-database

Adding a new page does not work also change the page slug does not work.

app.js:1 {status: “error”, route: “pages/([a-zA-Z0-9.-_%= +@()]+)”, exception: “Kirby\Exception\NotFoundException”, message: “Die Seite “items/asdasdasd” konnte nicht gefunden werden”, key: “error.page.notFound”, …}

Edit the content works.

class ItemsPage extends Kirby\Cms\Page
{
    public function children()
    {
        $items= [];

        foreach (Db::select('items') as $item) {
            $items[] = [
                'slug'     => $item->slug(),
                'num'      => 0,
                'template' => 'item',
                'model'    => 'item',
                'content'  => [
                    'name'  => $item->name(),
                    'zip'   => $item->zip(),
                ]
            ];
        }

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


class ItemPage extends Kirby\Cms\Page
{

    public function writeContent(array $data, string $languageCode = null): bool
    {
        unset($data['title']);

        if ($item = Db::first('items', '*', ['slug' => $this->slug()])) {
            return Db::update('items', $data, ['slug' => $this->slug()]);
        } else {
            $data['slug'] = $this->slug();
            return Db::insert('items', $data);
        }

    }

    public function delete(bool $force = false): bool
    {
        return Db::delete('items', ['slug' => $this->slug()]);
    }

    public function title(): Kirby\Cms\Field
    {
        return $this->text()->excerpt(100)->or('New item');
    }

}

any ideas?

@peterp Have you sorted this out? Haven’t got round to looking into it but will as soon as possible if it doesn’t work anymore.

Hi,

it still does not work.

Thank you very much!

any news?

Oops, sorry, I forgot. However, I made a test with another database recently, and that worked as expected. I’ll test the example from the cookbook today, but my guess is that the problem might be caused by wrong data type definitions.

Ok, the example should work, could you post your table scheme?

You have to make sure that the user and text fields are not required in the database and that the id field is the primary key and auto-increment.

Hi,

NOT required, thats important! Works now! Thanks alot!

KR

…but changing the url from the … menu does not work. i am getting a 200: “status”:“ok”
but the slug does not change in the DB.

changing the page status results in: {status: “error”, exception: “Whoops\Exception\ErrorException”, code: 1, message: “Nesting level too deep - recursive dependency?”, details: null, …}

can you share a table structure example where everything works?

thanks alot!

The comment model has status and url set to false in the options. If you want to allow that, you would have to extend the model with the changeStatus() and changeSlug() methods. For the status, you would also need an additional field in your database.

Kirby’s page methods work with the filesystem. Therefore, <ou have to create a model for every action that usually does something in the filesystem and change what these methods do to the stuff that has to be done in the database instead. So the changeSlug() method would have to update the slug field in the database.

Hi,

changingSlug works now.
saving the new status and position works! But not loading the new status, it shows always the green icon: “listed”

    foreach (Db::select('items') as $item) {
            $items[] = [
                'slug'     => $item->slug(),
                'num'      => $item->num(),
                'template' => 'item',
                'model'    => 'item',
                //'status'    => $item->status(),
                //'isDraft'    => ($item->status() === 'draft' ? true : false),
                //'isUnlisted' => ($item->status() === 'unlisted' ? true : false),
                'content'  => [
                    'name'  => $item->name(),
                    'zip'   => $item->zip(),
                ]
            ];
        }

Hm, I haven’t found a solution yet. One thing is the number scheme that has to be set according to status, it seems. But that alone doesn’t do the job. Then probably the isDraft() method.

hmm seems not to be the isDraft() method, strange.

 'status'    => 'draft',
 'isDraft'    => true
 'isUnlisted' => false

Green icon…

My models now look like this:

comments.php:

<?php

class CommentsPage extends Kirby\Cms\Page
{
    public function children()
    {
        $comments = [];

        foreach (Db::select('comments') as $comment) {
                        
            $comments[] = [
                'slug'     => $comment->slug(),
                'num'      => $comment->status() === 'listed' ? 0 : null,
                'template' => 'comment',
                'model'    => 'comment',
                'content'  => [
                    'text'   => $comment->text(),
                    'user'   => $comment->user(),
                    'status' => is_null($comment->status()) ? 'draft' : $comment->status()
                ]
            ];
        }

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

comment.php

<?php

class CommentPage extends Kirby\Cms\Page
{
    public function isDraft(): bool
    {
        return in_array($this->content()->status(), ['listed', 'unlisted']) === false;
    }

    public function changeSlug(string $slug, string $languageCode = null)
    {
        // always sanitize the slug
        $slug = Str::slug($slug);


        $data['slug'] = $slug;
        
        if ($comment = Db::first('comments', '*', ['slug' => $this->slug()])) {
            if (Db::update('comments', $data, ['slug' => $this->slug()])) {
                return $this;
            };
        } 
        return $this;
    }

    protected function changeStatusToDraft()
    {
        $data['status'] = 'null';

        if ($comment = Db::first('comments', '*', ['slug' => $this->slug()])) {
            return Db::update('comments', $data, ['slug' => $this->slug()]);
        }

        return $this;
    }

    protected function changeStatusToListed(int $position = null)
    {
        // create a sorting number for the page
        $num = $this->createNum($position);

        // don't sort if not necessary
        if ($this->status() === 'listed' && $num === $this->num()) {
            return $this;
        }

        $data['status'] = 'listed';

        if ($comment = Db::first('comments', '*', ['slug' => $this->slug()])) {
            return Db::update('comments', $data, ['slug' => $this->slug()]);
        }

        if ($this->blueprint()->num() === 'default') {
            $this->resortSiblingsAfterListing($num);
        }

        return $this;
    }

    protected function changeStatusToUnlisted()
    {
        if ($this->status() === 'unlisted') {
            return $this;
        }

        $data['status'] = 'unlisted';

        if ($comment = Db::first('comments', '*', ['slug' => $this->slug()])) {
            return Db::update('comments', $data, ['slug' => $this->slug()]);
        }

        $this->resortSiblingsAfterUnlisting();

        return $this;
    }
    public function changeTitle(string $slug, string $languageCode = null)
    {
        // always sanitize the slug
        $slug = Str::slug($slug);


        $data['slug'] = $slug;
        
        if ($comment = Db::first('comments', '*', ['slug' => $this->slug()])) {
            if (Db::update('comments', $data, ['slug' => $this->slug()])) {
                return $this;
            };
        } 
        return $this;
    }

    public function delete(bool $force = false): bool
    {
        return Db::delete('comments', ['slug' => $this->slug()]);
    }

    public function title(): Kirby\Cms\Field
    {
        return $this->text()->excerpt(100)->or('New comment');
    }

    public function writeContent(array $data, string $languageCode = null): bool
    {
        unset($data['title']);

        if ($comment = Db::first('comments', '*', ['slug' => $this->slug()])) {
            return Db::update('comments', $data, ['slug' => $this->slug()]);
        } else {
            $data['slug'] = $this->slug();
            return Db::insert('comments', $data);
        }

    }

}

comment.yml blueprint:

title: Comment
icon: 📢

options:
  title: false
  status: true
  url: true

fields:
  user:
    label: User
    type: text
  text:
    label: text
    type: textarea
  # just for control purposes
  status:
    label: Status
    type: text
    disabled: true

Let me know if that works for you as well or what issues you encounter with this setup.

Hi your code works, thanks alot!

with this two changes you can also add the position number:
comments.php :
'num' => $comment->status() === 'listed' ? $comment->num() : null,

comment.php

   protected function changeStatusToListed(int $position = null){
     // create a sorting number for the page
     $num = $this->createNum($position);

     // don't sort if not necessary

     if ($this->status() === 'listed' && $num === $this->num()) {
         return $this;
     }

     $data['status'] = 'listed';
     $data['num'] = $position;

     if ($range = Db::first('comments', '*', ['slug' => $this->slug()])) {
         return Db::update('comments', $data, ['slug' => $this->slug()]);
     }

     if ($this->blueprint()->num() === 'default') {
         $this->resortSiblingsAfterListing($num);
     }

     return $this;
 }

and your change title method also changes the slug:

public function changeTitle(string $title, string $languageCode = null){
    $data['title'] = $title;

    if ($range = Db::first('comments', '*', ['slug' => $this->slug()])) {
       if (Db::update('comments', $data, ['slug' => $this->slug()])) {
           return $this;
       };
    }
    return $this;
}

I have changed things in the final version: https://getkirby.com/docs/guide/virtual-pages/content-from-database#advanced-setup

Hello again,

i have updated my kirby installation to 3.3.4 and now i am not able to add new pages (database).

{status: “error”, message: “Die Seite “items/test” konnte nicht gefunden werden”, code: 404, exception: “Kirby\Exception\NotFoundException”, key: “error.page.notFound”, …}

my database is still the same. Did you change something?

There shouldn’t be any breaking changes in 3.3.4. From which version did you update?

The error message just means that a page cannot be found. But without any information, what page that is and how it relates to the virtual pages guide, it’s hard to tell.

Hi,

3.2.x i guess. Title was not null. It is really important to set its default null!

thx!

the only last think is when you add a new page the title won’t be saved. it says always New Comment and the title is null in the database.

Tested with a new installation and copy&paste from the doku.