Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Convert all highlight tags to markdown fenced code blocks

Since Github:pages support fenced code blocks
  • Loading branch information...
commit ec941c4d60566711293848e0b4426ee1845e03d9 1 parent a0918e1
@robin850 robin850 authored
Showing with 1,272 additions and 1,268 deletions.
  1. +3 −0  _config.yml
  2. +16 −16 behaviors/aggregate-column.markdown
  3. +6 −6 behaviors/alternative-coding-standards.markdown
  4. +32 −32 behaviors/archivable.markdown
  5. +12 −12 behaviors/auto-add-pk.markdown
  6. +18 −18 behaviors/delegate.markdown
  7. +22 −22 behaviors/i18n.markdown
  8. +36 −36 behaviors/nested-set.markdown
  9. +10 −10 behaviors/query-cache.markdown
  10. +18 −18 behaviors/sluggable.markdown
  11. +18 −18 behaviors/soft-delete.markdown
  12. +34 −34 behaviors/sortable.markdown
  13. +16 −16 behaviors/timestampable.markdown
  14. +24 −24 behaviors/versionable.markdown
  15. +12 −12 contribute.markdown
  16. +6 −6 cookbook/adding-additional-sql-files.markdown
  17. +4 −4 cookbook/copying-persisted-objects.markdown
  18. +18 −18 cookbook/customizing-build.markdown
  19. +4 −4 cookbook/dbdesigner.markdown
  20. +20 −20 cookbook/geocodable-behavior.markdown
  21. +32 −32 cookbook/multi-component-data-model.markdown
  22. +16 −16 cookbook/namespaces.markdown
  23. +6 −6 cookbook/replication.markdown
  24. +26 −26 cookbook/runtime-introspection.markdown
  25. +14 −14 cookbook/testing-your-behaviors.markdown
  26. +28 −28 cookbook/using-mssql-server.markdown
  27. +12 −12 cookbook/using-sql-schemas.markdown
  28. +22 −22 cookbook/working-with-advanced-column-types.markdown
  29. +20 −20 cookbook/working-with-existing-databases.markdown
  30. +6 −6 cookbook/working-with-unit-tests.markdown
  31. +34 −34 cookbook/writing-behavior.markdown
  32. +31 −29 documentation/01-installation.markdown
  33. +36 −36 documentation/02-buildtime.markdown
  34. +48 −48 documentation/03-basic-crud.markdown
  35. +48 −48 documentation/04-relationships.markdown
  36. +30 −30 documentation/05-validators.markdown
  37. +24 −24 documentation/06-transactions.markdown
  38. +46 −46 documentation/07-behaviors.markdown
  39. +44 −44 documentation/08-logging.markdown
  40. +38 −38 documentation/09-inheritance.markdown
  41. +38 −38 documentation/10-migrations.markdown
  42. +64 −64 documentation/whats-new.markdown
  43. +18 −19 download.markdown
  44. +2 −2 index.markdown
  45. +58 −58 reference/active-record.markdown
  46. +18 −18 reference/buildtime-configuration.markdown
  47. +124 −124 reference/model-criteria.markdown
  48. +30 −30 reference/runtime-configuration.markdown
  49. +30 −30 reference/schema.markdown
