Symfony/BDD example 05: CRUD

2 January 2015

This is the fifth example in Symfony/BDD series. It demonstrates how to create and test CRUD.

1. Background

I assume that you have already read:

In this example I want to create an administration panel to enter and modify records in the database.

The database will contain a table River to store some information about rivers. Every record will have the following columns:

2. Introductory step

2.1. Start the project

Create a new directory and clone my Symfony Standard repository:

# Host OS
$ mkdir symfony-bdd-example-05-crud
$ cd symfony-bdd-example-05-crud
$ git clone git@github.com:by-examples/symfony-standard.git .

2.2. Create a starting point for the project

Create a new orphan branch that starts at the tag Symfony Standard v2.6.1:

# Host OS
$ git checkout --orphan 2.6.1/symfony-bdd-example-05-crud v2.6.1

Commit your change:

# Host OS
$ git add -A
$ git commit -m "Symfony Standard 2.6.1"

2.3. Customize the project

Introduce the following changes in your project:

# Host OS
$ git cherry-pick origin/2.6.1/Gitignore
$ git cherry-pick origin/2.6.1/Cleanup
$ git cherry-pick origin/2.6.1/Vagrant
$ git cherry-pick origin/2.6.1/Speedup
$ git cherry-pick origin/2.6.1/Behat
$ git cherry-pick origin/2.6.1/BehatInitialization
$ git cherry-pick origin/2.6.1/Db

2.4. Install the dependencies

Boot the VM with:

# Host OS
$ vagrant up
$ vagrant ssh

and run:

# Guest OS
$ composer install -o

When this is done, commit you changes with:

# Host OS
$ git add -A
$ git commit -m "Updated dependencies"

3. Run Behat - project is GREEN

Now, try to run:

# Guest OS
$ bin/behat

You will get the output similar to:

No scenarios
No steps
0m0.03s (9.00Mb)

The project is GREEN.

GREEN

4. CRUD Tests - the project is RED

Create the file features/crud.feature with the following contents:

Feature: I would like to edit rivers

  Scenario Outline: Insert records
   Given I am on "/admin/river"
    Then I should not see "<river>"
     And I follow "Create a new entry"
    Then I should see "River creation"
    When I fill in "Name" with "<river>"
     And I fill in "Length" with "<length>"
     And I press "Create"
    Then I should see "<river>"
     And I should see "<length>"

  Examples:
    | river          | length |
    | ABC RIV        | 7182   |
    | Vistula RIV    | 1234   |
    | The Thames RIV | 555    |


  Scenario Outline: Edit records
   Given I am on "/admin/river"
    Then I should not see "<new-river>"
    When I follow "<old-river>"
    Then I should see "<old-river>"
    When I follow "Edit"
     And I fill in "Name" with "<new-river>"
     And I fill in "Length" with "<new-length>"
     And I press "Update"
     And I follow "Back to the list"
    Then I should see "<new-river>"
     And I should see "<new-length>"
     And I should not see "<old-river>"

  Examples:
    | old-river     | new-river       | new-length |
    | Vistula RIV   | VI-stula RIV    | 9876       |
    | ABC RIV       | The NEW RIV     | 3333       |


  Scenario Outline: Delete records
   Given I am on "/admin/river"
    Then I should see "<river>"
    When I follow "<river>"
    Then I should see "<river>"
    When I press "Delete"
    Then I should not see "<river>"

  Examples:
    |  river         |
    | VI-stula RIV   |
    | The NEW RIV    |
    | The Thames RIV |

Run Behat:

# Guest OS
$ bin/behat

The project is RED.

RED

Commit the test:

# Host OS
$ git add -A
$ git commit -m "[BDD:RED] tests for CRUD"

5. Generate River entity

Run the command:

$ php app/console doctrine:generate:entity

In this example the entity’s name is:

AppBundle:River

Leave default settings for format: annotation and add two columns:

name     -   string 255
length   -   integer

When you are finished press enter (as many times as necessary).

The command generates a class stored in:

src/AppBundle/Entity/River.php

For this entity the ORM will create a table named River.

Commit your changes with:

$ git commit -m "[BDD:RED] Create River entity"

6. The Database

Now that we have an entity class we want to create a table in the database:

# Guest OS (Linux/Ubuntu)
$ php app/console doctrine:schema:update --force

7. Generate CRUD

Generate CRUD:

# Guest OS (Linux/Ubuntu)
$ php app/console doctrine:generate:crud

You will be asked a number of questions. The three of them are crucial for us:

Commit your changes with:

$ git commit -m "[BDD:RED] CRUD for River entity"

8. Customize the list of records

Change the file src/AppBundle/Resources/views/River/index.html.twig:

...
<tbody>
{% for entity in entities %}
    <tr>
        <td>{{ loop.index }}.</td>
        <td>
            <a href="{{ path('admin_river_show', { 'id': entity.id }) }}">
                {{ entity.name }}
            </a>
        </td>
        <td>{{ entity.length }}</td>
        <td>
...

9. Run the tests

Clear the cache:

# Guest OS
$ php app/console cache:clear --env=prod

Rebuild the database:

# Guest OS
$ mysql -u root < 00-extra/db/create-empty-database.sql
$ php app/console doctrine:schema:update --force

and run the tests:

# Guest OS
$ bin/behat

The project is GREEN.

GREEN

Commit your changes with:

# Host OS
$ git add -A
$ git commit -m "[BDD:GREEN] code for CRUD tests"

10. Visit app with your browser

Run web browser and visit:

http://localhost:8880/admin/river
http://localhost:8880/app_dev.php/admin/river

11. Remove unnecessary commits

Remove unnecessary commits from your repository:

$ git remote rm origin
$ git branch -D 2.7
$ git tag | xargs git tag -d
$ git reflog expire --all --expire=now
$ git prune
$ git gc

Now your repository contains only the commits that you have authored working on this example.

13. The Example

You will find the source code of the example on GitHub.

For the instruction how to run the example refer to README.md file.

Fork me on GitHub