Content from a database Error

Hi again,

I have tried to to follow the steps from the Content from a database Guide and I keep running into the error: Invalid table: comments

I created a sample sqlite file which looks like this:

CREATE TABLE IF NOT EXISTS comments (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    slug TEXT,
    text TEXT,
    user TEXT
);

INSERT INTO comments (slug, text, user) VALUES
('comment-1', 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', 'User1'),
('comment-2', 'Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', 'User2');
    

my config file looks like this:

<?php

return [
    'debug' => true,
    'db' => [
        'type' => 'sqlite',
        'database' => '/Applications/MAMP/htdocs/plainkit-main-sqlite-test/site/storage/database/comments.sqlite'
    ]
];

my model file:

<?php


use Kirby\Uuid\Uuid;

class CommentsPage extends Page
{
    public function children(): Pages
    {
        if ($this->children instanceof Pages) {
            return $this->children;
        }

        $comments = [];

        foreach (Db::select('comments') as $comment) {
            $comments[] = [
                'slug'     => $comment->slug(),
                'num'      => 0,
                'template' => 'comment',
                'model'    => 'comment',
                'content'  => [
                    'text'  => $comment->text(),
                    'user'  => $comment->user(),
                    'uuid'  => Uuid::generate(),

                ]
            ];
        }

        return $this->children = Pages::factory($comments, $this);
    }
}

Everything else is copied from the guide into the plainkit. After hours of trying I don’t know what I can do to solve this issue. Any ideas?

When you open the database in an SQLite viewer, is the table there? No typo or so?

On a side note, I’d wouldn’t use the absolute path to the database file, but relative to your project, so

	'db' => [
		'type' => 'sqlite',
		'database' => __DIR__ . '/../storage/database/comments.sqlite'
	],

Otherwise, it will fail when you deploy.

Should add that I did a quick test and worked fine.

1 Like

Thank you for checking! In fact the sqlite file formatting I used seemed to be incompatible. I managed to make it work with a new database file.

I now proceeded to follow the Guide for the advanced setup to allow for changing the status in the panel. It works fine but if I try to create a new page from the panel the browser only displays this code after submitting:

{"$dialog":{"component":"k-page-create-dialog","props":{"blueprints":[{"name":"comment","title":"Comment"},{"name":"comments","title":"Comments"},{"name":"default","title":"Default Page"}],"fields":{"title":{"label":"Title","type":"text","icon":"title","required":true,"preselect":true},"slug":{"label":"URL appendix","type":"slug","allow":"a-z0-9","required":true,"sync":"title","path":"\/"},"parent":{"hidden":true},"section":{"hidden":true},"template":{"hidden":true},"view":{"hidden":true}},"submitButton":"Create as Draft","template":"comment","value":{"parent":"site","section":null,"slug":"","template":"comment","title":"","view":null}},"code":200,"path":"dialogs\/pages\/create","query":[],"referrer":"\/"}}

When I return to the Panel it gives the error message: “undefined is not an object (evaluating ‘n.json’)”

any idea why?

No, have you added/adapted the table columns as in the documentation?

If you do everything step by step as explained, it will work.

I am pretty sure that my table is formatted as required in the documentation…?

CREATE TABLE "comments" (
	"id"	INTEGER UNIQUE,
	"slug"	VARCHAR(185) UNIQUE,
	"text"	VARCHAR(600),
	"user"	VARCHAR(255),
	"status"	VARCHAR(8),
	"title"	VARCHAR(185),
	PRIMARY KEY("id")
);

Bildschirmfoto 2024-02-18 um 13.07.41

I tried changing the order and some other parameters but problem persists. When I use the first comment.php model from the documentation I can create new pages without problems.

You are right, I was being stupid. need to look into it.

1 Like

I also realised that when I change the status of a page in the panel from listed to unlisted, the database value changes to null, but the pages remain visible in the frontend.

This is the code of my model file comment.php (as copied from the Documentation)

<?php

class CommentPage extends Kirby\Cms\Page
{
    public function changeSlug(string $slug, string|null $languageCode = null): static
    {
        // always sanitize the slug
        $slug = Str::slug($slug);

        $data['slug'] = $slug;

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

        return $this;
    }

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

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

        return $this;
    }

    protected function changeStatusToListed(int|null $position = null): static
    {
        // 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()])) {
            Db::update('comments', $data, ['slug' => $this->slug()]);
        }

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

        return $this;
    }

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

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

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

        $this->resortSiblingsAfterUnlisting();

        return $this;
    }

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

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

        return $this;
    }

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

    public function isDraft(): bool
    {
        return in_array($this->content()->status(), ['listed', 'unlisted']) === false;
    }

    public function writeContent(array $data, string|null $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);
        }
    }
}

Ok, I could narrow it down to the isDraft() method which causes a memory issue. Deleting that method seems to solve the issue.

1 Like

Great, thank you! This solved the issue of page creation. The only problem left now is that changing the status in the panel changes the value in the database but doesn’t actually affect the pages displayed in the frontend.

I guess you have to filter what you query as children, children should not include drafts, so you need a where clause to filter by status.

Then you should also create a drafts method in the parent model that returns the drafts.

1 Like