View
3  _config.yml
@@ -1,2 +1,5 @@
pygments: true
permalink: none
+markdown: redcarpet
+redcarpet:
+ extensions: ["tables", "no_intra_emphasis"]
View
32 behaviors/aggregate-column.markdown
@@ -11,7 +11,7 @@ The `aggregate_column` behavior keeps a column updated using an aggregate functi
In the `schema.xml`, use the `<behavior>` tag to add the `aggregate_column` behavior to a table. You must provide parameters for the aggregate column `name`, the foreign table name, and the aggegate `expression`. For instance, to add an aggregate column keeping the comment count in a `post` table:
-{% highlight xml %}
+```xml
<table name="post">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -28,11 +28,11 @@ In the `schema.xml`, use the `<behavior>` tag to add the `aggregate_column` beha
<reference local="post_id" foreign="id" />
</foreign-key>
</table>
-{% endhighlight %}
+```
Rebuild your model, and insert the table creation sql again. The model now has an additional `nb_comments` column, of type `integer` by default. And each time an record from the foreign table is added, modified, or removed, the aggregate column is updated:
-{% highlight php %}
+```php
<?php
$post = new Post();
$post->setTitle('How Is Life On Earth?');
@@ -48,23 +48,23 @@ $comment2->save();
echo $post->getNbComments(); // 2
$comment2->delete();
echo $post->getNbComments(); // 1
-{% endhighlight %}
+```
The aggregate column is also kept up to date when related records get modified through a Query object:
-{% highlight php %}
+```php
<?php
CommentQuery::create()
->filterByPost($post)
->delete():
echo $post->getNbComments(); // 0
-{% endhighlight %}
+```
## Customizing The Aggregate Calculation ##
Any aggregate function can be used on any of the foreign columns. For instance, you can use the `aggregate_column` behavior to keep the latest update date of the related comments, or the total votes on the comments. You can even keep several aggregate columns in a single table:
-{% highlight xml %}
+```xml
<table name="post">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -93,11 +93,11 @@ Any aggregate function can be used on any of the foreign columns. For instance,
<column name="created_at" type="TIMESTAMP" />
<column name="vote" type="INTEGER" />
</table>
-{% endhighlight %}
+```
The behavior adds a `computeXXX()` method to the `Post` class to compute the value of the aggregate function. This method, called each time records are modified in the related `comment` table, is the translation of the behavior settings into a SQL query:
-{% highlight php %}
+```php
<?php
// in om/BasePost.php
public function computeNbComments(PropelPDO $con)
@@ -107,7 +107,7 @@ public function computeNbComments(PropelPDO $con)
$stmt->execute();
return $stmt->fetchColumn();
}
-{% endhighlight %}
+```
You can override this method in the model class to customize the aggregate column calculation.
@@ -116,7 +116,7 @@ You can override this method in the model class to customize the aggregate colum
What if you use your own soft deletion and want to calculate only comments which are not marked as deleted?
It is possible to add a custom SQL condition:
-{% highlight xml %}
+```xml
<table name="post">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -127,11 +127,11 @@ It is possible to add a custom SQL condition:
<parameter name="condition" value="is_deleted = false" />
</behavior>
</table>
-{% endhighlight %}
+```
Which will result in generated SQL query:
-{% highlight php %}
+```php
<?php
// in om/BasePost.php
public function computeNbComments(PropelPDO $con)
@@ -141,13 +141,13 @@ public function computeNbComments(PropelPDO $con)
$stmt->execute();
return $stmt->fetchColumn();
}
-{% endhighlight %}
+```
## Customizing The Aggregate Column ##
By default, the behavior adds one columns to the model. If this column is already described in the schema, the behavior detects it and doesn't add it a second time. This can be useful if you need to use a custom `type` or `phpName` for the aggregate column:
-{% highlight xml %}
+```xml
<table name="post">
<column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -158,4 +158,4 @@ By default, the behavior adds one columns to the model. If this column is alread
<parameter name="expression" value="COUNT(id)" />
</behavior>
</table>
-{% endhighlight %}
+```
View
12 behaviors/alternative-coding-standards.markdown
@@ -10,17 +10,17 @@ The `alternative_coding_standards` behavior changes the coding standards of the
## Basic Usage ##
In the `schema.xml`, use the `<behavior>` tag to add the `alternative_coding_standards` behavior to a table:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="alternative_coding_standards" />
</table>
-{% endhighlight %}
+```
Rebuild your model, and you're ready to go. The code of the model classes now uses an alternative set of coding standards:
-{% highlight php %}
+```php
<?php
// in om/BaseBook.php
/**
@@ -66,7 +66,7 @@ Rebuild your model, and you're ready to go. The code of the model classes now us
return $this;
} // setTitle()
-{% endhighlight %}
+```
The behavior replaces tabulations by whitespace (2 spaces by default), places opening brackets on newlines, removes closing brackets comments, and can even strip every comments in the generated classes if you wish.
@@ -74,7 +74,7 @@ The behavior replaces tabulations by whitespace (2 spaces by default), places op
Each of the new coding style rules has corresponding parameter in the behavior description. Here is the default configuration:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -86,6 +86,6 @@ Each of the new coding style rules has corresponding parameter in the behavior d
<parameter name="strip_comments" value="false" />
</behavior>
</table>
-{% endhighlight %}
+```
You can change these settings to better match your own coding styles.
View
64 behaviors/archivable.markdown
@@ -11,40 +11,40 @@ The `archivable` behavior gives model objects the ability to be copied to an arc
In the `schema.xml`, use the `<behavior>` tag to add the `archivable` behavior to a table:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="archivable" />
</table>
-{% endhighlight %}
+```
Rebuild your model, insert the table creation sql again, and you're ready to go. The model now has one new table, `book_archive`, with the same columns as the original `book` table. This table stores the archived `books` together with their archive date. To archive an object, call the `archive()` method:
-{% highlight php %}
+```php
<?php
$book = new Book();
$book->setTitle('War And Peace');
$book->save();
// copy the current Book to a BookArchive object and save it
$archivedBook = $book->archive();
-{% endhighlight %}
+```
The archive table contains only the freshest copy of each archived objects. Archiving an object twice doesn't create a new record in the archive table, but updates the existing archive.
The `book_archive` table has generated ActiveRecord and ActiveQuery classes, so you can browse the archive at will. The archived objects have the same primary key as the original objects. In addition, they contain an `ArchivedAt` property storing the date where the object was archived.
-{% highlight php %}
+```php
<?php
// find the archived book
$archivedBook = BookArchiveQuery::create()->findPk($book->getId());
echo $archivedBook->getTitle(); // 'War And Peace'
echo $archivedBook->getArchivedAt(); // 2011-08-23 18:14:23
-{% endhighlight %}
+```
The ActiveRecord class of an `archivable` model has more methods to deal with the archive:
-{% highlight php %}
+```php
// restore an object to the state it had when last archived
$book->restoreFromArchive();
// find the archived version of an existing book
@@ -52,11 +52,11 @@ $archivedBook = $book->getArchive();
// populate a book based on an archive
$book = new book();
$book->populateFromArchive($archivedBook);
-{% endhighlight %}
+```
By default, an `archivable` model is archived just before deletion:
-{% highlight php %}
+```php
<?php
$book = new Book();
$book->setTitle('Sense and Sensibility');
@@ -67,40 +67,40 @@ echo BookQuery::create()->count(); // 0
// find the archived book
$archivedBook = BookArchiveQuery::create()
->findOneByTitle('Sense and Sensibility');
-{% endhighlight %}
+```
>**Tip**<br />The behavior does not take care of archiving the related objects. This may be surprising on deletions if the deleted object has 'ON DELETE CASCADE' foreign keys. If you want to archive relations, override the generated `archive()` method in the ActiveRecord class with your custom logic.
To recover deleted objects, use `populateFromArchive()` on a new object and save it:
-{% highlight php %}
+```php
<?php
// create a new object based on the archive
$book = new Book();
$book->populateFromArchive($archivedBook);
$book->save();
echo $book->getTitle(); // 'Sense and Sensibility'
-{% endhighlight %}
+```
If you want to delete an `archivable` object without archiving it, use the `deleteWithoutArchive()` method generated by the behavior:
-{% highlight php %}
+```php
<?php
// delete the book but don't archive it
$book->deleteWithoutArchive();
-{% endhighlight %}
+```
## Archiving A Set Of Objects ##
The `archivable` behavior also generates an `archive()` method on the generated ActiveQuery class. That means you can easily archive a set of objects, in the same way you archive a single object:
-{% highlight php %}
+```php
<?php
// archive all books having a title starting with "war"
$nbArchivedObjects = BookQuery::create()
->filterByTitle('War%')
->archive();
-{% endhighlight %}
+```
`archive()` returns the number of archived objects, and not the current ActiveQuery object, so it's a termination method.
@@ -108,7 +108,7 @@ $nbArchivedObjects = BookQuery::create()
As explained earlier, an `archivable` model is archived just before deletion by default. This is also true when using the `delete()` and `deleteAll()` methods of the ActiveQuery class:
-{% highlight php %}
+```php
<?php
// delete and archive all books having a title starting with "war"
$nbDeletedObjects = BookQuery::create()
@@ -126,13 +126,13 @@ $nbDeletedObjects = BookQuery::create()
->filterByTitle('War%')
->setArchiveOnDelete(false)
->delete();
-{% endhighlight %}
+```
## Archiving on Insert, Update, or Delete ##
As explained earlier, the `archivable` behavior archives objects on deletion by default, but insertions and updates don't trigger the `archive()` method. You can disable the auto archiving on deletion, as well as enable it for insertion and update, in the behavior `<parameter>` tags. Here is the default configuration:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -142,7 +142,7 @@ As explained earlier, the `archivable` behavior archives objects on deletion by
<parameter name="archive_on_delete" value="true" />
</behavior>
</table>
-{% endhighlight %}
+```
If you turn on `archive_on_insert`, a call to `save()` on a new ActiveRecord object archives it - unless you call `saveWithoutArchive()`.
@@ -150,19 +150,19 @@ If you turn on `archive_on_update`, a call to `save()` on an existing ActiveReco
Of course, even if `archive_on_insert` or any of the similar parameters isn't turned on, you can always archive manually an object after persisting it by simply calling `archive()`:
-{% highlight php %}
+```php
<?php
// create a new object, save it, and archive it
$book = new Book();
$book->save();
$book->archive();
-{% endhighlight %}
+```
## Archiving To Another Database ##
The behavior can use another database connection for the archive table, to make it safer. To allow cross-database archives, you must declare the archive schema manually in another XML schema, and reference the archive class on in the behavior parameter:
-{% highlight xml %}
+```xml
<database name="main">
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
@@ -179,7 +179,7 @@ The behavior can use another database connection for the archive table, to make
<column name="archived_at" type="TIMESTAMP" />
</table>
</database>
-{% endhighlight %}
+```
The archive table must have the same columns as the archivable table, but without autoIncrements, and without foreign keys.
@@ -189,7 +189,7 @@ With this setup, the behavior uses `MyBookArchive` and `MyBookArchiveQuery` for
If you use `archivable` as a replacement for the `soft_delete` behavior, here is how you should update your code:
-{% highlight php %}
+```php
<?php
// do a soft delete
$book->delete(); // with soft_delete
@@ -218,32 +218,32 @@ $book->unDelete();
$book = new Book();
$book->populateFromArchive($bookArchive);
$book->save();
-{% endhighlight %}
+```
## Additional Parameters ##
You can change the name of the archive table added by the behavior by setting the `archive_table` parameter. If the table doesn't exist, the behavior creates it for you.
-{% highlight xml %}
+```xml
<behavior name="archivable">
<parameter name="archive_table" value="special_book_archive" />
</behavior>
-{% endhighlight %}
+```
>**Tip**<br />The `archive_table` and `archive_class` parameters are mutually exclusive. You can only use either one of the two.
You can also change the name of the column storing the archive date:
-{% highlight xml %}
+```xml
<behavior name="archivable">
<parameter name="archived_at_column" value="archive_date" />
</behavior>
-{% endhighlight %}
+```
Alternatively, you can disable the addition of an archive date column altogether:
-{% highlight xml %}
+```xml
<behavior name="archivable">
<parameter name="log_archived_at" value="false" />
</behavior>
-{% endhighlight %}
+```
View
24 behaviors/auto-add-pk.markdown
@@ -11,45 +11,45 @@ The `auto_add_pk` behavior adds a primary key columns to the tables that don't h
In the `schema.xml`, use the `<behavior>` tag to add the `auto_add_pk` behavior to a table:
-{% highlight xml %}
+```xml
<table name="book">
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="auto_add_pk" />
</table>
-{% endhighlight %}
+```
Rebuild your model, and insert the table creation sql. You will notice that the `book` table has two columns and not just one. The behavior added an `id` column, of type integer and autoincremented. This column can be used as any other column:
-{% highlight php %}
+```php
<?php
$b = new Book();
$b->setTitle('War And Peace');
$b->save();
echo $b->getId(); // 1
-{% endhighlight %}
+```
This behavior is more powerful if you add it to the database instead of a table. That way, it will alter all tables not defining a primary key column - and leave the others unchanged.
-{% highlight xml %}
+```xml
<database name="bookstore" defaultIdMethod="native">
<behavior name="auto_add_pk" />
<table name="book">
<column name="title" type="VARCHAR" required="true" primaryString="true" />
</table>
</database>
-{% endhighlight %}
+```
You can even enable it for all your databases by adding it to the default behaviors in your `build.properties` file:
-{% highlight ini %}
+```ini
propel.behavior.default = auto_add_pk
-{% endhighlight %}
+```
## Parameters ##
By default, the behavior adds a column named `id` to the table if the table has no primary key. You can customize all the attributes of the added column by setting corresponding parameters in the behavior definition:
-{% highlight xml %}
+```xml
<database name="bookstore" defaultIdMethod="native">
<behavior name="auto_add_pk">
<parameter name="name" value="identifier" />
@@ -60,15 +60,15 @@ By default, the behavior adds a column named `id` to the table if the table has
<column name="title" type="VARCHAR" required="true" primaryString="true" />
</table>
</database>
-{% endhighlight %}
+```
Once you regenerate your model, the column is now named differently:
-{% highlight php %}
+```php
<?php
$b = new Book();
$b->setTitle('War And Peace');
$b->setIdentifier(1);
$b->save();
echo $b->getIdentifier(); // 1
-{% endhighlight %}
+```
View
36 behaviors/delegate.markdown
@@ -11,7 +11,7 @@ The `delegate` behavior allows a model to delegate methods to one of its relatio
In the `schema.xml`, use the `<behavior>` tag to add the `delegate` behavior to a table. In the `<parameter>` tag, specify the table that the current table delegates to as the `to` parameter:
-{% highlight xml %}
+```xml
<table name="account">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="login" type="VARCHAR" required="true" />
@@ -24,11 +24,11 @@ In the `schema.xml`, use the `<behavior>` tag to add the `delegate` behavior to
<column name="email" type="VARCHAR" />
<column name="telephone" type="VARCHAR" />
</table>
-{% endhighlight %}
+```
Rebuild your model, insert the table creation sql again, and you're ready to go. The delegate `profile` table is now related to the `account` table using a one-to-one relationship. That means that the behavior creates a foreign primary key in the `profile` table. In fact, everything happens as if you had defined the following schema:
-{% highlight xml %}
+```xml
<table name="account">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="login" type="VARCHAR" required="true" />
@@ -42,13 +42,13 @@ Rebuild your model, insert the table creation sql again, and you're ready to go.
<reference local="id" foreign="id" />
</foreign-key>
</table>
-{% endhighlight %}
+```
>**Tip**<br />If the delegate table already has a foreign key to the main table, the behavior doesn't recreate it. It allows you to have full control over the relationship between the two tables.
In addition, the ActiveRecord `Account` class now provides integrated delegation capabilities. That means that it offers to handle directly the columns of the `Profile` model, while in reality it finds or create a related `Profile` object and calls the methods on this delegate:
-{% highlight php %}
+```php
<?php
$account = new Account();
$account->setLogin('francois');
@@ -68,11 +68,11 @@ $account->save();
// retrieve delegated data directly from the main object
echo $account->getEmail(); // francois@example.com
-{% endhighlight %}
+```
Getter and setter methods for delegate columns don't exist on the main object ; the delegation is handled by the magical `__call()` method. Therefore, the delegation also works for custom methods in the delegate table.
-{% highlight php %}
+```php
<?php
class Profile extends BaseProfile
{
@@ -86,13 +86,13 @@ class Profile extends BaseProfile
$account = new Account();
$account->setFakeEmail(); // delegates to Profile::setFakeEmail()
-{% endhighlight %}
+```
## Delegating Using a Many-To-One Relationship ##
Instead of adding a one-to-one relationship, the `delegate` behavior can take advantage of an existing many-to-one relationship. For instance:
-{% highlight xml %}
+```xml
<table name="player">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="first_name" type="VARCHAR" />
@@ -112,11 +112,11 @@ Instead of adding a one-to-one relationship, the `delegate` behavior can take ad
</behavior>
</table>
-{% endhighlight %}
+```
In that case, the behavior doesn't modify the foreign keys, it just proxies method called on `Basketballer` to the related `Player`, or creates one if it doesn't exist:
-{% highlight php %}
+```php
<?php
$basketballer = new Basketballer();
$basketballer->setPoints(101);
@@ -136,7 +136,7 @@ $basketballer->save();
// retrieve delegated data directly from the main object
echo $basketballer->getFirstName(); // Michael
-{% endhighlight %}
+```
And since several models can delegate to the same player object, that means that a single player can have both basketball and soccer stats!
@@ -146,7 +146,7 @@ And since several models can delegate to the same player object, that means that
Delegation allows to delegate to several tables. Just separate the name of the delegate tables by commas in the `to` parameter of the `delegate` behavior tag in your schema to delegate to several tables:
-{% highlight xml %}
+```xml
<table name="account">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="login" type="VARCHAR" required="true" />
@@ -163,11 +163,11 @@ Delegation allows to delegate to several tables. Just separate the name of the d
<column name="preferred_color" type="VARCHAR" />
<column name="max_size" type="INTEGER" />
</table>
-{% endhighlight %}
+```
Now the `Account` class has two delegates, that can be addressed seamlessly:
-{% highlight php %}
+```php
<?php
$account = new Account();
$account->setLogin('francois');
@@ -182,7 +182,7 @@ $account->setMaxSize('200');
// save the account and its profile and its preference
$account->save();
-{% endhighlight %}
+```
On the other hand, it is not possible to cascade delegation to yet another model. So even if the `profile` table delegates to another `detail` table, the methods of the `Detail` model won't be accessibe to the `Profile` objects.
@@ -190,7 +190,7 @@ On the other hand, it is not possible to cascade delegation to yet another model
The `delegate` behavior takes only one parameter, the list of delegate tables:
-{% highlight xml %}
+```xml
<table name="account">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="login" type="VARCHAR" required="true" />
@@ -199,6 +199,6 @@ The `delegate` behavior takes only one parameter, the list of delegate tables:
<parameter name="to" value="profile, preference" />
</behavior>
</table>
-{% endhighlight %}
+```
Note that the delegate tables must exist, but they don't need to share a relationship with the main table (in which case the behavior creates a one-to-one relationship).
View
44 behaviors/i18n.markdown
@@ -11,7 +11,7 @@ The `i18n` behavior provides internationalization to any !ActiveRecord object. U
In the `schema.xml`, use the `<behavior>` tag to add the `i18n` behavior to a table. In the `<parameters>` tag, list the columns that need internationalization as the `i18n_columns` parameter:
-{% highlight xml %}
+```xml
<table name="item">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="name" type="VARCHAR" required="true" />
@@ -22,11 +22,11 @@ In the `schema.xml`, use the `<behavior>` tag to add the `i18n` behavior to a ta
<parameter name="i18n_columns" value="name, description" />
</behavior>
</table>
-{% endhighlight %}
+```
Rebuild your model, insert the table creation sql again, and you're ready to go. The internationalized columns have now been moved to a new translation table called `item_i18n`; this new table contains a `locale` column, and shares a many-to-one relationship with the `item` table. In fact, everything happens as if you had defined the following schema:
-{% highlight xml %}
+```xml
<table name="item">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="price" type="FLOAT" />
@@ -41,11 +41,11 @@ Rebuild your model, insert the table creation sql again, and you're ready to go.
<reference local="id" foreign="id" />
</foreign-key>
</table>
-{% endhighlight %}
+```
In addition, the ActiveRecord Item class now provides integrated translation capabilities.
-{% highlight php %}
+```php
<?php
$item = new Item();
$item->setPrice('12.99');
@@ -72,7 +72,7 @@ $item->setLocale('en_US');
echo $item->getName(); // Microwave oven
$item->setLocale('fr_FR');
echo $item->getName(); // Four micro-ondes
-{% endhighlight %}
+```
Getter an setter methods for internationalized columns still exist on the main object ; they are just proxy methods to the current translation object, using the same signature and phpDoc for better IDE integration.
@@ -82,7 +82,7 @@ Getter an setter methods for internationalized columns still exist on the main o
If you prefer to deal with real translation objects, the behavior generates a `getTranslation()` method on the !ActiveRecord class, which returns a translation object with the required locale.
-{% highlight php %}
+```php
<?php
$item = new Item();
$item->setPrice('12.99');
@@ -104,24 +104,24 @@ $t2->setName('Four micro-ondes');
// these translation objects are already related to the main item
// and therefore get saved together with it
$item->save(); // already saves the two translations
-{% endhighlight %}
+```
>**Tip**<br />Or course, if a translation already exists for a given locale, `getTranslation()` returns the existing translation and not a new one.
You can remove a translation using `removeTranslation()` and a locale:
-{% highlight php %}
+```php
<?php
$item = ItemQuery::create()->findPk(1);
// remove the French translation
$item->removeTranslation('fr_FR');
-{% endhighlight %}
+```
## Querying For Objects With Translations ##
If you need to display a list, the following code will issue n+1 SQL queries, n being the number of items:
-{% highlight php %}
+```php
<?php
$items = ItemQuery::create()->find(); // one query to retrieve all items
$locale = 'en_US';
@@ -130,11 +130,11 @@ foreach ($items as $item) {
$item->setLocale($locale);
echo $item->getName(); // one query to retrieve the English translation
}
-{% endhighlight %}
+```
Fortunately, the behavior adds methods to the Query class, allowing you to hydrate both the `Item` objects and the related `ItemI18n` objects for the given locale:
-{% highlight php %}
+```php
<?php
$items = ItemQuery::create()
->joinWithI18n('en_US')
@@ -143,7 +143,7 @@ foreach ($items as $item) {
echo $item->getPrice();
echo $item->getName(); // no additional query
}
-{% endhighlight %}
+```
In addition to hydrating translations, `joinWithI18n()` sets the correct locale on results, so you don't need to call `setLocale()` for each result.
@@ -151,14 +151,14 @@ In addition to hydrating translations, `joinWithI18n()` sets the correct locale
If you need to search items using a condition on a translation, use the generated `useI18nQuery()` as you would with any `useXXXQuery()` method:
-{% highlight php %}
+```php
<?php
$items = ItemQuery::create()
->useI18nQuery('en_US') // tests the condition on the English translation
->filterByName('Microwave oven')
->endUse()
->find();
-{% endhighlight %}
+```
## Symfony Compatibility ##
@@ -166,7 +166,7 @@ This behavior is entirely compatible with the i18n behavior for symfony. That me
So the following schema is exactly equivalent to the first one in this tutorial:
-{% highlight xml %}
+```xml
<table name="item">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="price" type="FLOAT" />
@@ -180,7 +180,7 @@ So the following schema is exactly equivalent to the first one in this tutorial:
<column name="name" type="VARCHAR" required="true" />
<column name="description" type="LONGVARCHAR" />
</table>
-{% endhighlight %}
+```
Such a schema is almost similar to a schema built for symfony; that means that the Propel i18n behavior is a drop-in replacement for symfony's i18n behavior, keeping BC but improving performance and usability.
@@ -188,7 +188,7 @@ Such a schema is almost similar to a schema built for symfony; that means that t
If you don't specify a locale when dealing with a translatable object, Propel uses the default English locale 'en_US'. This default can be overridden in the schema using the `default_locale` parameter:
-{% highlight xml %}
+```xml
<table name="item">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="name" type="VARCHAR" required="true" />
@@ -200,11 +200,11 @@ If you don't specify a locale when dealing with a translatable object, Propel us
<parameter name="default_locale" value="fr_FR" />
</behavior>
</table>
-{% endhighlight %}
+```
You can change the name of the locale column added by the behavior by setting the `locale_column` parameter. Also, you can change the table name, the primary key name and the phpName of the i18n table by setting the `i18n_table`, `i18n_pk_name` and `i18n_phpname` parameters:
-{% highlight xml %}
+```xml
<table name="item">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="name" type="VARCHAR" required="true" />
@@ -219,4 +219,4 @@ You can change the name of the locale column added by the behavior by setting th
<parameter name="i18n_phpname" value="ItemTranslation" />
</behavior>
</table>
-{% endhighlight %}
+```
View
72 behaviors/nested-set.markdown
@@ -12,17 +12,17 @@ Many applications need to store hierarchical data in the model. For instance, a
## Basic Usage ##
In the `schema.xml`, use the `<behavior>` tag to add the `nested_set` behavior to a table:
-{% highlight xml %}
+```xml
<table name="section">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="nested_set" />
</table>
-{% endhighlight %}
+```
Rebuild your model, insert the table creation sql again, and you're ready to go. The model now has the ability to be inserted into a tree structure, as follows:
-{% highlight php %}
+```php
<?php
$s1 = new Section();
$s1->setTitle('Home');
@@ -47,13 +47,13 @@ $s2:World
| \
$s3:Europe $s4:Business
*/
-{% endhighlight %}
+```
You can continue to insert new nodes as children or siblings of existing nodes, using any of the `insertAsFirstChildOf()`, `insertAsLastChildOf()`, `insertAsPrevSiblingOf()`, and `insertAsNextSiblingOf()` methods.
Once you have built a tree, you can traverse it using any of the numerous methods the `nested_set` behavior adds to the query and model objects. For instance:
-{% highlight php %}
+```php
<?php
$rootNode = SectionQuery::create()->findRoot(); // $s1
$worldNode = $rootNode->getFirstChild(); // $s2
@@ -63,11 +63,11 @@ $allSections = $rootNode->getDescendants(); // array($s2, $s3, $s4)
// you can also chain the methods
$europeNode = $rootNode->getLastChild()->getPrevSibling()->getFirstChild(); // $s3
$path = $europeNode->getAncestors(); // array($s1, $s2)
-{% endhighlight %}
+```
The nodes returned by these methods are regular Propel model objects, with access to the properties and related models. The `nested_set` behavior also adds inspection methods to nodes:
-{% highlight php %}
+```php
<?php
echo $s2->isRoot(); // false
echo $s2->isLeaf(); // false
@@ -75,7 +75,7 @@ echo $s2->getLevel(); // 1
echo $s2->hasChildren(); // true
echo $s2->countChildren(); // 1
echo $s2->hasSiblings(); // true
-{% endhighlight %}
+```
Each of the traversal and inspection methods result in a single database query, whatever the position of the node in the tree. This is because the information about the node position in the tree is stored in three columns of the model, named `tree_left`, `tree_right`, and `tree_level`. The value given to these columns is determined by the nested set algorithm, and it makes read queries much more effective than trees using a simple `parent_id` foreign key.
@@ -83,7 +83,7 @@ Each of the traversal and inspection methods result in a single database query,
You can move a node - and its subtree - across the tree using any of the `moveToFirstChildOf()`, `moveToLastChildOf()`, `moveToPrevSiblingOf()`, and `moveToLastSiblingOf()` methods. These operations are immediate and don't require that you save the model afterwards:
-{% highlight php %}
+```php
<?php
// move the entire "World" section under "Business"
$s2->moveToFirstChildOf($s4);
@@ -105,11 +105,11 @@ $s4:Business $s3:Europe
|
$s2:World
*/
-{% endhighlight %}
+```
You can delete the descendants of a node using `deleteDescendants()`:
-{% highlight php %}
+```php
<?php
// move the entire "World" section under "Business"
$s4->deleteDescendants($s4);
@@ -118,7 +118,7 @@ $s4->deleteDescendants($s4);
| \
$s4:Business $s3:Europe
*/
-{% endhighlight %}
+```
If you `delete()` a node, all its descendants are deleted in cascade. To avoid accidental deletion of an entire tree, calling `delete()` on a root node throws an exception. Use the `delete()` Query method instead to delete an entire tree.
@@ -126,27 +126,27 @@ If you `delete()` a node, all its descendants are deleted in cascade. To avoid a
The `nested_set` behavior adds numerous methods to the generated Query object. You can use these methods to build more complex queries. For instance, to get all the children of the root node ordered by title, build a Query as follows:
-{% highlight php %}
+```php
<?php
$children = SectionQuery::create()
->childrenOf($rootNode)
->orderByTitle()
->find();
-{% endhighlight %}
+```
Alternatively, if you already have an existing query method, you can pass it to the model object's methods to filter the results:
-{% highlight php %}
+```php
<?php
$orderQuery = SectionQuery::create()->orderByTitle();
$children = $rootNode->getChildren($orderQuery);
-{% endhighlight %}
+```
## Multiple Trees ##
When you need to store several trees for a single model - for instance, several threads of posts in a forum - use a _scope_ for each tree. This requires that you enable scope tree support in the behavior definition by setting the `use_scope` parameter to `true`:
-{% highlight xml %}
+```xml
<table name="post">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="body" type="VARCHAR" required="true" primaryString="true" />
@@ -158,18 +158,18 @@ When you need to store several trees for a single model - for instance, several
<reference local="thread_id" foreign="id" />
</foreign-key>
</table>
-{% endhighlight %}
+```
Now, after rebuilding your model, you can have as many trees as required:
-{% highlight php %}
+```php
<?php
$thread = ThreadQuery::create()->findPk(123);
$firstPost = PostQuery::create()->findRoot($thread->getId()); // first message of the discussion
$discussion = PostQuery::create()->findTree(thread->getId()); // all messages of the discussion
PostQuery::create()->inTree($thread->getId())->delete(); // delete an entire discussion
$firstPostOfEveryDiscussion = PostQuery::create()->findRoots();
-{% endhighlight %}
+```
## Using a RecursiveIterator ##
@@ -177,31 +177,31 @@ An alternative way to browse a tree structure extensively is to use a [Recursive
For instance, to display an entire tree structure, you can use the following code:
-{% highlight php %}
+```php
<?php
$root = SectionQuery::create()->findRoot();
foreach ($root->getIterator() as $node) {
echo str_repeat(' ', $node->getLevel()) . $node->getTitle() . "\n";
}
-{% endhighlight %}
+```
The iterator parses the tree in a recursive way by retrieving the children of every node. This can be quite effective on very large trees, since the iterator hydrates only a few objects at a time.
Beware, though, that the iterator executes many queries to parse a tree. On smaller trees, prefer the `getBranch()` method to execute only one query, and hydrate all records at once:
-{% highlight php %}
+```php
<?php
$root = SectionQuery::create()->findRoot();
foreach ($root->getBranch() as $node) {
echo str_repeat(' ', $node->getLevel()) . $node->getTitle() . "\n";
}
-{% endhighlight %}
+```
## Parameters ##
By default, the behavior adds three columns to the model - four if you use the scope feature. You can use custom names for the nested sets columns. The following schema illustrates a complete customization of the behavior:
-{% highlight xml %}
+```xml
<table name="post">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="lft" type="INTEGER" />
@@ -220,11 +220,11 @@ By default, the behavior adds three columns to the model - four if you use the s
<reference local="thread_id" foreign="id" />
</foreign-key>
</table>
-{% endhighlight %}
+```
Whatever name you give to your columns, the `nested_sets` behavior always adds the following proxy methods, which are mapped to the correct column:
-{% highlight php %}
+```php
<?php
$post->getLeftValue(); // returns $post->lft
$post->setLeftValue($left);
@@ -234,11 +234,11 @@ $post->getLevel(); // returns $post->lvl
$post->setLevel($level);
$post->getScopeValue(); // returns $post->thread_id
$post->setScopeValue($scope);
-{% endhighlight %}
+```
If your application used the old nested sets builder from Propel 1.4, you can enable the `method_proxies` parameter so that the behavior generates method proxies for the methods that used a different name (e.g. `createRoot()` for `makeRoot()`, `retrieveFirstChild()` for `getFirstChild()`, etc.
-{% highlight xml %}
+```xml
<table name="section">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -246,13 +246,13 @@ If your application used the old nested sets builder from Propel 1.4, you can en
<parameter name="method_proxies" value="true" />
</behavior>
</table>
-{% endhighlight %}
+```
## Complete API ##
Here is a list of the methods added by the behavior to the model objects:
-{% highlight php %}
+```php
<?php
// storage columns accessors
int getLeftValue()
@@ -317,11 +317,11 @@ $node retrieveNextSibling()
$node retrieveFirstChild()
$node retrieveLastChild()
array getPath()
-{% endhighlight %}
+```
The behavior also adds some methods to the Query classes:
-{% highlight php %}
+```php
<?php
// tree filter methods
query descendantsOf($node)
@@ -340,18 +340,18 @@ query orderByLevel($reverse = false)
// termination methods
$node findRoot($scope = null)
coll findTree($scope = null)
-{% endhighlight %}
+```
Lastly, the behavior adds a few methods to the Peer classes:
-{% highlight php %}
+```php
<?php
$node retrieveRoot($scope = null)
array retrieveTree($scope = null)
int deleteTree($scope = null)
// only for behavior with use_scope
array retrieveRoots(Criteria $c = null)
-{% endhighlight %}
+```
## TODO ##
View
20 behaviors/query-cache.markdown
@@ -10,35 +10,35 @@ The `query_cache` behavior gives a speed boost to Propel queries by caching the
## Basic Usage ##
In the `schema.xml`, use the `<behavior>` tag to add the `query_cache` behavior to a table:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="query_cache" />
</table>
-{% endhighlight %}
+```
After you rebuild your model, all the queries on this object can now be cached. To trigger the query cache on a particular query, just give it a query key using the `setQueryKey()` method. The key is a unique identifier that you can choose, later used for cache lookups:
-{% highlight php %}
+```php
<?php
$title = 'War And Peace';
$books = BookQuery::create()
->setQueryKey('search book by title')
->filterByTitle($title)
->findOne();
-{% endhighlight %}
+```
The first time Propel executes the termination method, it computes the SQL translation of the Query object and stores it into a cache backend (APC by default). Next time you run the same query, it executes faster, even with different parameters:
-{% highlight php %}
+```php
<?php
$title = 'Anna Karenina';
$books = BookQuery::create()
->setQueryKey('search book by title')
->filterByTitle($title)
->findOne();
-{% endhighlight %}
+```
>**Tip**<br />The more complex the query, the greater the boost you get from the query cache behavior.
@@ -46,7 +46,7 @@ $books = BookQuery::create()
You can change the cache backend and the cache lifetime (in seconds) by setting the `backend` and `lifetime` parameters:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -55,11 +55,11 @@ You can change the cache backend and the cache lifetime (in seconds) by setting
<parameter name="lifetime" value="600" />
</behavior>
</table>
-{% endhighlight %}
+```
To implement a custom cache backend, just override the generated `cacheContains()`, `cacheFetch()` and `cacheStore()` methods in the Query object. For instance, to implement query cache using Zend_Cache and memcached, try the following:
-{% highlight php %}
+```php
<?php
class BookQuery extends BaseBookQuery
{
@@ -100,4 +100,4 @@ class BookQuery extends BaseBookQuery
return self::$cacheBackend;
}
}
-{% endhighlight %}
+```
View
36 behaviors/sluggable.markdown
@@ -10,48 +10,48 @@ The `sluggable` behavior allows a model to offer a human readable identifier tha
## Basic Usage ##
In the `schema.xml`, use the `<behavior>` tag to add the `sluggable` behavior to a table:
-{% highlight xml %}
+```xml
<table name="post">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="sluggable" />
</table>
-{% endhighlight %}
+```
Rebuild your model, insert the table creation sql again, and you're ready to go. The model now has an additional getter for its slug, which is automatically set before the object is saved:
-{% highlight php %}
+```php
<?php
$p1 = new Post();
$p1->setTitle('Hello, World!');
$p1->save();
echo $p1->getSlug(); // 'hello-world'
-{% endhighlight %}
+```
By default, the behavior uses the string representation of the object to build the slug. In the example above, the `title` column is defined as `primaryString`, so the slug uses this column as a base string. The string is then cleaned up in order to allow it to appear in a URL. In the process, blanks and special characters are replaced by a dash, and the string is lowercased.
>**Tip**<br />The slug is unique by design. That means that if you create a new object and that the behavior calculates a slug that already exists, the string is modified to be unique:
-{% highlight php %}
+```php
<?php
$p2 = new Post();
$p2->setTitle('Hello, World!');
$p2->save();
echo $p2->getSlug(); // 'hello-world-1'
-{% endhighlight %}
+```
The generated model query offers a `findOneBySlug()` method to easily retrieve a model object based on its slug:
-{% highlight php %}
+```php
<?php
$p = PostQuery::create()->findOneBySlug('hello-world');
-{% endhighlight %}
+```
## Parameters ##
By default, the behavior adds one column to the model. If this column is already described in the schema, the behavior detects it and doesn't add it a second time. The behavior parameters allow you to use custom patterns for the slug composition. The following schema illustrates a complete customization of the behavior:
-{% highlight xml %}
+```xml
<table name="post">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -66,25 +66,25 @@ By default, the behavior adds one column to the model. If this column is already
<parameter name="scope_column" value="" />
</behavior>
</table>
-{% endhighlight %}
+```
Whatever `slug_column` name you choose, the `sluggable` behavior always adds the following proxy methods, which are mapped to the correct column:
-{% highlight php %}
+```php
<?php
$post->getSlug(); // returns $post->url
$post->setSlug($slug); // $post->url = $slug
-{% endhighlight %}
+```
The `slug_pattern` parameter is the rule used to build the raw slug based on the object properties. Any substring enclosed between brackets '{}' is turned into a getter, so the `Post` class generates slugs as follows:
-{% highlight php %}
+```php
<?php
protected function createRawSlug()
{
return '/posts/' . $this->getTitle();
}
-{% endhighlight %}
+```
Incidentally, that means that you can use names that don't match a real column phpName, as long as your model provides a getter for it.
@@ -92,12 +92,12 @@ The `replace_pattern` parameter is a regular expression that shows all the chara
The `separator` parameter is the character that separates the slug from the incremental index added in case of non-unicity. Set as '/', it makes `Post` objects sharing the same title have the following slugs:
-{% highlight text %}
+```text
'posts/hello-world'
'posts/hello-world/1'
'posts/hello-world/2'
...
-{% endhighlight %}
+```
A `permanent` slug is not automatically updated when the fields that constitute it change. This is useful when the slug serves as a permalink, that should work even when the model object properties change. Note that you can still manually change the slug in a model using the `permanent` setting by calling `setSlug()`;
@@ -105,7 +105,7 @@ A `permanent` slug is not automatically updated when the fields that constitute
The slug is generated by the object when it is saved, via the `createSlug()` method. This method does several operations on a simple string:
-{% highlight php %}
+```php
<?php
protected function createSlug()
{
@@ -128,6 +128,6 @@ protected function createRawSlug()
return $slug;
}
-{% endhighlight %}
+```
You can override any of these methods in your model class, in order to implement a custom slug logic.
View
36 behaviors/soft-delete.markdown
@@ -12,17 +12,17 @@ The `soft_delete` behavior overrides the deletion methods of a model object to m
## Basic Usage ##
In the `schema.xml`, use the `<behavior>` tag to add the `soft_delete` behavior to a table:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="soft_delete" />
</table>
-{% endhighlight %}
+```
Rebuild your model, insert the table creation sql again, and you're ready to go. The model now has one new column, `deleted_at`, that stores the deletion date. Select queries don't return the deleted objects:
-{% highlight php %}
+```php
<?php
$b = new Book();
$b->setTitle('War And Peace');
@@ -31,7 +31,7 @@ $b->delete();
echo $b->isDeleted(); // false
echo $b->getDeletedAt(); // 2009-10-02 18:14:23
$books = BookQuery::create()->find(); // empty collection
-{% endhighlight %}
+```
Behind the curtain, the behavior adds a condition to every SELECT query to return only records where the `deleted_at` column is null. That's why the deleted objects don't appear anymore upon selection.
@@ -39,22 +39,22 @@ _Warning_gg Deleted results may show up in related results (i.e. when you use `j
You can include deleted results in a query by calling the `includeDeleted()` filter:
-{% highlight php %}
+```php
<?php
$book = BookQuery::create()
->includeDeleted()
->findOne();
echo $book->getTitle(); // 'War And Peace'
-{% endhighlight %}
+```
You can also turn off the query alteration for the next query by calling the static method `disableSoftDelete()` on the related Query object:
-{% highlight php %}
+```php
<?php
BookQuery::disableSoftDelete();
$book = BookQuery::create()->findOne();
echo $book->getTitle(); // 'War And Peace'
-{% endhighlight %}
+```
Note that `find()` and other selection methods automatically re-enable the `soft_delete` filter, so `disableSoftDelete()` is really a single shot method. You can also enable the query alteration manually by calling the `enableSoftDelete()` method on Query objects.
@@ -62,26 +62,26 @@ Note that `find()` and other selection methods automatically re-enable the `soft
If you want to recover a deleted object, use the `unDelete()` method:
-{% highlight php %}
+```php
<?php
$book->unDelete();
$books = BookQuery::create()->find();
$book = $books[0];
echo $book->getTitle(); // 'War And Peace'
-{% endhighlight %}
+```
If you want to force the real deletion of an object, call the `forceDelete()` method:
-{% highlight php %}
+```php
<?php
$book->forceDelete();
echo $book->isDeleted(); // true
$books = BookQuery::create()->find(); // empty collection
-{% endhighlight %}
+```
The query methods `delete()` and `deleteAll()` also perform a soft deletion, unless you disable the behavior on the peer class:
-{% highlight php %}
+```php
<?php
$b = new Book();
$b->setTitle('War And Peace');
@@ -102,13 +102,13 @@ BookQuery::create()->delete();
BookQuery::create()->filterByTitle('%Lo%')->forceDelete();
// To remove all use
BookQuery::create()->forceDeleteAll();
-{% endhighlight %}
+```
## Parameters ##
You can change the name of the column added by the behavior by setting the `deleted_column` parameter:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -117,9 +117,9 @@ You can change the name of the column added by the behavior by setting the `dele
<parameter name="deleted_column" value="my_deletion_date" />
</behavior>
</table>
-{% endhighlight %}
+```
-{% highlight php %}
+```php
<?php
$b = new Book();
$b->setTitle('War And Peace');
@@ -127,4 +127,4 @@ $b->save();
$b->delete();
echo $b->getMyDeletionDate(); // 2009-10-02 18:14:23
$books = BookQuery::create()->find(); // empty collection
-{% endhighlight %}
+```
View
68 behaviors/sortable.markdown
@@ -10,17 +10,17 @@ The `sortable` behavior allows a model to become an ordered list, and provides n
## Basic Usage ##
In the `schema.xml`, use the `<behavior>` tag to add the `sortable` behavior to a table:
-{% highlight xml %}
+```xml
<table name="task">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="sortable" />
</table>
-{% endhighlight %}
+```
Rebuild your model, insert the table creation sql again, and you're ready to go. The model now has the ability to be inserted into an ordered list, as follows:
-{% highlight php %}
+```php
<?php
$t1 = new Task();
$t1->setTitle('Wash the dishes');
@@ -34,13 +34,13 @@ $t3 = new Task();
$t3->setTitle('Rest a little');
$t3->save()
echo $t3->getRank(); // 3
-{% endhighlight %}
+```
As long as you save new objects, Propel gives them the first available rank in the list.
Once you have built an ordered list, you can traverse it using any of the methods added by the `sortable` behavior. For instance:
-{% highlight php %}
+```php
<?php
$firstTask = TaskQuery::create()->findOneByRank(1); // $t1
$secondTask = $firstTask->getNext(); // $t2
@@ -51,22 +51,22 @@ $allTasks = TaskQuery::create()->findList();
// => collection($t1, $t2, $t3)
$allTasksInReverseOrder = TaskQuery::create()->orderByRank('desc')->find();
// => collection($t3, $t2, $t2)
-{% endhighlight %}
+```
The results returned by these methods are regular Propel model objects, with access to the properties and related models. The `sortable` behavior also adds inspection methods to objects:
-{% highlight php %}
+```php
<?php
echo $t2->isFirst(); // false
echo $t2->isLast(); // false
echo $t2->getRank(); // 2
-{% endhighlight %}
+```
## Manipulating Objects In A List ##
You can move an object in the list using any of the `moveUp()`, `moveDown()`, `moveToTop()`, `moveToBottom()`, `moveToRank()`, and `swapWith()` methods. These operations are immediate and don't require that you save the model afterwards:
-{% highlight php %}
+```php
<?php
// The list is 1 - Wash the dishes, 2 - Do the laundry, 3 - Rest a little
$t2->moveToTop();
@@ -80,11 +80,11 @@ $t2->swapWith($t1);
$t2->moveToRank(3);
// The list is now 1 - Wash the dishes, 2 - Rest a little, 3 - Do the laundry
$t2->moveToRank(2);
-{% endhighlight %}
+```
By default, new objects are added at the bottom of the list. But you can also insert them at a specific position, using any of the `insertAtTop()`, `insertAtBottom()`, and `insertAtRank()` methods. Note that the `insertAtXXX` methods don't save the object:
-{% highlight php %}
+```php
<?php
// The list is 1 - Wash the dishes, 2 - Do the laundry, 3 - Rest a little
$t4 = new Task();
@@ -92,15 +92,15 @@ $t4->setTitle('Clean windows');
$t4->insertAtRank(2);
$t4->save();
// The list is now 1 - Wash the dishes, 2 - Clean Windows, 3 - Do the laundry, 4 - Rest a little
-{% endhighlight %}
+```
Whenever you `delete()` an object, the ranks are rearranged to fill the gap:
-{% highlight php %}
+```php
<?php
$t4->delete();
// The list is now 1 - Wash the dishes, 2 - Do the laundry, 3 - Rest a little
-{% endhighlight %}
+```
>**Tip**<br />You can remove an object from the list without necessarily deleting it by calling `removeFromList()`. Don't forget to `save()` it afterwards so that the other objects in the lists are rearranged to fill the gap.
@@ -108,7 +108,7 @@ $t4->delete();
When you need to store several lists for a single model - for instance, one task list for each user - use a _scope_ for each list. This requires that you enable scope support in the behavior definition by setting the `use_scope` parameter to `true`:
-{% highlight xml %}
+```xml
<table name="task">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -121,11 +121,11 @@ When you need to store several lists for a single model - for instance, one task
<parameter name="scope_column" value="user_id" />
</behavior>
</table>
-{% endhighlight %}
+```
Now, after rebuilding your model, you can have as many lists as required:
-{% highlight php %}
+```php
<?php
// test users
$paul = new User();
@@ -146,29 +146,29 @@ $t3->setTitle('Rest a little');
$t3->setUser($john);
$t3->save()
echo $t3->getRank(); // 1, because John has his own task list
-{% endhighlight %}
+```
The generated methods now accept a `$scope` parameter to restrict the query to a given scope:
-{% highlight php %}
+```php
<?php
$firstPaulTask = TaskQuery::create()->findOneByRank($rank = 1, $scope = $paul->getId()); // $t1
$lastPaulTask = $firstTask->getNext(); // $t2
$firstJohnTask = TaskPeer::create()->findOneByRank($rank = 1, $scope = $john->getId()); // $t1
-{% endhighlight %}
+```
Models using the sortable behavior with scope benefit from one additional Query method named `inList()`:
-{% highlight php %}
+```php
<?php
$allPaulsTasks = TaskPeer::create()->inList($scope = $paul->getId())->find();
-{% endhighlight %}
+```
## Parameters ##
By default, the behavior adds one columns to the model - two if you use the scope feature. If these columns are already described in the schema, the behavior detects it and doesn't add them a second time. The behavior parameters allow you to use custom names for the sortable columns. The following schema illustrates a complete customization of the behavior:
-{% highlight xml %}
+```xml
<table name="task">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -183,26 +183,26 @@ By default, the behavior adds one columns to the model - two if you use the scop
<parameter name="scope_column" value="user_id" />
</behavior>
</table>
-{% endhighlight %}
+```
Whatever name you give to your columns, the `sortable` behavior always adds the following proxy methods, which are mapped to the correct column:
-{% highlight php %}
+```php
<?php
$task->getRank(); // returns $task->my_rank_column
$task->setRank($rank);
$task->getScopeValue(); // returns $task->user_id
$task->setScopeValue($scope);
-{% endhighlight %}
+```
The same happens for the generated Query object:
-{% highlight php %}
+```php
<?php
$query = TaskQuery::create()->filterByRank(); // proxies to filterByMyRankColumn()
$query = TaskQuery::create()->orderByRank(); // proxies to orderByMyRankColumn()
$tasks = TaskQuery::create()->findOneByRank(); // proxies to findOneByMyRankColumn()
-{% endhighlight %}
+```
>**Tip**<br />The behavior adds columns but no index. Depending on your table structure, you might want to add a column index by hand to speed up queries on sorted lists.
@@ -210,7 +210,7 @@ $tasks = TaskQuery::create()->findOneByRank(); // proxies to findOneByMyRankColu
Here is a list of the methods added by the behavior to the model objects:
-{% highlight php %}
+```php
<?php
// storage columns accessors
int getRank()
@@ -242,11 +242,11 @@ $object swapWith($object)
// method to remove an object from the list (requires calling save() afterwards)
$object removeFromList()
-{% endhighlight %}
+```
Here is a list of the methods added by the behavior to the query objects:
-{% highlight php %}
+```php
<?php
query filterByRank($order, $scope = null)
query orderByRank($order, $scope = null)
@@ -256,11 +256,11 @@ int getMaxRank($scope = null)
bool reorder($newOrder) // $newOrder is a $id => $rank associative array
// only for behavior with use_scope
array inList($scope)
-{% endhighlight %}
+```
The behavior also adds a few methods to the Peer classes:
-{% highlight php %}
+```php
<?php
int getMaxRank($scope = null)
$object retrieveByRank($rank, $scope = null)
@@ -270,4 +270,4 @@ bool reorder($newOrder) // $newOrder is a $id => $rank associative array
array retrieveList($scope)
int countList($scope)
int deleteList($scope)
-{% endhighlight %}
+```
View
32 behaviors/timestampable.markdown
@@ -10,17 +10,17 @@ The `timestampable` behavior allows you to keep track of the date of creation an
## Basic Usage ##
In the `schema.xml`, use the `<behavior>` tag to add the `timestampable` behavior to a table:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
<behavior name="timestampable" />
</table>
-{% endhighlight %}
+```
Rebuild your model, insert the table creation sql again, and you're ready to go. The model now has two new columns, `created_at` and `updated_at`, that store a timestamp automatically updated on save:
-{% highlight php %}
+```php
<?php
$b = new Book();
$b->setTitle('War And Peace');
@@ -31,21 +31,21 @@ $b->setTitle('Anna Karenina');
$b->save();
echo $b->getCreatedAt(); // 2009-10-02 18:14:23
echo $b->getUpdatedAt(); // 2009-10-02 18:14:25
-{% endhighlight %}
+```
The object query also has specific methods to retrieve recent objects and order them according to their update date:
-{% highlight php %}
+```php
<?php
$books = BookQuery::create()
->recentlyUpdated() // adds a minimum value for the update date
->lastUpdatedFirst() // orders the results by descending update date
->find();
-{% endhighlight %}
+```
You can use any of the following methods in the object query:
-{% highlight php %}
+```php
<?php
// limits the query to recent objects
ModelCriteria recentlyCreated($nbDays = 7)
@@ -55,7 +55,7 @@ ModelCriteria lastCreatedFirst() // order by creation date desc
ModelCriteria firstCreatedFirst() // order by creation date asc
ModelCriteria lastUpdatedFirst() // order by update date desc
ModelCriteria firstUpdatedFirst() // order by update date asc
-{% endhighlight %}
+```
>**Tip**<br />You may need to keep the update date unchanged after an update on the object, for instance when you only update a calculated row. In this case, call the `keepUpdateDateUnchanged()` method on the object before saving it.
@@ -64,7 +64,7 @@ ModelCriteria firstUpdatedFirst() // order by update date asc
You can change the name of the columns added by the behavior by setting the `create_column` and `update_column` parameters:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -75,9 +75,9 @@ You can change the name of the columns added by the behavior by setting the `cre
<parameter name="update_column" value="my_update_date" />
</behavior>
</table>
-{% endhighlight %}
+```
-{% highlight php %}
+```php
<?php
$b = new Book();
$b->setTitle('War And Peace');
@@ -88,10 +88,10 @@ $b->setTitle('Anna Karenina');
$b->save();
echo $b->getMyCreateDate(); // 2009-10-02 18:14:23
echo $b->getMyUpdateDate(); // 2009-10-02 18:14:25
-{% endhighlight %}
+```
If you only want to keep track of the date of creation of your model objects set the `disable_updated_at` parameter to true:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" primaryString="true" />
@@ -99,9 +99,9 @@ If you only want to keep track of the date of creation of your model objects set
<parameter name="disable_updated_at" value="true" />
</behavior>
</table>
-{% endhighlight %}
+```
-{% highlight php %}
+```php
<?php
$b = new Book();
$b->setTitle('War And Peace');
@@ -109,4 +109,4 @@ $b->save();
echo method_exists($b, 'getCreatedAt'); // true
echo method_exists($b, 'getUpdatedAt'); // false
echo $b->getCreatedAt(); // 2009-10-02 18:14:23
-{% endhighlight %}
+```
View
48 behaviors/versionable.markdown
@@ -14,17 +14,17 @@ The `versionable` behavior provides versioning capabilities to any ActiveRecord
## Basic Usage ##
In the `schema.xml`, use the `<behavior>` tag to add the `versionable` behavior to a table:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" />
<behavior name="versionable" />
</table>
-{% endhighlight %}
+```
Rebuild your model, insert the table creation sql again, and you're ready to go. The model now has one new column, `version`, which stores the version number. It also has a new table, `book_version`, which stores all the versions of all `Book` objects, past and present. You won't need to interact with this second table, since the behavior offers an easy-to-use API that takes care of all verisoning actions from the main ActiveRecord object.
-{% highlight php %}
+```php
<?php
$book = new Book();
@@ -51,13 +51,13 @@ print_r($book->compareVersions(1, 2));
// deleting an object also deletes all its versions
$book->delete();
-{% endhighlight %}
+```
## Adding details about each revision ##
For future reference, you probably need to record who edited an object, as well as when and why. To enable audit log capabilities, add the three following parameters to the `<behavior>` tag:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" />
@@ -67,11 +67,11 @@ For future reference, you probably need to record who edited an object, as well
<parameter name="log_comment" value="true" />
</behavior>
</table>
-{% endhighlight %}
+```
Rebuild your model, and you can now define an author name and a comment for each revision using the `setVersionCreatedBy()` and `setVersionComment()` methods, as follows:
-{% highlight php %}
+```php
<?php
$book = new Book();
$book->setTitle('War and Peas');
@@ -83,11 +83,11 @@ $book->setTitle('War and Peace');
$book->setVersionCreatedBy('John Doe');
$book->setVersionComment('Corrected typo on book title');
$book->save();
-{% endhighlight %}
+```
## Retrieving revision history ##
-{% highlight php %}
+```php
<?php
// details about each revision are available for all versions of an object
$book->toVersion(1);
@@ -109,13 +109,13 @@ foreach ($book->getAllVersions() as $bookVersion) {
}
// 'War and Peas', Version 1, updated by John Doe on 2010-12-21 22:53:02 (Book Creation)
// 'War and Peace', Version 2, updated by John Doe on 2010-12-21 22:57:19 (Corrected typo on book title)
-{% endhighlight %}
+```
## Conditional versioning ##
You may not need a new version each time an object is created or modified. If you want to specify your own condition, just override the `isVersioningNecessary()` method in your stub class. The behavior calls it behind the curtain each time you `save()` the main object. No version is created if it returns false.
-{% highlight php %}
+```php
<?php
class Book extends BaseBook
{
@@ -130,11 +130,11 @@ $book->setTitle('Pride and Prejudice');
$book->save(); // book is saved, no new version is created
$book->setISBN('0553213105');
$book->save(): // book is saved, and a new version is created
-{% endhighlight %}
+```
Alternatively, you can choose to disable the automated creation of a new version at each save for all objects of a given model by calling the `disableVersioning()` method on the Peer class. In this case, you still have the ability to manually create a new version of an object, using the `addVersion()` method on a saved object:
-{% highlight php %}
+```php
<?php
BookPeer::disableVersioning();
$book = new Book();
@@ -145,7 +145,7 @@ $book->addVersion(); // a new version is created
// you can reenable versioning using the Peer static method enableVersioning()
BookPeer::enableVersioning();
-{% endhighlight %}
+```
## Versioning Related objects ##
@@ -153,7 +153,7 @@ If a model uses the versionable behavior, and is related to another model also u
The following example assumes that both the `Book` model and the `Author` model are versionable - one `Author` has many `Books`:
-{% highlight php %}
+```php
<?php
$author = new Author();
$author->setFirstName('Leo');
@@ -175,7 +175,7 @@ echo $book->getAuthor()->getLastName(); // 'Totoi'
$book->toVersion(3);
echo $book->getTitle(); // 'War and Peace'
echo $book->getAuthor()->getLastName(); // 'Tolstoi'
-{% endhighlight %}
+```
>**Tip**<br />Versioning of related objects is only possible for simple foreign keys. Relationships based on composite foreign keys cannot preserve relation versionning for now.
@@ -183,7 +183,7 @@ echo $book->getAuthor()->getLastName(); // 'Tolstoi'
You can change the name of the column added by the behavior by setting the `version_column` parameter. Propel only adds the column if it's not already present, so you can easily customize this column by adding it manually to your schema:
-{% highlight xml %}
+```xml
<table name="book">
<column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
<column name="title" type="VARCHAR" required="true" />
@@ -192,9 +192,9 @@ You can change the name of the column added by the behavior by setting the `vers
<parameter name="version_column" value="my_version_column" />
</behavior>
</table>
-{% endhighlight %}
+```
-{% highlight php %}
+```php
<?php
$b = new Book();
$b->setTitle('War And Peace');
@@ -202,11 +202,11 @@ $b->save();
echo $b->getMyVersionColumn(); // 1
// For convenience and ease of use, Propel creates a getVersion() anyway
echo $b->getVersion(); // 1
-{% endhighlight %}
+```
You can also change the name of the version table by setting the `version_table` parameter. Again, Propel automatically creates the table, unless it's already present in the schema:
-{% highlight xml %}