Introduction

In this chapter, we'll step by step to create a simple blog system, that helps you understand how to use phoenix.

Create Admin Package

First, we have to create a basic blog admin package. please type this command:

php windwalker muse init Blog/Admin category.categories
php windwalker muse add-subsystem Blog/Admin article.articles
php windwalker muse add-subsystem Blog/Admin comment.comments

After package created, register package and add assets link.

// etc/app/windwlaker.php

// ...

    'packages' => [
        // ...
        'phoenix' => \Phoenix\PhoenixPackage::class,
        'admin' => \Blog\Admin\AdminPackage::class
    ]

// ...
$ php windwalker asset sync admin

And add routing to /etc/routing.yml.

## /etc/routing.yml

## ...

admin:
    pattern: /admin
    package: admin

Migration

Open src/Blog/Admin/*.php files, change migration like below:

// src/Blog/Admin/xxxxxxxxxxxxxx_CategoryInit.php

// ...

class CategoryInit extends AbstractMigration
{
    public function up()
    {
        $this->createTable(Table::CATEGORIES, function (Schema $schema)
        {
            $schema->primary('id')->unsigned()->notNull()->comment('Primary Key');
            $schema->varchar('title')->comment('Title');
            $schema->varchar('alias')->comment('Alias');
            $schema->integer('ordering');
            $schema->tinyint('state');
            $schema->datetime('created')->comment('Created Date');
            $schema->integer('created_by')->comment('Author');
            $schema->datetime('modified')->comment('Modified Date');
            $schema->integer('modified_by')->comment('Modified User');
            $schema->char('language')->length(7)->comment('Language');
            $schema->text('params')->comment('Params');

            $schema->addIndex('alias');
            $schema->addIndex('language');
            $schema->addIndex('created_by');
        });
    }

    public function down()
    {
        $this->drop(Table::CATEGORIES, true);
    }
}
// src/Blog/Admin/xxxxxxxxxxxxxx_ArticleInit.php

class ArticleInit extends AbstractMigration
{
    public function up()
    {
        $this->createTable(Table::ARTICLES, function(Schema $schema)
        {
            $schema->primary('id')->comment('Primary Key');
            $schema->integer('category_id');
            $schema->varchar('title')->comment('Title');
            $schema->varchar('alias')->comment('Alias');
            $schema->varchar('url')->comment('URL');
            $schema->text('introtext')->comment('Intro Text');
            $schema->text('fulltext')->comment('Full Text');
            $schema->varchar('image')->comment('Main Image');
            $schema->tinyint('state')->signed(true)->comment('0: unpublished, 1:published');
            $schema->integer('ordering')->comment('Ordering');
            $schema->datetime('created')->comment('Created Date');
            $schema->integer('created_by')->comment('Author');
            $schema->datetime('modified')->comment('Modified Date');
            $schema->integer('modified_by')->comment('Modified User');
            $schema->char('language')->length(7)->comment('Language');
            $schema->text('params')->comment('Params');

            $schema->addIndex('alias');
            $schema->addIndex('language');
            $schema->addIndex('created_by');
        });
    }

    public function down()
    {
        $this->drop(Table::ARTICLES);
    }
}
// src/Blog/Admin/xxxxxxxxxxxxxx_CommentInit.php

class CommentInit extends AbstractMigration
{
    public function up()
    {
        $this->createTable(Table::COMMENTS, function(Schema $schema)
        {
            $schema->primary('id')->comment('Primary Key');
            $schema->integer('article_id');
            $schema->varchar('name')->comment('Name');
            $schema->varchar('alias')->comment('Alias');
            $schema->varchar('email')->comment('Email');
            $schema->text('introtext')->comment('Intro Text');
            $schema->text('fulltext')->comment('Full Text');
            $schema->varchar('image')->comment('Main Image');
            $schema->tinyint('state')->signed(true)->comment('0: unpublished, 1:published');
            $schema->integer('ordering')->comment('Ordering');
            $schema->datetime('created')->comment('Created Date');
            $schema->integer('created_by')->comment('Author');
            $schema->datetime('modified')->comment('Modified Date');
            $schema->integer('modified_by')->comment('Modified User');
            $schema->char('language')->length(7)->comment('Language');
            $schema->text('params')->comment('Params');

            $schema->addIndex('alias');
            $schema->addIndex('language');
            $schema->addIndex('created_by');
        });
    }

    public function down()
    {
        $this->drop(Table::COMMENTS);
    }
}

Run migration:

php windwalker migration migrate -p=admin

Now you can open http://{your_site}/admin/categories to see your admin page.

Fake Data

We must add some fake data to help us developing. Use seeder to do this work, please modify src/Blog/Admin/Seed/*.php files.

First check that the seeder ordering is CategorySeeder -> ArticleSeeder -> CommentSeeder in MainSeeder.

// src/Blog/Admin/MainSeeder.php

// ...

class MainSeeder extends AbstractSeeder
{
    /**
     * doExecute
     *
     * @return  void
     */
    public function doExecute()
    {
        $this->execute(CategorySeeder::class);

        $this->execute(ArticleSeeder::class);

        $this->execute(CommentSeeder::class);

        // @muse-placeholder  seeder-execute  Do not remove this.
    }

    // ...

