Builder Example

This example shows how you can use the builder to create a simple form from a database table. I am using Atlas ORM as the database mapper (and you should check it out too!).

Setup

I am basing this example on a simple page controller with a view renderer. In this case, I am using Plates as the view renderer. And as mentioned above, Atlas ORM is the database layer. Keep in mind that this is simplistic and only meant as an example for instructional purposes. Much of the code would be set up in some sort of dependency container etc.

The posts table in the example will look something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
+-------------+--------------+------+-----+---------+----------------+
| Field       | Type         | Null | Key | Default | Extra          |
+-------------+--------------+------+-----+---------+----------------+
| id          | int(11)      | NO   | PRI | NULL    | auto_increment |
| title       | varchar(255) | NO   |     | NULL    |                |
| post        | text         | NO   |     | NULL    |                |
| userid      | varchar(8)   | NO   | MUL | NULL    |                |
| created_at  | datetime     | YES  |     | NULL    |                |
| updated_at  | datetime     | YES  |     | NULL    |                |
+-------------+--------------+------+-----+---------+----------------+

Controller

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<?php

use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
use League\Plates\Engine as View;
use Atlas\Orm\AtlasContainer;
use Vespula\Form\Form;
use Vespula\Form\Builder\Builder as FormBuilder;
use Blog\DataSource\Posts\PostsMapper; // An atlas mapper
use Blog\DataSource\Users\UsersMapper; // An atlas mapper
use PDO;

class MyController
{
    protected $atlas;
    protected $form;
    protected $view;
    protected $request; // Some PSR7 RequestInterface object
    protected $response; // Some PSR7 ResponseInterface object

    public function __construct(ServerRequestInterface $request, ResponseInterface $response)
    {
        $this->request = $request;
        $this->response = $response;

        $pdo = new PDO('mysql:host=localhost;dbname=blog', 'juser', '*******');
        $atlasContainer = new AtlasContainer($pdo);
        $atlasContainer->setMappers([
            PostsMapper::class,
            UsersMapper::class
        ]);
        $this->atlas = $atlasContainer->getAtlas();

        $form = new Form();
        $form->autoLf();
        $builder = new FormBuilder($pdo);
        $form->setBuilder($builder);
        $this->form = $form;

        $this->view = new View('/path/to/templates');
    }

    public function edit($id)
    {
        $post = $this->atlas->fetchRecord(PostsMapper::class, $id);
        if (! $post) {
            return $this->notFound();
        }

        // Get users as an array of key value pairs
        $users = $this->atlas->select(UsersMapper::class)
            ->cols(['id', 'name'])
            ->orderBy(['name ASC'])
            ->fetchPairs();


        $builder = $this->form->getBuilder();

        // Make the userid input a select
        $builder->setColumnOptions([
            'userid'=>[
                'type'=>'select',
                'callback'=>function ($element) use ($users) {
                    $element->options($users)
                }
            ]
        ]);

        // Set some default classes
        $builder->setDefaultClasses([
            'textarea'=>'form-control',
            'text'=>'form-control',
            'select'=>'form-control'
        ]);

        // Atlas has a handy method `getArrayCopy()` which returns a record as
        // an array. Perfect for our form.

        // Build the form elements and use the values from the $post to populate
        // the form element values.
        $this->form->build('posts', $post->getArrayCopy());

        // Get the rendered view and hand it to the response.
        $content = $this->view->render('edit', [
            'post'=>$post,
            'form'=>$this->form
        ]);

        return $this->response->getBody()->write($content);
    }
}

View

The view template (edit.php) might look something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<h1>Edit a Post</h1>

<h2><?=$this->e($post->title); ?></h2>

<?=$form->begin(); ?>
<?=$form->getElement('id'); ?>

<div class="form-group">
    <?=$form->getElement('label_title'); ?>
    <?=$form->getElement('title'); ?>
</div>
<div class="form-group">
    <?=$form->getElement('label_post'); ?>
    <?=$form->getElement('post'); ?>
</div>
<div class="form-group">
    <?=$form->getElement('label_userid')->text('Author'); ?>
    <?=$form->getElement('userid')->indent(1); ?>
</div>

<?=$form->submit('Save')->class('btn btn-primary'); ?>
<?=$form->end(); ?>

And the resulting HTML might look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<form method="post">
<input type="hidden" id="id" name="id" value="1" maxlength="11" />
<div class="form-group">
    <label for="title">Title</label>
    <input type="text" id="title" name="title" value="Lorem ipsum" class="form-control" maxlength="255" required />
</div>
<div class="form-group">
    <label for="post">Post</label>
    <textarea cols="10" rows="5" id="post" name="post" class="form-control" required>Blah blah blah</textarea>
</div>
<div class="form-group">
    <label for="user_userid">Author</label>
    <select id="user_userid" name="user_userid" class="form-control" required>
        <option value="bar">Bar</option>
        <option value="baz" selected>Baz</option>
        <option value="foo">Foo</option>
    </select>
</div>

<button type="submit" class="btn btn-primary">Save</button>
</form>