1
0
mirror of synced 2025-02-02 21:41:45 +03:00

Updating the Getting Started guide's documentation

This commit is contained in:
NateC 2016-02-24 17:13:25 -06:00 committed by Marco Pivetta
parent 9cfdf1ef81
commit b446afd937
No known key found for this signature in database
GPG Key ID: 4167D3337FD9D629

View File

@ -14,7 +14,7 @@ Guide Assumptions
----------------- -----------------
This guide is designed for beginners that haven't worked with Doctrine ORM This guide is designed for beginners that haven't worked with Doctrine ORM
before. There are some prerequesites for the tutorial that have to be before. There are some prerequisites for the tutorial that have to be
installed: installed:
- PHP (latest stable version) - PHP (latest stable version)
@ -118,8 +118,8 @@ Add the following directories:
Obtaining the EntityManager Obtaining the EntityManager
--------------------------- ---------------------------
Doctrine's public interface is the EntityManager, it provides the Doctrine's public interface is through the ``EntityManager``. This class
access point to the complete lifecycle management of your entities provides access points to the complete lifecycle management for your entities,
and transforms entities from and back to persistence. You have to and transforms entities from and back to persistence. You have to
configure and create it to use your entities with Doctrine 2. I configure and create it to use your entities with Doctrine 2. I
will show the configuration steps and then discuss them step by will show the configuration steps and then discuss them step by
@ -150,8 +150,8 @@ step:
// obtaining the entity manager // obtaining the entity manager
$entityManager = EntityManager::create($conn, $config); $entityManager = EntityManager::create($conn, $config);
The first require statement sets up the autoloading capabilities of Doctrine The require_once statement sets up the class autoloading for Doctrine and
using the Composer autoload. its dependencies using Composer's autoloader.
The second block consists of the instantiation of the ORM The second block consists of the instantiation of the ORM
``Configuration`` object using the Setup helper. It assumes a bunch ``Configuration`` object using the Setup helper. It assumes a bunch
@ -159,8 +159,8 @@ of defaults that you don't have to bother about for now. You can
read up on the configuration details in the read up on the configuration details in the
:doc:`reference chapter on configuration <../reference/configuration>`. :doc:`reference chapter on configuration <../reference/configuration>`.
The third block shows the configuration options required to connect The third block shows the configuration options required to connect to
to a database, in my case a file-based sqlite database. All the a database. In this case, we'll use a file-based SQLite database. All the
configuration options for all the shipped drivers are given in the configuration options for all the shipped drivers are given in the
`DBAL Configuration section of the manual <http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/>`_. `DBAL Configuration section of the manual <http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/>`_.
@ -170,15 +170,10 @@ factory method.
Generating the Database Schema Generating the Database Schema
------------------------------ ------------------------------
Now that we have defined the Metadata mappings and bootstrapped the Doctrine has a command-line interface that allows you to access the SchemaTool,
EntityManager we want to generate the relational database schema a component that can generate a relational database schema based entirely on the
from it. Doctrine has a Command-Line Interface that allows you to defined entity classes and their metadata. For this tool to work, a
access the SchemaTool, a component that generates the required cli-config.php file must exist in the project root directory:
tables to work with the metadata.
For the command-line tool to work a cli-config.php file has to be
present in the project root directory, where you will execute the
doctrine command. Its a fairly simple file:
.. code-block:: php .. code-block:: php
@ -188,40 +183,38 @@ doctrine command. Its a fairly simple file:
return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager); return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager);
You can then change into your project directory and call the Change into your project directory and call the Doctrine command-line tool:
Doctrine command-line tool:
:: ::
$ cd project/ $ cd project/
$ vendor/bin/doctrine orm:schema-tool:create $ vendor/bin/doctrine orm:schema-tool:create
At this point no entity metadata exists in `src` so you will see a message like Since we haven't added any entity metadata in `src` yet, you'll see a message
"No Metadata Classes to process." Don't worry, we'll create a Product entity and stating "No Metadata Classes to process." In the next section, we'll create a
corresponding metadata in the next section. Product entity along with the corresponding metadata, and run this command again.
You should be aware that during the development process you'll periodically need Note that as you modify your entities' metadata during the development process,
to update your database schema to be in sync with your Entities metadata. you'll need to update your database schema to stay in sync with the metadata.
You can rasily recreate the database using the following commands:
You can easily recreate the database:
:: ::
$ vendor/bin/doctrine orm:schema-tool:drop --force $ vendor/bin/doctrine orm:schema-tool:drop --force
$ vendor/bin/doctrine orm:schema-tool:create $ vendor/bin/doctrine orm:schema-tool:create
Or use the update functionality: Or you can use the update functionality:
:: ::
$ vendor/bin/doctrine orm:schema-tool:update --force $ vendor/bin/doctrine orm:schema-tool:update --force
The updating of databases uses a Diff Algorithm for a given The updating of databases uses a Diff Algorithm for a given
Database Schema, a cornerstone of the ``Doctrine\DBAL`` package, Database Schema. This is a cornerstone of the ``Doctrine\DBAL`` package,
which can even be used without the Doctrine ORM package. which can even be used without the Doctrine ORM package.
Starting with the Product Starting with the Product Entity
------------------------- --------------------------------
We start with the simplest entity, the Product. Create a ``src/Product.php`` file to contain the ``Product`` We start with the simplest entity, the Product. Create a ``src/Product.php`` file to contain the ``Product``
entity definition: entity definition:
@ -257,9 +250,9 @@ entity definition:
} }
} }
Note that all fields are set to protected (not public) with a When creating entity classes, all of the fields should be protected or private
mutator (getter and setter) defined for every field except $id. (not public), with getter and setter methods for each one (except $id).
The use of mutators allows Doctrine to hook into calls which The use of mutators allows Doctrine to hook into calls which
manipulate the entities in ways that it could not if you just manipulate the entities in ways that it could not if you just
directly set the values with ``entity#field = foo;`` directly set the values with ``entity#field = foo;``
@ -274,9 +267,10 @@ language. The metadata language describes how entities, their
properties and references should be persisted and what constraints properties and references should be persisted and what constraints
should be applied to them. should be applied to them.
Metadata for entities are configured using a XML, YAML or Docblock Annotations. Metadata for an Entity can be configured using DocBlock annotations directly
This Getting Started Guide will show the mappings for all Mapping Drivers. in the Entity class itself, or in an external XML or YAML file. This Getting
References in the text will be made to the XML mapping. Started guide will demonstrate metadata mappings using all three methods,
but you only need to choose one.
.. configuration-block:: .. configuration-block::
@ -332,27 +326,28 @@ References in the text will be made to the XML mapping.
The top-level ``entity`` definition tag specifies information about The top-level ``entity`` definition tag specifies information about
the class and table-name. The primitive type ``Product#name`` is the class and table-name. The primitive type ``Product#name`` is
defined as a ``field`` attribute. The ``id`` property is defined with defined as a ``field`` attribute. The ``id`` property is defined with
the ``id`` tag, this has a ``generator`` tag nested inside which the ``id`` tag. It has a ``generator`` tag nested inside, which
defines that the primary key generation mechanism automatically specifies that the primary key generation mechanism should automatically
uses the database platforms native id generation strategy (for use the database platform's native id generation strategy (for
example AUTO INCREMENT in the case of MySql or Sequences in the example, AUTO INCREMENT in the case of MySql, or Sequences in the
case of PostgreSql and Oracle). case of PostgreSql and Oracle).
Now that we have defined our first entity, let's update the database: Now that we have defined our first entity and its metadata,
let's update the database schema:
:: ::
$ vendor/bin/doctrine orm:schema-tool:update --force --dump-sql $ vendor/bin/doctrine orm:schema-tool:update --force --dump-sql
Specifying both flags ``--force`` and ``--dump-sql`` prints and executes the DDL Specifying both flags ``--force`` and ``--dump-sql`` will cause the DDL
statements. statements to be executed and then printed to the screen.
Now create a new script that will insert products into the database: Now, we'll create a new script to insert products into the database:
.. code-block:: php .. code-block:: php
<?php <?php
// create_product.php // create_product.php <name>
require_once "bootstrap.php"; require_once "bootstrap.php";
$newProductName = $argv[1]; $newProductName = $argv[1];
@ -372,22 +367,19 @@ Call this script from the command-line to see how new products are created:
$ php create_product.php ORM $ php create_product.php ORM
$ php create_product.php DBAL $ php create_product.php DBAL
What is happening here? Using the ``Product`` is pretty standard OOP. What is happening here? Using the ``Product`` class is pretty standard OOP.
The interesting bits are the use of the ``EntityManager`` service. To The interesting bits are the use of the ``EntityManager`` service. To
notify the EntityManager that a new entity should be inserted into the database notify the EntityManager that a new entity should be inserted into the database,
you have to call ``persist()``. To initiate a transaction to actually perform you have to call ``persist()``. To initiate a transaction to actually *perform*
the insertion, You have to explicitly call ``flush()`` on the ``EntityManager``. the insertion, you have to explicitly call ``flush()`` on the ``EntityManager``.
This distinction between persist and flush is allows to aggregate all writes This distinction between persist and flush is what allows the aggregation of
(INSERT, UPDATE, DELETE) into one single transaction, which is executed when all database writes (INSERT, UPDATE, DELETE) into one single transaction, which
flush is called. Using this approach the write-performance is significantly is executed when ``flush()`` is called. Using this approach, the write-performance
better than in a scenario where updates are done for each entity in isolation. is significantly better than in a scenario in which writes are performed on
each entity in isolation.
Doctrine follows the UnitOfWork pattern which additionally detects all entities Next, we'll fetch a list of all the Products in the database. Let's create a
that were fetched and have changed during the request. You don't have to keep track of
entities yourself, when Doctrine already knows about them.
As a next step we want to fetch a list of all the Products. Let's create a
new script for this: new script for this:
.. code-block:: php .. code-block:: php
@ -404,10 +396,10 @@ new script for this:
} }
The ``EntityManager#getRepository()`` method can create a finder object (called The ``EntityManager#getRepository()`` method can create a finder object (called
a repository) for every entity. It is provided by Doctrine and contains some a repository) for every type of entity. It is provided by Doctrine and contains
finder methods such as ``findAll()``. some finder methods like ``findAll()``.
Let's continue with displaying the name of a product based on its ID: Let's continue by creating a script to display the name of a product based on its ID:
.. code-block:: php .. code-block:: php
@ -425,9 +417,13 @@ Let's continue with displaying the name of a product based on its ID:
echo sprintf("-%s\n", $product->getName()); echo sprintf("-%s\n", $product->getName());
Updating a product name demonstrates the functionality UnitOfWork of pattern Next we'll update a product's name, given its id. This simple example will
discussed before. We only need to find a product entity and all changes to its help demonstrate Doctrine's implementation of the UnitOfWork pattern. Doctrine
properties are written to the database: keeps track of all the entities that were retrieved from the Entity Manager,
and can detect when any of those entities' properties have been modified.
As a result, rather than needing to call ``persist($entity)`` for each individual
entity whose properties were changed, a single call to ``flush()`` at the end of a
request is sufficient to update the database for all of the modified entities.
.. code-block:: php .. code-block:: php
@ -455,9 +451,8 @@ product name changed by calling the ``show_product.php`` script.
Adding Bug and User Entities Adding Bug and User Entities
---------------------------- ----------------------------
We continue with the bug tracker domain, by creating the missing classes We continue with the bug tracker example by creating the ``Bug`` and ``User``
``Bug`` and ``User`` and putting them into ``src/Bug.php`` and classes. We'll store them in ``src/Bug.php`` and ``src/User.php``, respectively.
``src/User.php`` respectively.
.. code-block:: php .. code-block:: php
@ -561,14 +556,15 @@ We continue with the bug tracker domain, by creating the missing classes
} }
} }
All of the properties discussed so far are simple string and integer values, All of the properties we've seen so far are of simple types (integer, string,
for example the id fields of the entities, their names, description, status and and datetime). But now, we'll add properties that will store objects of
change dates. Next we will model the dynamic relationships between the entities specific *entity types* in order to model the relationships between different
by defining the references between entities. entities.
References between objects are foreign keys in the database. You never have to At the database level, relationships between entities are represented by foreign
(and never should) work with the foreign keys directly, only with the objects keys. But with Doctrine, you'll never have to (and never should) work with
that represent the foreign key through their own identity. the foreign keys directly. You should only work with objects that represent
foreign keys through their own identities.
For every foreign key you either have a Doctrine ManyToOne or OneToOne For every foreign key you either have a Doctrine ManyToOne or OneToOne
association. On the inverse sides of these foreign keys you can have association. On the inverse sides of these foreign keys you can have
@ -602,6 +598,7 @@ domain model to match the requirements:
<?php <?php
// src/User.php // src/User.php
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
class User class User
{ {
// ... (previous code) // ... (previous code)
@ -616,12 +613,13 @@ domain model to match the requirements:
} }
} }
You use Doctrine's ArrayCollections in your Doctrine models, rather .. note::
than plain PHP arrays, so that Doctrine can watch what happens with
them and act appropriately. Note that if you dump your entities, Whenever an entity is created from the database, a ``Collection``
you'll see a "PersistentCollection" in place of your ArrayCollection, implementation of the type ``PersistentCollection`` will be injected into
which is just an your entity instead of an ``ArrayCollection``. This helps Doctrine ORM
internal Doctrine class with the same interface. understand the changes that have happened to the collection that are
noteworthy for persistence.
.. warning:: .. warning::
@ -644,24 +642,22 @@ able to work with Doctrine 2. These assumptions are not unique to
Doctrine 2 but are best practices in handling database relations Doctrine 2 but are best practices in handling database relations
and Object-Relational Mapping. and Object-Relational Mapping.
- In a one-to-one relation, the entity holding the foreign key of
the related entity on its own database table is *always* the owning
side of the relation.
- In a many-to-one relation, the Many-side is the owning side by
default because it holds the foreign key. Accordingly, the One-side
is the inverse side by default.
- In a many-to-one relation, the One-side can only be the owning side if
the relation is implemented as a ManyToMany with a join table, and the
One-side is restricted to allow only UNIQUE values per database constraint.
- In a many-to-many relation, both sides can be the owning side of
the relation. However, in a bi-directional many-to-many relation,
only one side is allowed to be the owning side.
- Changes to Collections are saved or updated, when the entity on - Changes to Collections are saved or updated, when the entity on
the *owning* side of the collection is saved or updated. the *owning* side of the collection is saved or updated.
- Saving an Entity at the inverse side of a relation never - Saving an Entity at the inverse side of a relation never
triggers a persist operation to changes to the collection. triggers a persist operation to changes to the collection.
- In a one-to-one relation the entity holding the foreign key of
the related entity on its own database table is *always* the owning
side of the relation.
- In a many-to-many relation, both sides can be the owning side of
the relation. However in a bi-directional many-to-many relation
only one is allowed to be.
- In a many-to-one relation the Many-side is the owning side by
default, because it holds the foreign key.
- The OneToMany side of a relation is inverse by default, since
the foreign key is saved on the Many side. A OneToMany relation can
only be the owning side, if its implemented using a ManyToMany
relation with join table and restricting the one side to allow only
UNIQUE values per database constraint.
.. note:: .. note::
@ -686,13 +682,13 @@ the bi-directional reference:
protected $engineer; protected $engineer;
protected $reporter; protected $reporter;
public function setEngineer($engineer) public function setEngineer(User $engineer)
{ {
$engineer->assignedToBug($this); $engineer->assignedToBug($this);
$this->engineer = $engineer; $this->engineer = $engineer;
} }
public function setReporter($reporter) public function setReporter(User $reporter)
{ {
$reporter->addReportedBug($this); $reporter->addReportedBug($this);
$this->reporter = $reporter; $this->reporter = $reporter;
@ -717,15 +713,15 @@ the bi-directional reference:
{ {
// ... (previous code) // ... (previous code)
protected $reportedBugs = null; protected $reportedBugs;
protected $assignedBugs = null; protected $assignedBugs;
public function addReportedBug($bug) public function addReportedBug(Bug $bug)
{ {
$this->reportedBugs[] = $bug; $this->reportedBugs[] = $bug;
} }
public function assignedToBug($bug) public function assignedToBug(Bug $bug)
{ {
$this->assignedBugs[] = $bug; $this->assignedBugs[] = $bug;
} }
@ -741,7 +737,7 @@ You can see from ``User#addReportedBug()`` and
``User#assignedToBug()`` that using this method in userland alone ``User#assignedToBug()`` that using this method in userland alone
would not add the Bug to the collection of the owning side in would not add the Bug to the collection of the owning side in
``Bug#reporter`` or ``Bug#engineer``. Using these methods and ``Bug#reporter`` or ``Bug#engineer``. Using these methods and
calling Doctrine for persistence would not update the collections calling Doctrine for persistence would not update the Collections'
representation in the database. representation in the database.
Only using ``Bug#setEngineer()`` or ``Bug#setReporter()`` Only using ``Bug#setEngineer()`` or ``Bug#setReporter()``
@ -749,7 +745,7 @@ correctly saves the relation information.
The ``Bug#reporter`` and ``Bug#engineer`` properties are The ``Bug#reporter`` and ``Bug#engineer`` properties are
Many-To-One relations, which point to a User. In a normalized Many-To-One relations, which point to a User. In a normalized
relational model the foreign key is saved on the Bug's table, hence relational model, the foreign key is saved on the Bug's table, hence
in our object-relation model the Bug is at the owning side of the in our object-relation model the Bug is at the owning side of the
relation. You should always make sure that the use-cases of your relation. You should always make sure that the use-cases of your
domain model should drive which side is an inverse or owning one in domain model should drive which side is an inverse or owning one in
@ -758,7 +754,7 @@ or an engineer is assigned to the bug, we don't want to update the
User to persist the reference, but the Bug. This is the case with User to persist the reference, but the Bug. This is the case with
the Bug being at the owning side of the relation. the Bug being at the owning side of the relation.
Bugs reference Products by an uni-directional ManyToMany relation in Bugs reference Products by a uni-directional ManyToMany relation in
the database that points from Bugs to Products. the database that points from Bugs to Products.
.. code-block:: php .. code-block:: php
@ -771,7 +767,7 @@ the database that points from Bugs to Products.
protected $products = null; protected $products = null;
public function assignToProduct($product) public function assignToProduct(Product $product)
{ {
$this->products[] = $product; $this->products[] = $product;
} }
@ -783,7 +779,7 @@ the database that points from Bugs to Products.
} }
We are now finished with the domain model given the requirements. We are now finished with the domain model given the requirements.
Lets add metadata mappings for the ``User`` and ``Bug`` as we did for Lets add metadata mappings for the ``Bug`` entity, as we did for
the ``Product`` before: the ``Product`` before:
.. configuration-block:: .. configuration-block::
@ -890,13 +886,13 @@ For the "created" field we have used the ``datetime`` type,
which translates the YYYY-mm-dd HH:mm:ss database format which translates the YYYY-mm-dd HH:mm:ss database format
into a PHP DateTime instance and back. into a PHP DateTime instance and back.
After the field definitions the two qualified references to the After the field definitions, the two qualified references to the
user entity are defined. They are created by the ``many-to-one`` user entity are defined. They are created by the ``many-to-one``
tag. The class name of the related entity has to be specified with tag. The class name of the related entity has to be specified with
the ``target-entity`` attribute, which is enough information for the ``target-entity`` attribute, which is enough information for
the database mapper to access the foreign-table. Since the database mapper to access the foreign-table. Since
``reporter`` and ``engineer`` are on the owning side of a ``reporter`` and ``engineer`` are on the owning side of a
bi-directional relation we also have to specify the ``inversed-by`` bi-directional relation, we also have to specify the ``inversed-by``
attribute. They have to point to the field names on the inverse attribute. They have to point to the field names on the inverse
side of the relationship. We will see in the next example that the ``inversed-by`` side of the relationship. We will see in the next example that the ``inversed-by``
attribute has a counterpart ``mapped-by`` which makes that attribute has a counterpart ``mapped-by`` which makes that
@ -907,7 +903,7 @@ holds all products where the specific bug occurs. Again
you have to define the ``target-entity`` and ``field`` attributes you have to define the ``target-entity`` and ``field`` attributes
on the ``many-to-many`` tag. on the ``many-to-many`` tag.
The last missing definition is that of the User entity: Finally, we'll add metadata mappings for the ``User`` entity.
.. configuration-block:: .. configuration-block::
@ -934,13 +930,13 @@ The last missing definition is that of the User entity:
/** /**
* @OneToMany(targetEntity="Bug", mappedBy="reporter") * @OneToMany(targetEntity="Bug", mappedBy="reporter")
* @var Bug[] * @var Bug[] An ArrayCollection of Bug objects.
**/ **/
protected $reportedBugs = null; protected $reportedBugs = null;
/** /**
* @OneToMany(targetEntity="Bug", mappedBy="engineer") * @OneToMany(targetEntity="Bug", mappedBy="engineer")
* @var Bug[] * @var Bug[] An ArrayCollection of Bug objects.
**/ **/
protected $assignedBugs = null; protected $assignedBugs = null;
@ -996,10 +992,7 @@ means the join details have already been defined on the owning
side. Therefore we only have to specify the property on the Bug side. Therefore we only have to specify the property on the Bug
class that holds the owning sides. class that holds the owning sides.
This example has a fair overview of the most basic features of the Update your database schema by running:
metadata definition language.
Update your database running:
:: ::
$ vendor/bin/doctrine orm:schema-tool:update --force $ vendor/bin/doctrine orm:schema-tool:update --force
@ -1008,7 +1001,8 @@ Update your database running:
Implementing more Requirements Implementing more Requirements
------------------------------ ------------------------------
For starters we need to create user entities: So far, we've seen the most basic features of the metadata definition language.
To explore additional functionality, let's first create new ``User`` entities:
.. code-block:: php .. code-block:: php
@ -1032,23 +1026,22 @@ Now call:
$ php create_user.php beberlei $ php create_user.php beberlei
We now have the data to create a bug and the code for this scenario may look We now have the necessary data to create a new Bug entity:
like this:
.. code-block:: php .. code-block:: php
<?php <?php
// create_bug.php // create_bug.php <reporter-id> <engineer-id> <product-ids>
require_once "bootstrap.php"; require_once "bootstrap.php";
$theReporterId = $argv[1]; $reporterId = $argv[1];
$theDefaultEngineerId = $argv[2]; $engineerId = $argv[2];
$productIds = explode(",", $argv[3]); $productIds = explode(",", $argv[3]);
$reporter = $entityManager->find("User", $theReporterId); $reporter = $entityManager->find("User", $reporterId);
$engineer = $entityManager->find("User", $theDefaultEngineerId); $engineer = $entityManager->find("User", $engineerId);
if (!$reporter || !$engineer) { if (!$reporter || !$engineer) {
echo "No reporter and/or engineer found for the input.\n"; echo "No reporter and/or engineer found for the given id(s).\n";
exit(1); exit(1);
} }
@ -1070,22 +1063,17 @@ like this:
echo "Your new Bug Id: ".$bug->getId()."\n"; echo "Your new Bug Id: ".$bug->getId()."\n";
Since we only have one user and product, probably with the ID of 1, we can call this script with: Since we only have one user and product, probably with the ID of 1, we can
call this script as follows:
:: ::
php create_bug.php 1 1 1 php create_bug.php 1 1 1
This is the first contact with the read API of the EntityManager, See how simple it is to relate a Bug, Reporter, Engineer and Products?
showing that a call to ``EntityManager#find($name, $id)`` returns a Also recall that thanks to the UnitOfWork pattern, Doctrine will detect
single instance of an entity queried by primary key. Besides this these relations and update all of the modified entities in the database
we see the persist + flush pattern again to save the Bug into the automatically when ``flush()`` is called.
database.
See how simple relating Bug, Reporter, Engineer and Products is
done by using the discussed methods in the "A first prototype"
section. The UnitOfWork will detect this relationship when flush is
called and relate them in the database appropriately.
Queries for Application Use-Cases Queries for Application Use-Cases
--------------------------------- ---------------------------------
@ -1094,7 +1082,7 @@ List of Bugs
~~~~~~~~~~~~ ~~~~~~~~~~~~
Using the previous examples we can fill up the database quite a Using the previous examples we can fill up the database quite a
bit, however we now need to discuss how to query the underlying bit. However, we now need to discuss how to query the underlying
mapper for the required view representations. When opening the mapper for the required view representations. When opening the
application, bugs can be paginated through a list-view, which is application, bugs can be paginated through a list-view, which is
the first read-only use-case: the first read-only use-case:
@ -1225,7 +1213,7 @@ write scenarios:
.. code-block:: php .. code-block:: php
<?php <?php
// show_bug.php // show_bug.php <id>
require_once "bootstrap.php"; require_once "bootstrap.php";
$theBugId = $argv[1]; $theBugId = $argv[1];
@ -1300,7 +1288,7 @@ and usage of bound parameters:
.. code-block:: php .. code-block:: php
<?php <?php
// dashboard.php // dashboard.php <user-id>
require_once "bootstrap.php"; require_once "bootstrap.php";
$theUserId = $argv[1]; $theUserId = $argv[1];
@ -1366,7 +1354,7 @@ should be able to close a bug. This looks like:
.. code-block:: php .. code-block:: php
<?php <?php
// close_bug.php // close_bug.php <bug-id>
require_once "bootstrap.php"; require_once "bootstrap.php";
$theBugId = $argv[1]; $theBugId = $argv[1];