Then add modify all other seeder class to:

// src/Blog/Admin/Seed/CategorySeeder.php

// ...

class CategorySeeder extends AbstractSeeder
{
    public function doExecute()
    {
        $faker = Factory::create();

        foreach (range(1, 7) as $i)
        {
            $data = new Data;

            $data['title']       = $faker->word;
            $data['alias']       = OutputFilter::stringURLSafe($data['title']);
            $data['version']     = rand(1, 50);
            $data['created']     = $faker->dateTime->format($this->getSqlFormat());
            $data['created_by']  = rand(20, 100);
            $data['modified']    = $faker->dateTime->format($this->getSqlFormat());
            $data['modified_by'] = rand(20, 100);
            $data['ordering']    = $i;
            $data['state']       = $faker->randomElement(array(1, 1, 1, 1, 0, 0));
            $data['language']    = 'en-GB';
            $data['params']      = '';

            CategoryMapper::createOne($data);

            $this->outCounting();
        }
    }

    public function doClean()
    {
        $this->truncate(Table::CATEGORIES);
    }
}
// src/Blog/Admin/Seed/ArticleSeeder.php

// ...

class ArticleSeeder extends AbstractSeeder
{
    public function doExecute()
    {
        $faker = Factory::create();

        $categories = CategoryMapper::findAll();

        foreach ($categories as $category)
        {
            foreach (range(1, rand(3, 5)) as $i)
            {
                $data = new Data;

                $data['title']       = $faker->sentence(rand(3, 5));
                $data['alias']       = OutputFilter::stringURLSafe($data['title']);
                $data['category_id'] = $category->id;
                $data['introtext']   = $faker->paragraph(5);
                $data['fulltext']    = $faker->paragraph(5);
                $data['version']     = rand(1, 50);
                $data['created']     = $faker->dateTime->format($this->getSqlFormat());
                $data['created_by']  = rand(20, 100);
                $data['modified']    = $faker->dateTime->format($this->getSqlFormat());
                $data['modified_by'] = rand(20, 100);
                $data['ordering']    = $i;
                $data['state']       = $faker->randomElement(array(1, 1, 1, 1, 0, 0));
                $data['language']    = 'en-GB';
                $data['params']      = '';

                ArticleMapper::createOne($data);

                $this->outCounting();
            }
        }
    }

    public function doClean()
    {
        $this->truncate(Table::ARTICLES);
    }
}
// src/Blog/Admin/Seed/CommentSeeder.php

// ...

class CommentSeeder extends AbstractSeeder
{
    public function doExecute()
    {
        $faker = Factory::create();

        $articles = ArticleMapper::findAll();

        foreach ($articles as $article)
        {
            foreach (range(1, rand(1, 7)) as $i)
            {
                $data = new Data;

                $data['article_id'] = $article->id;
                $data['name']       = $faker->name;
                $data['email']      = $faker->email;
                $data['text']       = $faker->paragraph(5);
                $data['created']    = $faker->dateTime->format($this->getSqlFormat());
                $data['ordering']   = $i;
                $data['state']      = $faker->randomElement(array(1, 1, 1, 1, 0, 0));
                $data['params']     = '';

                CommentMapper::createOne($data);

                $this->outCounting();
            }
        }
    }

    public function doClean()
    {
        $this->db->getTable(Table::COMMENTS)->truncate();
    }
}

Run seeder import

php windwalker seed import -p=admin

# OR

php windwalker migration reset --seed -p=admin

If migration and seeder works fine, open the admin page, you will see sample data to test.

Imgur

The first Categories menu item is a placeholder, you can delete it in src/Blog/Admin/Templates/_global/admin/widget/submenu.blade.php.


If you found a typo or error, please help us improve this document.