Skip to content
Browse files

Removed the docs/ directory as the documentation has its own repository

  • Loading branch information...
1 parent ca7d188 commit 691b648ed72d155effe7549e980e4ec525b991e8 @willdurand willdurand committed Aug 27, 2011
Showing with 1 addition and 11,330 deletions.
  1. +1 −1 INSTALL
  2. +0 −132 docs/behavior/aggregate_column.txt
  3. +0 −91 docs/behavior/alternative_coding_standards.txt
  4. +0 −261 docs/behavior/archivable.txt
  5. +0 −76 docs/behavior/auto_add_pk.txt
  6. +0 −210 docs/behavior/delegate.txt
  7. +0 −228 docs/behavior/i18n.txt
  8. +0 −373 docs/behavior/nested_set.txt
  9. +0 −105 docs/behavior/query_cache.txt
  10. +0 −137 docs/behavior/sluggable.txt
  11. +0 −134 docs/behavior/soft_delete.txt
  12. +0 −287 docs/behavior/sortable.txt
  13. +0 −94 docs/behavior/timestampable.txt
  14. +0 −272 docs/behavior/versionable.txt
  15. +0 −34 docs/build.xml
  16. +0 −34 docs/cookbook/Add-Custom-SQL.txt
  17. +0 −201 docs/cookbook/Advanced-Column-Types.txt
  18. +0 −47 docs/cookbook/Copying-Objects.txt
  19. +0 −153 docs/cookbook/Customizing-Build.txt
  20. +0 −38 docs/cookbook/DBDesigner.txt
  21. +0 −95 docs/cookbook/Existing-Database.txt
  22. +0 −94 docs/cookbook/Master-Slave.txt
  23. +0 −297 docs/cookbook/Multi-Component.txt
  24. +0 −133 docs/cookbook/Namespaces.txt
  25. +0 −183 docs/cookbook/Nested-Set.txt
  26. +0 −165 docs/cookbook/Runtime-Introspection.txt
  27. +0 −168 docs/cookbook/Using-MSSQL-Server.txt
  28. +0 −101 docs/cookbook/Using-SQL-Schemas.txt
  29. +0 −446 docs/cookbook/Writing-Behavior.txt
  30. +0 −155 docs/guide/01-Installation.txt
  31. +0 −359 docs/guide/02-BuildTime.txt
  32. +0 −332 docs/guide/03-Basic-CRUD.txt
  33. +0 −420 docs/guide/04-Relationships.txt
  34. +0 −252 docs/guide/05-Validators.txt
  35. +0 −291 docs/guide/06-Transactions.txt
  36. +0 −425 docs/guide/07-Behaviors.txt
  37. +0 −447 docs/guide/08-Logging.txt
  38. +0 −511 docs/guide/09-Inheritance.txt
  39. +0 −361 docs/guide/10-Migrations.txt
  40. +0 −753 docs/reference/ActiveRecord.txt
  41. +0 −339 docs/reference/Buildtime-Configuration.txt
  42. +0 −1,302 docs/reference/ModelCriteria.txt
  43. +0 −318 docs/reference/Runtime-Configuration.txt
  44. +0 −475 docs/reference/Schema.txt
View
2 INSTALL
@@ -1,4 +1,4 @@
I N S T A L L I N G P R O P E L
==================================
-See docs/guide/01-Installation.txt for detailed installation instructions.
+See: https://github.com/propelorm/propel-docs/blob/gh-pages/documentation/01-installation.markdown
View
132 docs/behavior/aggregate_column.txt
@@ -1,132 +0,0 @@
-= Aggregate Column Behavior =
-
-[[PageOutline]]
-
-The `aggregate_column` behavior keeps a column updated using an aggregate function executed on a related table.
-
-== Basic Usage ==
-
-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:
-
-{{{
-#!xml
-<table name="post">
- <column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <behavior name="aggregate_column">
- <parameter name="name" value="nb_comments" />
- <parameter name="foreign_table" value="comment" />
- <parameter name="expression" value="COUNT(id)" />
- </behavior>
-</table>
-<table name="comment">
- <column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
- <column name="post_id" type="INTEGER" />
- <foreign-key foreignTable="post" onDelete="cascade">
- <reference local="post_id" foreign="id" />
- </foreign-key>
-</table>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$post = new Post();
-$post->setTitle('How Is Life On Earth?');
-$post->save();
-echo $post->getNbComments(); // 0
-$comment1 = new Comment();
-$comment1->setPost($post);
-$comment1->save();
-echo $post->getNbComments(); // 1
-$comment2 = new Comment();
-$comment2->setPost($post);
-$comment2->save();
-echo $post->getNbComments(); // 2
-$comment2->delete();
-echo $post->getNbComments(); // 1
-}}}
-
-The aggregate column is also kept up to date when related records get modified through a Query object:
-
-{{{
-#!php
-<?php
-CommentQuery::create()
- ->filterByPost($post)
- ->delete():
-echo $post->getNbComments(); // 0
-}}}
-
-== 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:
-
-{{{
-#!xml
-<table name="post">
- <column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <behavior name="aggregate_column">
- <parameter name="name" value="nb_comments" />
- <parameter name="foreign_table" value="comment" />
- <parameter name="expression" value="COUNT(id)" />
- </behavior>
- <behavior name="aggregate_column">
- <parameter name="name" value="last_comment" />
- <parameter name="foreign_table" value="comment" />
- <parameter name="expression" value="MAX(created_at)" />
- </behavior>
- <behavior name="aggregate_column">
- <parameter name="name" value="total_votes" />
- <parameter name="foreign_table" value="comment" />
- <parameter name="expression" value="SUM(vote)" />
- </behavior>
-</table>
-<table name="comment">
- <column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
- <column name="post_id" type="INTEGER" />
- <foreign-key foreignTable="post" onDelete="cascade">
- <reference local="post_id" foreign="id" />
- </foreign-key>
- <column name="created_at" type="TIMESTAMP" />
- <column name="vote" type="INTEGER" />
-</table>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-// in om/BasePost.php
-public function computeNbComments(PropelPDO $con)
-{
- $stmt = $con->prepare('SELECT COUNT(id) FROM `comment` WHERE comment.POST_ID = :p1');
- $stmt->bindValue(':p1', $this->getId());
- $stmt->execute();
- return $stmt->fetchColumn();
-}
-}}}
-
-You can override this method in the model class to customize the aggregate column calculation.
-
-== 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:
-
-{{{
-#!xml
-<table name="post">
- <column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <column name="nb_comments" phpName="CommentCount" type="INTEGER" />
- <behavior name="aggregate_column">
- <parameter name="name" value="nb_comments" />
- <parameter name="foreign_table" value="comment" />
- <parameter name="expression" value="COUNT(id)" />
- </behavior>
-</table>
-}}}
View
91 docs/behavior/alternative_coding_standards.txt
@@ -1,91 +0,0 @@
-= Alternative Coding Standards Behavior =
-
-[[PageOutline]]
-
-The `alternative_coding_standards` behavior changes the coding standards of the model classes generated by Propel to match your own coding style.
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `alternative_coding_standards` behavior to a table:
-{{{
-#!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>
-}}}
-
-Rebuild your model, and you're ready to go. The code of the model classes now uses an alternative set of coding standards:
-
-{{{
-#!php
-<?php
-// in om/BaseBook.php
- /**
- * Set the value of [title] column.
- *
- * @param string $v new value
- * @return Table4 The current object (for fluent API support)
- */
- public function setTitle($v)
- {
- if ($v !== null)
- {
- $v = (string) $v;
- }
-
- if ($this->title !== $v)
- {
- $this->title = $v;
- $this->modifiedColumns[] = BookPeer::TITLE;
- }
-
- return $this;
- }
-
-// instead of
-
- /**
- * Set the value of [title] column.
- *
- * @param string $v new value
- * @return Table4 The current object (for fluent API support)
- */
- public function setTitle($v)
- {
- if ($v !== null) {
- $v = (string) $v;
- }
-
- if ($this->title !== $v) {
- $this->title = $v;
- $this->modifiedColumns[] = BookPeer::TITLE;
- }
-
- return $this;
- } // setTitle()
-}}}
-
-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.
-
-== Parameters ==
-
-Each of the new coding style rules has corresponding parameter in the behavior description. Here is the default configuration:
-
-{{{
-#!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">
- <parameter name="brackets_newline" value="true" />
- <parameter name="remove_closing_comments" value="true" />
- <parameter name="use_whitespace" value="true" />
- <parameter name="tab_size" value="2" />
- <parameter name="strip_comments" value="false" />
- </behavior>
-</table>
-}}}
-
-You can change these settings to better match your own coding styles.
View
261 docs/behavior/archivable.txt
@@ -1,261 +0,0 @@
-= Archivable Behavior =
-
-[[PageOutline]]
-
-The `archivable` behavior gives model objects the ability to be copied to an archive table. By default, the behavior archives objects on deletion, acting as a replacement of the [wiki:Documentation/1.6/Behaviors/soft_delete `soft_delete`] behavior, which is deprecated.
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `archivable` behavior to a table:
-
-{{{
-#!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>
-}}}
-
-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:
-
-{{{
-#!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();
-}}}
-
-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.
-
-{{{
-#!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
-}}}
-
-The ActiveRecord class of an `archivable` model has more methods to deal with the archive:
-
-{{{
-// restore an object to the state it had when last archived
-$book->restoreFromArchive();
-// find the archived version of an existing book
-$archivedBook = $book->getArchive();
-// populate a book based on an archive
-$book = new book();
-$book->populateFromArchive($archivedBook);
-}}}
-
-By default, an `archivable` model is archived just before deletion:
-
-{{{
-#!php
-<?php
-$book = new Book();
-$book->setTitle('Sense and Sensibility');
-$book->save();
-// delete and archive the book
-$book->delete();
-echo BookQuery::create()->count(); // 0
-// find the archived book
-$archivedBook = BookArchiveQuery::create()
- ->findOneByTitle('Sense and Sensibility');
-}}}
-
-'''Tip''': 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:
-
-{{{
-#!php
-<?php
-// create a new object based on the archive
-$book = new Book();
-$book->populateFromArchive($archivedBook);
-$book->save();
-echo $book->getTitle(); // 'Sense and Sensibility'
-}}}
-
-If you want to delete an `archivable` object without archiving it, use the `deleteWithoutArchive()` method generated by the behavior:
-
-{{{
-#!php
-<?php
-// delete the book but don't archive it
-$book->deleteWithoutArchive();
-}}}
-
-== 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:
-
-{{{
-#!php
-<?php
-// archive all books having a title starting with "war"
-$nbArchivedObjects = BookQuery::create()
- ->filterByTitle('War%')
- ->archive();
-}}}
-
-`archive()` returns the number of archived objects, and not the current ActiveQuery object, so it's a termination method.
-
-'''Tip''': Since the `archive()` method doesn't duplicate archived objects, it must iterate over the results of the query to check whether each object has already been archived. In practice, `archive()` issues 2n+1 database queries, where `n` is the number of results of the query as returned by a `count()`.
-
-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:
-
-{{{
-#!php
-<?php
-// delete and archive all books having a title starting with "war"
-$nbDeletedObjects = BookQuery::create()
- ->filterByTitle('War%')
- ->delete();
-
-// use deleteWithoutArchive() if you just want to delete
-$nbDeletedObjects = BookQuery::create()
- ->filterByTitle('War%')
- ->deleteWithoutArchive();
-
-// you can also turn off the query alteration on the current query
-// by calling setArchiveOnDelete(false) before deleting
-$nbDeletedObjects = BookQuery::create()
- ->filterByTitle('War%')
- ->setArchiveOnDelete(false)
- ->delete();
-}}}
-
-== 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:
-
-{{{
-#!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">
- <parameter name="archive_on_insert" value="false" />
- <parameter name="archive_on_update" value="false" />
- <parameter name="archive_on_delete" value="true" />
- </behavior>
-</table>
-}}}
-
-If you turn on `archive_on_insert`, a call to `save()` on a new ActiveRecord object archives it - unless you call `saveWithoutArchive()`.
-
-If you turn on `archive_on_update`, a call to `save()` on an existing ActiveRecord object archives it, and a call to `update()` on an ActiveQuery object archives the results as well. You can still use `saveWithoutArchive()` on the ActiveRecord class and `updateWithoutArchive()` on the ActiveQuery class to skip archiving on updates.
-
-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()`:
-
-{{{
-#!php
-<?php
-// create a new object, save it, and archive it
-$book = new Book();
-$book->save();
-$book->archive();
-}}}
-
-== 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:
-
-{{{
-#!xml
-<database name="main">
- <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">
- <parameter name="archive_class" value="MyBookArchive" />
- </behavior>
- </table>
-</database>
-<database name="backup">
- <table name="my_book_archive" phpName="MyBookArchive">
- <column name="id" required="true" primaryKey="true" type="INTEGER" />
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <column name="archived_at" type="TIMESTAMP" />
- </table>
-</database>
-}}}
-
-The archive table must have the same columns as the archivable table, but without autoIncrements, and without foreign keys.
-
-With this setup, the behavior uses `MyBookArchive` and `MyBookArchiveQuery` for all operations on archives, and therefore uses the `backup` connection.
-
-== Migrating From `soft_delete` ==
-
-If you use `archivable` as a replacement for the `soft_delete` behavior, here is how you should update your code:
-
-{{{
-#!php
-<?php
-// do a soft delete
-$book->delete(); // with soft_delete
-$book->delete(); // with archivable
-
-// do a hard delete
-// with soft_delete
-$book->forceDelete();
-// with archivable
-$book->deleteWithoutArchive();
-
-// find deleted objects
-// with soft_delete
-$books = BookQuery::create()
- ->includeDeleted()
- ->where('Book.DeletedAt IS NOT NULL')
- ->find();
-// with archivable
-$bookArchives = BookArchiveQuery::create()
- ->find();
-
-// recover a deleted object
-// with soft_delete
-$book->unDelete();
-// with archivable
-$book = new Book();
-$book->populateFromArchive($bookArchive);
-$book->save();
-}}}
-
-== 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.
-
-{{{
-#!xml
-<behavior name="archivable">
- <parameter name="archive_table" value="special_book_archive" />
-</behavior>
-}}}
-
-'''Tip''': 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:
-
-{{{
-#!xml
-<behavior name="archivable">
- <parameter name="archived_at_column" value="archive_date" />
-</behavior>
-}}}
-
-Alternatively, you can disable the addition of an archive date column altogether:
-
-{{{
-#!xml
-<behavior name="archivable">
- <parameter name="log_archived_at" value="false" />
-</behavior>
-}}}
View
76 docs/behavior/auto_add_pk.txt
@@ -1,76 +0,0 @@
-= AutoAddPk Behavior =
-
-[[PageOutline]]
-
-The `auto_add_pk` behavior adds a primary key columns to the tables that don't have one. Using this behavior allows you to omit the declaration of primary keys in your tables.
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `auto_add_pk` behavior to a table:
-{{{
-#!xml
-<table name="book">
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <behavior name="auto_add_pk" />
-</table>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$b = new Book();
-$b->setTitle('War And Peace');
-$b->save();
-echo $b->getId(); // 1
-}}}
-
-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.
-
-{{{
-#!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>
-}}}
-
-You can even enable it for all your databases by adding it to the default behaviors in your `build.properties` file:
-
-{{{
-#!ini
-propel.behavior.default = auto_add_pk
-}}}
-
-== 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:
-
-{{{
-#!xml
-<database name="bookstore" defaultIdMethod="native">
- <behavior name="auto_add_pk">
- <parameter name="name" value="identifier" />
- <parameter name="autoIncrement" value="false" />
- <parameter name="type" value="BIGINT" />
- </behavior>
- <table name="book">
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- </table>
-</database>
-}}}
-
-Once you regenerate your model, the column is now named differently:
-
-{{{
-#!php
-<?php
-$b = new Book();
-$b->setTitle('War And Peace');
-$b->setIdentifier(1);
-$b->save();
-echo $b->getIdentifier(); // 1
-}}}
View
210 docs/behavior/delegate.txt
@@ -1,210 +0,0 @@
-= Delegate Behavior =
-
-[[PageOutline]]
-
-The `delegate` behavior allows a model to delegate methods to one of its relationships. This helps to isolate logic in a dedicated model, or to simulate [http://martinfowler.com/eaaCatalog/classTableInheritance.html class table inheritance].
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `delegate` behavior to a table. In the `<parameters>` tag, specify the table that the current table delegates to as the `to` parameter:
-
-{{{
-#!xml
-<table name="account">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="login" type="VARCHAR" required="true" />
- <column name="password" type="VARCHAR" required="true" />
- <behavior name="delegate">
- <parameter name="to" value="profile" />
- </behavior>
-</table>
-<table name="profile">
- <column name="email" type="VARCHAR" />
- <column name="telephone" type="VARCHAR" />
-</table>
-}}}
-
-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:
-
-{{{
-#!xml
-<table name="account">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="login" type="VARCHAR" required="true" />
- <column name="password" type="VARCHAR" required="true" />
-</table>
-<table name="profile">
- <column name="id" required="true" primaryKey="true" type="INTEGER" />
- <column name="email" type="VARCHAR" />
- <column name="telephone" type="VARCHAR" />
- <foreign-key foreignTable="account" onDelete="setnull" onUpdate="cascade">
- <reference local="id" foreign="id" />
- </foreign-key>
-</table>
-}}}
-
-**Tip**: 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 relatiosnhip 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:
-
-{{{
-#!php
-<?php
-$account = new Account();
-$account->setLogin('francois');
-$account->setPassword('S€cr3t');
-
-// Fill the profile via delegation
-$account->setEmail('francois@example.com');
-$account->setTelephone('202-555-9355');
-// same as
-$profile = new Profile();
-$profile->setEmail('francois@example.com');
-$profile->setTelephone('202-555-9355');
-$account->setProfile($profile);
-
-// save the account and its profile
-$account->save();
-
-// retrieve delegated data directly from the main object
-echo $account->getEmail(); // francois@example.com
-}}}
-
-Getter an 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.
-
-{{{
-#!php
-<?php
-class Profile extends BaseProfile
-{
- public function setFakeEmail()
- {
- $n = rand(10e16, 10e20);
- $fakeEmail = base_convert($n, 10, 36) . '@example.com';
- $this->setEmail($fakeEmail);
- }
-}
-
-$account = new Account();
-$account->setFakeEmail(); // delegates to Profile::setFakeEmail()
-}}}
-
-== 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:
-
-{{{
-#!xml
-<table name="player">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="first_name" type="VARCHAR" />
- <column name="last_name" type="VARCHAR" />
-</table>
-<table name="basketballer">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="points" type="INTEGER" />
- <column name="field_goals" type="INTEGER" />
- <column name="three_points_field_goals" type="INTEGER" />
- <column name="player_id" type="INTEGER" />
- <foreign-key foreignTable="player">
- <reference local="player_id" foreign="id" />
- </foreign-key>
- <behavior name="delegate">
- <parameter name="to" value="player" />
- </behavior>
-</table>
-
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$basketballer = new Basketballer();
-$basketballer->setPoints(101);
-$basketballer->setFieldGoals(47);
-$basketballer->setThreePointsFieldGoals(7);
-// set player identity via delegation
-$basketballer->setFirstName('Michael');
-$basketballer->setLastName('Giordano');
-// same as
-$player = new Player();
-$player->setFirstName('Michael');
-$player->setLastName('Giordano');
-$basketballer->setPlayer($player);
-
-// save basketballer and player
-$basketballer->save();
-
-// retrieve delegated data directly from the main object
-echo $basketballer->getFirstName(); // Michael
-}}}
-
-And since several models can delegate to the same player object, that means that a single player can have both basketball and soccer stats!
-
-**Tip**: In this example, table delegation is used to implement [http://martinfowler.com/eaaCatalog/classTableInheritance.html Class Table Inheritance]. See how Propel implements this inheritance type, and others, in the [wiki:Documentation/1.6/Inheritance inheritance chapter].
-
-== Delegating To Several Tables ==
-
-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:
-
-{{{
-#!xml
-<table name="account">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="login" type="VARCHAR" required="true" />
- <column name="password" type="VARCHAR" required="true" />
- <behavior name="delegate">
- <parameter name="to" value="profile, preference" />
- </behavior>
-</table>
-<table name="profile">
- <column name="email" type="VARCHAR" />
- <column name="telephone" type="VARCHAR" />
-</table>
-<table name="preference">
- <column name="preferred_color" type="VARCHAR" />
- <column name="max_size" type="INTEGER" />
-</table>
-}}}
-
-Now the `Account` class has two delegates, that can be addressed seamlessly:
-
-{{{
-#!php
-<?php
-$account = new Account();
-$account->setLogin('francois');
-$account->setPassword('S€cr3t');
-
-// Fill the profile via delegation
-$account->setEmail('francois@example.com');
-$account->setTelephone('202-555-9355');
-// Fill the preference via delegation
-$account->setPreferredColor('orange');
-$account->setMaxSize('200');
-
-// save the account and its profile and its preference
-$account->save();
-}}}
-
-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.
-
-== Parameters ==
-
-The `delegate` behavior takes only one parameter, the list of delegate tables:
-
-{{{
-#!xml
-<table name="account">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="login" type="VARCHAR" required="true" />
- <column name="password" type="VARCHAR" required="true" />
- <behavior name="delegate">
- <parameter name="to" value="profile, preference" />
- </behavior>
-</table>
-}}}
-
-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
228 docs/behavior/i18n.txt
@@ -1,228 +0,0 @@
-= I18n Behavior =
-
-[[PageOutline]]
-
-The `i18n` behavior provides internationalization to any !ActiveRecord object. Using this behavior, you can separate text data from the other data, and keep several translations of the text data for a single object. Applications supporting several languages always use the `i18n` behavior.
-
-== Basic Usage ==
-
-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:
-{{{
-#!xml
-<table name="item">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="name" type="VARCHAR" required="true" />
- <column name="description" type="LONGVARCHAR" />
- <column name="price" type="FLOAT" />
- <column name="is_in_store" type="BOOLEAN" />
- <behavior name="i18n">
- <parameter name="i18n_columns" value="name, description" />
- </behavior>
-</table>
-}}}
-
-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:
-
-{{{
-#!xml
-<table name="item">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="price" type="FLOAT" />
- <column name="is_in_store" type="BOOLEAN" />
-</table>
-<table name="item_i18n">
- <column name="id" type="INTEGER" required="true" primaryKey="true" />
- <column name="locale" type="VARCHAR" size="5" required="true" primaryKey="true" />
- <column name="name" type="VARCHAR" required="true" />
- <column name="description" type="LONGVARCHAR" />
- <foreign-key foreignTable="item" onDelete="setnull" onUpdate="cascade">
- <reference local="id" foreign="id" />
- </foreign-key>
-</table>
-}}}
-
-In addition, the !ActiveRecord Item class now provides integrated translation capabilities.
-
-{{{
-#!php
-<?php
-$item = new Item();
-$item->setPrice('12.99');
-
-// add an English translation
-$item->setLocale('en_EN');
-$item->setName('Microwave oven');
-// same as
-$itemI18n = new ItemI18n();
-$itemI18n->setLocale('en_EN');
-$itemI18n->setName('Microwave oven');
-$item->addItemI18n($itemI18n);
-
-// add a French translation
-$item->setLocale('fr_FR');
-$item->setName('Four micro-ondes');
-
-// save the item and its translations
-$item->save();
-
-// retrieve text and non-text translations directly from the main object
-echo $item->getPrice(); // 12.99
-$item->setLocale('en_EN');
-echo $item->getName(); // Microwave oven
-$item->setLocale('fr_FR');
-echo $item->getName(); // Four micro-ondes
-}}}
-
-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.
-
-'''Tip''': Propel uses the [http://en.wikipedia.org/wiki/Locale locale] concept to identify translations. A locale is a string composed of a language code and a territory code (such as 'en_EN' and 'fr_FR'). This allows different translations for two countries using the same language (such as 'fr_FR' and 'fr_CA');
-
-== Dealing With Locale And Translations ==
-
-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.
-
-{{{
-#!php
-<?php
-$item = new Item();
-$item->setPrice('12.99');
-
-// get the English translation
-$t1 = $item->getTranslation('en_EN');
-// same as
-$t1 = new ItemI18n();
-$t1->setLocale('en_EN');
-$item->addItemI18n($t1);
-
-$t1->setName('Microwave oven');
-
-// get the French translation
-$t2 = $item->getTranslation('fr_FR');
-
-$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
-}}}
-
-'''Tip''': 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:
-
-{{{
-#!php
-<?php
-$item = ItemQuery::create()->findPk(1);
-// remove the French translation
-$item->removeTranslation('fr_FR');
-}}}
-
-== 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:
-
-{{{
-#!php
-<?php
-$items = ItemQuery::create()->find(); // one query to retrieve all items
-$locale = 'en_EN';
-foreach ($items as $item) {
- echo $item->getPrice();
- $item->setLocale($locale);
- echo $item->getName(); // one query to retrieve the English translation
-}
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$items = ItemQuery::create()
- ->joinWithI18n('en_EN')
- ->find(); // one query to retrieve both all items and their translations
-foreach ($items as $item) {
- echo $item->getPrice();
- echo $item->getName(); // no additional query
-}
-}}}
-
-In addition to hydrating translations, `joinWithI18n()` sets the correct locale on results, so you don't need to call `setLocale()` for each result.
-
-'''Tip''': `joinWithI18n()` adds a left join with two conditions. That means that the query returns all items, including those with no translation. If you need to return only objects having translations, add `Criteria::INNER_JOIN` as second parameter to `joinWithI18n()`.
-
-If you need to search items using a condition on a translation, use the generated `useI18nQuery()` as you would with any `useXXXQuery()` method:
-
-{{{
-#!php
-<?php
-$items = ItemQuery::create()
- ->useI18nQuery('en_EN') // tests the condition on the English translation
- ->filterByName('Microwave oven')
- ->endUse()
- ->find();
-}}}
-
-== Symfony Compatibility ==
-
-This behavior is entirely compatible with the i18n behavior for symfony. That means that it can generate `setCulture()` and `getCulture()` methods as aliases to `setLocale()` and `getLocale()`, provided that you add a `locale_alias` parameter. That also means that if you add the behavior to a table without translated columns, and that the translation table is present in the schema, the behavior recognizes them.
-
-So the following schema is exactly equivalent to the first one in this tutorial:
-
-{{{
-#!xml
-<table name="item">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="price" type="FLOAT" />
- <column name="is_in_store" type="BOOLEAN" />
- <behavior name="i18n">
- <parameter name="locale_alias" value="culture" />
- </behavior>
-</table>
-<table name="item_i18n">
- <column name="id" type="INTEGER" required="true" primaryKey="true" />
- <column name="name" type="VARCHAR" required="true" />
- <column name="description" type="LONGVARCHAR" />
-</table>
-}}}
-
-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.
-
-== Parameters ==
-
-If you don't specify a locale when dealing with a translatable object, Propel uses the default English locale 'en_EN'. This default can be overridden in the schema using the `default_locale` parameter:
-
-{{{
-#!xml
-<table name="item">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="name" type="VARCHAR" required="true" />
- <column name="description" type="LONGVARCHAR" />
- <column name="price" type="FLOAT" />
- <column name="is_in_store" type="BOOLEAN" />
- <behavior name="i18n">
- <parameter name="i18n_columns" value="name, description" />
- <parameter name="default_locale" value="fr_FR" />
- </behavior>
-</table>
-}}}
-
-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 and the phpName of the i18n table by setting the `i18n_table` and `i18n_phpname` parameters:
-
-{{{
-#!xml
-<table name="item">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="name" type="VARCHAR" required="true" />
- <column name="description" type="LONGVARCHAR" />
- <column name="price" type="FLOAT" />
- <column name="is_in_store" type="BOOLEAN" />
- <behavior name="i18n">
- <parameter name="i18n_columns" value="name, description" />
- <parameter name="locale_column" value="language" />
- <parameter name="i18n_table" value="item_translation" />
- <parameter name="i18n_phpname" value="ItemTranslation" />
- </behavior>
-</table>
-}}}
View
373 docs/behavior/nested_set.txt
@@ -1,373 +0,0 @@
-= NestedSet Behavior =
-
-[[PageOutline]]
-
-The `nested_set` behavior allows a model to become a tree structure, and provides numerous methods to traverse the tree in an efficient way.
-
-Many applications need to store hierarchical data in the model. For instance, a forum stores a tree of messages for each discussion. A CMS sees sections and subsections as a navigation tree. In a business organization chart, each person is a leaf of the organization tree. [http://en.wikipedia.org/wiki/Nested_set_model Nested sets] are the best way to store such hierachical data in a relational database and manipulate it. The name "nested sets" describes the algorithm used to store the position of a model in the tree ; it is also known as "modified preorder tree traversal".
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `nested_set` behavior to a table:
-{{{
-#!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>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$s1 = new Section();
-$s1->setTitle('Home');
-$s1->makeRoot(); // make this node the root of the tree
-$s1->save();
-$s2 = new Section();
-$s2->setTitle('World');
-$s2->insertAsFirstChildOf($s1); // insert the node in the tree
-$s2->save();
-$s3 = new Section();
-$s3->setTitle('Europe');
-$s3->insertAsFirstChildOf($s2); // insert the node in the tree
-$s3->save()
-$s4 = new Section();
-$s4->setTitle('Business');
-$s4->insertAsNextSiblingOf($s2); // insert the node in the tree
-$s4->save();
-/* The sections are now stored in the database as a tree:
- $s1:Home
- | \
-$s2:World $s4:Business
- |
-$s3:Europe
-*/
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$rootNode = SectionQuery::create()->findRoot(); // $s1
-$worldNode = $rootNode->getFirstChild(); // $s2
-$businessNode = $worldNode->getNextSibling(); // $s4
-$firstLevelSections = $rootNode->getChildren(); // array($s2, $s4)
-$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)
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-echo $s2->isRoot(); // false
-echo $s2->isLeaf(); // false
-echo $s2->getLevel(); // 1
-echo $s2->hasChildren(); // true
-echo $s2->countChildren(); // 1
-echo $s2->hasSiblings(); // true
-}}}
-
-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_left`, 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.
-
-== Manipulating Nodes ==
-
-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:
-
-{{{
-#!php
-<?php
-// move the entire "World" section under "Business"
-$s2->moveToFirstChildOf($s4);
-/* The tree is modified as follows:
-$s1:Home
- |
-$s4:Business
- |
-$s2:World
- |
-$s3:Europe
-*/
-// now move the "Europe" section directly under root, after "Business"
-$s2->moveToFirstChildOf($s4);
-/* The tree is modified as follows:
- $s1:Home
- | \
-$s4:Business $s3:Europe
- |
-$s2:World
-*/
-}}}
-
-You can delete the descendants of a node using `deleteDescendants()`:
-
-{{{
-#!php
-<?php
-// move the entire "World" section under "Business"
-$s4->deleteDescendants($s4);
-/* The tree is modified as follows:
- $s1:Home
- | \
-$s4:Business $s3:Europe
-*/
-}}}
-
-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.
-
-== Filtering Results ==
-
-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:
-
-{{{
-#!php
-<?php
-$children = SectionQuery::create()
- ->childrenOf($rootNode)
- ->orderByTitle()
- ->find();
-}}}
-
-Alternatively, if you already have an existing query method, you can pass it to the model object's methods to filter the results:
-
-{{{
-#!php
-<?php
-$orderQuery = SectionQuery::create()->orderByTitle();
-$children = $rootNode->getChildren($orderQuery);
-}}}
-
-== 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`:
-
-{{{
-#!xml
-<table name="post">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="body" type="VARCHAR" required="true" primaryString="true" />
- <behavior name="nested_set">
- <parameter name="use_scope" value="true" />
- <parameter name="scope_column" value="thread_id" />
- </behavior>
- <foreign-key foreignTable="thread" onDelete="cascade">
- <reference local="thread_id" foreign="id" />
- </foreign-key>
-</table>
-}}}
-
-Now, after rebuilding your model, you can have as many trees as required:
-
-{{{
-#!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();
-}}}
-
-== Using a RecursiveIterator ==
-
-An alternative way to browse a tree structure extensively is to use a [http://php.net/RecursiveIterator RecursiveIterator]. The `nested_set` behavior provides an easy way to retrieve such an iterator from a node, and to parse the entire branch in a single iteration.
-
-For instance, to display an entire tree structure, you can use the following code:
-
-{{{
-#!php
-<?php
-$root = SectionQuery::create()->findRoot();
-foreach ($root->getIterator() as $node) {
- echo str_repeat(' ', $node->getLevel()) . $node->getTitle() . "\n";
-}
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$root = SectionQuery::create()->findRoot();
-foreach ($root->getBranch() as $node) {
- echo str_repeat(' ', $node->getLevel()) . $node->getTitle() . "\n";
-}
-}}}
-
-== 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:
-
-{{{
-#!xml
-<table name="post">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="lft" type="INTEGER" />
- <column name="rgt" type="INTEGER" />
- <column name="lvl" type="INTEGER" />
- <column name="thread_id" type="INTEGER" />
- <column name="body" type="VARCHAR" required="true" primaryString="true" />
- <behavior name="nested_set">
- <parameter name="left_column" value="lft" />
- <parameter name="right_column" value="rgt" />
- <parameter name="level_column" value="lvl" />
- <parameter name="use_scope" value="true" />
- <parameter name="scope_column" value="thread_id" />
- </behavior>
- <foreign-key foreignTable="thread" onDelete="cascade">
- <reference local="thread_id" foreign="id" />
- </foreign-key>
-</table>
-}}}
-
-Whatever name you give to your columns, the `nested_sets` behavior always adds the following proxy methods, which are mapped to the correct column:
-
-{{{
-#!php
-<?php
-$post->getLeftValue(); // returns $post->lft
-$post->setLeftValue($left);
-$post->getRightValue(); // returns $post->rgt
-$post->setRightValue($right);
-$post->getLevel(); // returns $post->lvl
-$post->setLevel($level);
-$post->getScopeValue(); // returns $post->thread_id
-$post->setScopeValue($scope);
-}}}
-
-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.
-
-{{{
-#!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">
- <parameter name="method_proxies" value="true" />
- </behavior>
-</table>
-}}}
-
-== Complete API ==
-
-Here is a list of the methods added by the behavior to the model objects:
-
-{{{
-#!php
-<?php
-// storage columns accessors
-int getLeftValue()
-$node setLeftValue(int $left)
-int getRightValue()
-$node setRightValue(int $right)
-int getLevel()
-$node setLevel(int $level)
-// only for behavior with use_scope
-int getScopeValue()
-$node setScopeValue(int $scope)
-
-// root maker (requires calling save() afterwards)
-$node makeRoot()
-
-// inspection methods
-bool isInTree()
-bool isRoot()
-bool isLeaf()
-bool isDescendantOf()
-bool isAncestorOf()
-bool hasParent()
-bool hasPrevSibling()
-bool hasNextSibling()
-bool hasChildren()
-int countChildren()
-int countDescendants()
-
-// tree traversal methods
-$node getParent()
-$node getPrevSibling()
-$node getNextSibling()
-array getChildren()
-$node getFirstChild()
-$node getLastChild()
-array getSiblings($includeCurrent = false, Criteria $c = null)
-array getDescendants(Criteria $c = null)
-array getBranch(Criteria $c = null)
-array getAncestors(Criteria $c = null)
-
-// node insertion methods (require calling save() afterwards)
-$node addChild($node)
-$node insertAsFirstChildOf($node)
-$node insertAsLastChildOf($node)
-$node insertAsPrevSiblingOf($node)
-$node insertAsNextSiblingOf($node)
-
-// node move methods (immediate, no need to save() afterwards)
-$node moveToFirstChildOf($node)
-$node moveToLastChildOf($node)
-$node moveToPrevSiblingOf($node)
-$node moveToNextSiblingOf($node)
-
-// deletion methods
-$node deleteDescendants()
-
-// only for behavior with method_proxies
-$node createRoot()
-$node retrieveParent()
-$node retrievePrevSibling()
-$node retrieveNextSibling()
-$node retrieveFirstChild()
-$node retrieveLastChild()
-array getPath()
-}}}
-
-The behavior also adds some methods to the Query classes:
-
-{{{
-#!php
-<?php
-// tree filter methods
-query descendantsOf($node)
-query branchOf($node)
-query childrenOf($node)
-query siblingsOf($node)
-query ancestorsOf($node)
-query rootsOf($node)
-// only for behavior with use_scope
-query treeRoots()
-query inTree($scope = null)
-coll findRoots()
-// order methods
-query orderByBranch($reverse = false)
-query orderByLevel($reverse = false)
-// termination methods
-$node findRoot($scope = null)
-coll findTree($scope = null)
-}}}
-
-Lastly, the behavior adds a few methods to the Peer classes:
-
-{{{
-#!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)
-}}}
-
-== TODO ==
-
-* InsertAsParentOf
View
105 docs/behavior/query_cache.txt
@@ -1,105 +0,0 @@
-= Query Cache Behavior =
-
-[[PageOutline]]
-
-The `query_cache` behavior gives a speed boost to Propel queries by caching the transformation of a PHP Query object into reusable SQL code.
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `query_cache` behavior to a table:
-{{{
-#!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>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$title = 'War And Peace';
-$books = BookQuery::create()
- ->setQueryKey('search book by title')
- ->filterByTitle($title)
- ->findOne();
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$title = 'Anna Karenina';
-$books = BookQuery::create()
- ->setQueryKey('search book by title')
- ->filterByTitle($title)
- ->findOne();
-}}}
-
-'''Tip''': The more complex the query, the greater the boost you get from the query cache behavior.
-
-== Parameters ==
-
-You can change the cache backend and the cache lifetime (in seconds) by setting the `backend` and `lifetime` parameters:
-
-{{{
-#!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">
- <parameter name="backend" value="custom" />
- <parameter name="lifetime" value="600" />
- </behavior>
-</table>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-class BookQuery extends BaseBookQuery
-{
- public function cacheContains($key)
- {
- return $this->getCacheBackend()->test($key);
- }
-
- public function cacheFetch($key)
- {
- return $this->getCacheBackend()->load($key);
- }
-
- public function cacheStore($key, $value)
- {
- return $this->getCacheBackend()->save($key, $value);
- }
-
- protected function getCacheBackend()
- {
- if (self::$cacheBackend === null) {
- $frontendOptions = array(
- 'lifetime' => 7200,
- 'automatic_serialization' => true
- );
- $backendOptions = array(
- 'servers' => array(
- array(
- 'host' => 'localhost',
- 'port' => 11211,
- 'persistent' => true
- )
- )
- );
- self::$cacheBackend = Zend_Cache::factory('Core', 'Memcached', $frontendOptions, $backendOptions);
- }
-
- return self::$cacheBackend;
- }
-}
-}}}
View
137 docs/behavior/sluggable.txt
@@ -1,137 +0,0 @@
-= Sluggable Behavior =
-
-[[PageOutline]]
-
-The `sluggable` behavior allows a model to offer a human readable identifier that can be used for search engine friendly URLs.
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `sluggable` behavior to a table:
-{{{
-#!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>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$p1 = new Post();
-$p1->setTitle('Hello, World!');
-$p1->save();
-echo $p1->getSlug(); // 'hello-world'
-}}}
-
-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''': 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:
-
-{{{
-#!php
-<?php
-$p2 = new Post();
-$p2->setTitle('Hello, World!');
-$p2->save();
-echo $p2->getSlug(); // 'hello-world-1'
-}}}
-
-The generated model query offers a `findOneBySlug()` method to easily retrieve a model object based on its slug:
-
-{{{
-#!php
-<?php
-$p = PostQuery::create()->findOneBySlug('hello-world');
-}}}
-
-== Parameters ==
-
-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. The behavior parameters allow you to use custom patterns for the slug composition. The following schema illustrates a complete customization of the behavior:
-
-{{{
-#!xml
-<table name="post">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <column name="url" type="VARCHAR" size="100" />
- <behavior name="sluggable" />
- <parameter name="slug_column" value="url" />
- <parameter name="slug_pattern" value="/posts/{Title}" />
- <parameter name="replace_pattern" value="/[^\w\/]+/u" />
- <parameter name="replacement" value="-" />
- <parameter name="separator" value="/" />
- <parameter name="permanent" value="true" />
- </behavior>
-</table>
-}}}
-
-Whatever `slug_column` name you choose, the `sluggable` behavior always adds the following proxy methods, which are mapped to the correct column:
-
-{{{
-#!php
-<?php
-$post->getSlug(); // returns $post->url
-$post->setSlug($slug); // $post->url = $slug
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-protected function createRawSlug()
-{
- return '/posts/' . $this->getTitle();
-}
-}}}
-
-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.
-
-The `replace_pattern` parameter is a regular expression that shows all the characters that will end up replaced by the `replacement` parameter. In the above example, special characters like '!' or ':' are replaced by '-', but not letters, digits, nor '/'.
-
-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:
-
-{{{
-'posts/hello-world'
-'posts/hello-world/1'
-'posts/hello-world/2'
-...
-}}}
-
-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()`;
-
-== Further Customization ==
-
-The slug is generated by the object when it is saved, via the `createSlug()` method. This method does several operations on a simple string:
-
-{{{
-#!php
-<?php
-protected function createSlug()
-{
- // create the slug based on the `slug_pattern` and the object properties
- $slug = $this->createRawSlug();
- // truncate the slug to accomodate the size of the slug column
- $slug = $this->limitSlugSize($slug);
- // add an incremental index to make sure the slug is unique
- $slug = $this->makeSlugUnique($slug);
-
- return $slug;
-}
-
-protected function createRawSlug()
-{
- // here comes the string composition code, generated according to `slug_pattern`
- $slug = 'posts/' . $this->cleanupSlugPart($this->getTitle());
- // cleanupSlugPart() cleans up the slug part
- // based on the `replace_pattern` and `replacement` parameters
-
- return $slug;
-}
-}}}
-
-You can override any of these methods in your model class, in order to implement a custom slug logic.
View
134 docs/behavior/soft_delete.txt
@@ -1,134 +0,0 @@
-= SoftDelete Behavior =
-
-[[PageOutline]]
-
-The `soft_delete` behavior overrides the deletion methods of a model object to make them 'hide' the deleted rows but keep them in the database. Deleted objects still don't show up on select queries, but they can be retrieved or undeleted when necessary.
-
-'''Warning''': This behavior is deprecated due to limitations that can't be fixed. Use the [wiki:Documentation/1.6/Behaviors/archivable `archivable`] behavior instead.
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `soft_delete` behavior to a table:
-{{{
-#!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>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$b = new Book();
-$b->setTitle('War And Peace');
-$b->save();
-$b->delete();
-echo $b->isDeleted(); // false
-echo $b->getDeletedAt(); // 2009-10-02 18:14:23
-$books = BookQuery::create()->find(); // empty collection
-}}}
-
-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.
-
-'''Warning''': Deleted results may show up in related results (i.e. when you use `joinWith()` on a query and point to a `soft_delete` model). This is something that can't be fixed, and a good reason to use the `archivable` behavior instead.
-
-You can include deleted results in a query by calling the `includeDeleted()` filter:
-
-{{{
-#!php
-<?php
-$book = BookQuery::create()
- ->includeDeleted()
- ->findOne();
-echo $book->getTitle(); // 'War And Peace'
-}}}
-
-You can also turn off the query alteration for the next query by calling the static method `disableSoftDelete()` on the related Query object:
-
-{{{
-#!php
-<?php
-BookQuery::disableSoftDelete();
-$book = BookQuery::create()->findOne();
-echo $book->getTitle(); // 'War And Peace'
-}}}
-
-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.
-
-'''Tip''': `ModelCriteria::paginate()` executes two queries, so `disableSoftDelete()` doesn't work in this case. Prefer `includeDeleted()` in queries using `paginate()`.
-
-If you want to recover a deleted object, use the `unDelete()` method:
-
-{{{
-#!php
-<?php
-$book->unDelete();
-$books = BookQuery::create()->find();
-$book = $books[0];
-echo $book->getTitle(); // 'War And Peace'
-}}}
-
-If you want to force the real deletion of an object, call the `forceDelete()` method:
-
-{{{
-#!php
-<?php
-$book->forceDelete();
-echo $book->isDeleted(); // true
-$books = BookQuery::create()->find(); // empty collection
-}}}
-
-The query methods `delete()` and `deleteAll()` also perform a soft deletion, unless you disable the behavior on the peer class:
-
-{{{
-#!php
-<?php
-$b = new Book();
-$b->setTitle('War And Peace');
-$b->save();
-
-BookQuery::create()->delete($b);
-$books = BookQuery::create()->find(); // empty collection
-// the rows look deleted, but they are still there
-BookQuery::disableSoftDelete();
-$books = BookQuery::create()->find();
-$book = $books[0];
-echo $book->getTitle(); // 'War And Peace'
-
-// To perform a true deletion, disable the softDelete feature
-BookQuery::disableSoftDelete();
-BookQuery::create()->delete();
-// Alternatively, use forceDelete()
-BookQuery::create()->forceDelete();
-}}}
-
-== Parameters ==
-
-You can change the name of the column added by the behavior by setting the `deleted_column` parameter:
-
-{{{
-#!xml
-<table name="book">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <column name="my_deletion_date" type="TIMESTAMP" />
- <behavior name="soft_delete">
- <parameter name="deleted_column" value="my_deletion_date" />
- </behavior>
-</table>
-}}}
-
-{{{
-#!php
-<?php
-$b = new Book();
-$b->setTitle('War And Peace');
-$b->save();
-$b->delete();
-echo $b->getMyDeletionDate(); // 2009-10-02 18:14:23
-$books = BookQuery::create()->find(); // empty collection
-}}}
View
287 docs/behavior/sortable.txt
@@ -1,287 +0,0 @@
-= Sortable Behavior =
-
-[[PageOutline]]
-
-The `sortable` behavior allows a model to become an ordered list, and provides numerous methods to traverse this list in an efficient way.
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `sortable` behavior to a table:
-{{{
-#!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>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$t1 = new Task();
-$t1->setTitle('Wash the dishes');
-$t1->save();
-echo $t1->getRank(); // 1, the first rank to be given (not 0)
-$t2 = new Task();
-$t2->setTitle('Do the laundry');
-$t2->save();
-echo $t2->getRank(); // 2
-$t3 = new Task();
-$t3->setTitle('Rest a little');
-$t3->save()
-echo $t3->getRank(); // 3
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$firstTask = TaskQuery::create()->findOneByRank(1); // $t1
-$secondTask = $firstTask->getNext(); // $t2
-$lastTask = $secondTask->getNext(); // $t3
-$secondTask = $lastTask->getPrevious(); // $t2
-
-$allTasks = TaskQuery::create()->findList();
-// => collection($t1, $t2, $t3)
-$allTasksInReverseOrder = TaskQuery::create()->orderByRank('desc')->find();
-// => collection($t3, $t2, $t2)
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-echo $t2->isFirst(); // false
-echo $t2->isLast(); // false
-echo $t2->getRank(); // 2
-}}}
-
-== 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:
-
-{{{
-#!php
-<?php
-// The list is 1 - Wash the dishes, 2 - Do the laundry, 3 - Rest a little
-$t2->moveToTop();
-// The list is now 1 - Do the laundry, 2 - Wash the dishes, 3 - Rest a little
-$t2->moveToBottom();
-// The list is now 1 - Wash the dishes, 2 - Rest a little, 3 - Do the laundry
-$t2->moveUp();
-// The list is 1 - Wash the dishes, 2 - Do the laundry, 3 - Rest a little
-$t2->swapWith($t1);
-// The list is now 1 - Do the laundry, 2 - Wash the dishes, 3 - Rest a little
-$t2->moveToRank(3);
-// The list is now 1 - Wash the dishes, 2 - Rest a little, 3 - Do the laundry
-$t2->moveToRank(2);
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-// The list is 1 - Wash the dishes, 2 - Do the laundry, 3 - Rest a little
-$t4 = new Task();
-$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
-}}}
-
-Whenever you `delete()` an object, the ranks are rearranged to fill the gap:
-
-{{{
-#!php
-<?php
-$t4->delete();
-// The list is now 1 - Wash the dishes, 2 - Do the laundry, 3 - Rest a little
-}}}
-
-'''Tip''': 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.
-
-== Multiple Lists ==
-
-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`:
-
-{{{
-#!xml
-<table name="task">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <column name="user_id" required="true" type="INTEGER" />
- <foreign-key foreignTable="user" onDelete="cascade">
- <reference local="user_id" foreign="id" />
- </foreign-key>
- <behavior name="sortable">
- <parameter name="use_scope" value="true" />
- <parameter name="scope_column" value="user_id" />
- </behavior>
-</table>
-}}}
-
-Now, after rebuilding your model, you can have as many lists as required:
-
-{{{
-#!php
-<?php
-// test users
-$paul = new User();
-$john = new User();
-// now onto the tasks
-$t1 = new Task();
-$t1->setTitle('Wash the dishes');
-$t1->setUser($paul);
-$t1->save();
-echo $t1->getRank(); // 1
-$t2 = new Task();
-$t2->setTitle('Do the laundry');
-$t2->setUser($paul);
-$t2->save();
-echo $t2->getRank(); // 2
-$t3 = new Task();
-$t3->setTitle('Rest a little');
-$t3->setUser($john);
-$t3->save()
-echo $t3->getRank(); // 1, because John has his own task list
-}}}
-
-The generated methods now accept a `$scope` parameter to restrict the query to a given scope:
-
-{{{
-#!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
-}}}
-
-Models using the sortable behavior with scope benefit from one additional Query methods named `inList()`:
-
-{{{
-#!php
-<?php
-$allPaulsTasks = TaskPeer::create()->inList($scope = $paul->getId())->find();
-}}}
-
-== 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:
-
-{{{
-#!xml
-<table name="task">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <column name="my_rank_column" required="true" type="INTEGER" />
- <column name="user_id" required="true" type="INTEGER" />
- <foreign-key foreignTable="user" onDelete="cascade">
- <reference local="user_id" foreign="id" />
- </foreign-key>
- <behavior name="sortable">
- <parameter name="rank_column" value="my_rank_column" />
- <parameter name="use_scope" value="true" />
- <parameter name="scope_column" value="user_id" />
- </behavior>
-</table>
-}}}
-
-Whatever name you give to your columns, the `sortable` behavior always adds the following proxy methods, which are mapped to the correct column:
-
-{{{
-#!php
-<?php
-$task->getRank(); // returns $task->my_rank_column
-$task->setRank($rank);
-$task->getScopeValue(); // returns $task->user_id
-$task->setScopeValue($scope);
-}}}
-
-The same happens for the generated Query object:
-
-{{{
-#!php
-<?php
-$query = TaskQuery::create()->filterByRank(); // proxies to filterByMyRankColumn()
-$query = TaskQuery::create()->orderByRank(); // proxies to orderByMyRankColumn()
-$tasks = TaskQuery::create()->findOneByRank(); // proxies to findOneByMyRankColumn()
-}}}
-
-'''Tip''': 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.
-
-== Complete API ==
-
-Here is a list of the methods added by the behavior to the model objects:
-
-{{{
-#!php
-<?php
-// storage columns accessors
-int getRank()
-$object setRank(int $rank)
-// only for behavior with use_scope
-int getScopeValue()
-$object setScopeValue(int $scope)
-
-// inspection methods
-bool isFirst()
-bool isLast()
-
-// list traversal methods
-$object getNext()
-$object getPrevious()
-
-// methods to insert an object in the list (require calling save() afterwards)
-$object insertAtRank($rank)
-$object insertAtBottom()
-$object insertAtTop()
-
-// methods to move an object in the list (immediate, no need to save() afterwards)
-$object moveToRank($rank)
-$object moveUp()
-$object moveDown()
-$object moveToTop()
-$object moveToBottom()
-$object swapWith($object)
-
-// method to remove an object from the list (requires calling save() afterwards)
-$object removeFromList()
-}}}
-
-Here is a list of the methods added by the behavior to the query objects:
-
-{{{
-#!php
-<?php
-query filterByRank($order, $scope = null)
-query orderByRank($order, $scope = null)
-$object findOneByRank($rank, $scope = null)
-coll findList($scope = null)
-int getMaxRank($scope = null)
-bool reorder($newOrder) // $newOrder is a $id => $rank associative array
-// only for behavior with use_scope
-array inList($scope)
-}}}
-
-The behavior also adds a few methods to the Peer classes:
-
-{{{
-#!php
-<?php
-int getMaxRank($scope = null)
-$object retrieveByRank($rank, $scope = null)
-array doSelectOrderByRank($order, $scope = null)
-bool reorder($newOrder) // $newOrder is a $id => $rank associative array
-// only for behavior with use_scope
-array retrieveList($scope)
-int countList($scope)
-int deleteList($scope)
-}}}
View
94 docs/behavior/timestampable.txt
@@ -1,94 +0,0 @@
-= Timestampable Behavior =
-
-[[PageOutline]]
-
-The `timestampable` behavior allows you to keep track of the date of creation and last update of your model objects.
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `timestampable` behavior to a table:
-{{{
-#!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>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$b = new Book();
-$b->setTitle('War And Peace');
-$b->save();
-echo $b->getCreatedAt(); // 2009-10-02 18:14:23
-echo $b->getUpdatedAt(); // 2009-10-02 18:14:23
-$b->setTitle('Anna Karenina');
-$b->save();
-echo $b->getCreatedAt(); // 2009-10-02 18:14:23
-echo $b->getUpdatedAt(); // 2009-10-02 18:14:25
-}}}
-
-The object query also has specific methods to retrieve recent objects and order them according to their update date:
-
-{{{
-#!php
-<?php
-$books = BookQuery::create()
- ->recentlyUpdated() // adds a minimum value for the update date
- ->lastUpdatedFirst() // orders the results by descending update date
- ->find();
-}}}
-
-You can use any of the following methods in the object query:
-
-{{{
-#!php
-<?php
-// limits the query to recent objects
-ModelCriteria recentlyCreated($nbDays = 7)
-ModelCriteria recentlyUpdated($nbDays = 7)
-// orders the results
-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
-}}}
-
-'''Tip''': 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.
-
-
-== Parameters ==
-
-You can change the name of the columns added by the behavior by setting the `create_column` and `update_column` parameters:
-
-{{{
-#!xml
-<table name="book">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="title" type="VARCHAR" required="true" primaryString="true" />
- <column name="my_create_date" type="TIMESTAMP" />
- <column name="my_update_date" type="TIMESTAMP" />
- <behavior name="timestampable">
- <parameter name="create_column" value="my_create_date" />
- <parameter name="update_column" value="my_update_date" />
- </behavior>
-</table>
-}}}
-
-{{{
-#!php
-<?php
-$b = new Book();
-$b->setTitle('War And Peace');
-$b->save();
-echo $b->getMyCreateDate(); // 2009-10-02 18:14:23
-echo $b->getMyUpdateDate(); // 2009-10-02 18:14:23
-$b->setTitle('Anna Karenina');
-$b->save();
-echo $b->getMyCreateDate(); // 2009-10-02 18:14:23
-echo $b->getMyUpdateDate(); // 2009-10-02 18:14:25
-}}}
View
272 docs/behavior/versionable.txt
@@ -1,272 +0,0 @@
-= Versionable Behavior =
-
-[[PageOutline]]
-
-The `versionable` behavior provides versioning capabilities to any !ActiveRecord object. Using this behavior, you can:
-
- * Revert an object to previous versions easily
- * Track and browse history of the modifications of an object
- * Keep track of the modifications in related objects
-
-== Basic Usage ==
-
-In the `schema.xml`, use the `<behavior>` tag to add the `versionable` behavior to a table:
-{{{
-#!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>
-}}}
-
-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.
-
-{{{
-#!php
-<?php
-$book = new Book();
-
-// automatic version increment
-$book->setTitle('War and Peas');
-$book->save();
-echo $book->getVersion(); // 1
-$book->setTitle('War and Peace');
-$book->save();
-echo $book->getVersion(); // 2
-
-// reverting to a previous version
-$book->toVersion(1);
-echo $book->getTitle(); // 'War and Peas'
-// saving a previous version creates a new one
-$book->save();
-echo $book->getVersion(); // 3
-
-// checking differences between versions
-print_r($book->compareVersions(1, 2));
-// array(
-// 'Title' => array(1 => 'War and Peas', 2 => 'War and Pace'),
-// );
-
-// deleting an object also deletes all its versions
-$book->delete();
-}}}
-
-== 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:
-
-{{{
-#!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">
- <parameter name="log_created_at" value="true" />
- <parameter name="log_created_by" value="true" />
- <parameter name="log_comment" value="true" />
- </behavior>
-</table>
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-$book = new Book();
-$book->setTitle('War and Peas');
-$book->setVersionCreatedBy('John Doe');
-$book->setVersionComment('Book creation');
-$book->save();
-
-$book->setTitle('War and Peace');
-$book->setVersionCreatedBy('John Doe');
-$book->setVersionComment('Corrected typo on book title');
-$book->save();
-}}}
-
-== Retrieving revision history ==
-
-{{{
-#!php
-<?php
-// details about each revision are available for all versions of an object
-$book->toVersion(1);
-echo $book->getVersionCreatedBy(); // 'John Doe'
-echo $book->getVersionComment(); // 'Book creation'
-// besides, the behavior also logs the creation date for all versions
-echo $book->getVersionCreatedAt(); // '2010-12-21 22:57:19'
-
-// if you need to list the revision details, it is better to use the version object
-// than the main object. The following requires only one database query:
-foreach ($book->getAllVersions() as $bookVersion) {
- echo sprintf("'%s', Version %d, updated by %s on %s (%s)\n",
- $bookVersion->getTitle(),
- $bookVersion->getVersion(),
- $bookVersion->getVersionCreatedBy(),
- $bookVersion->getVersionCreatedAt(),
- $bookVersion->getVersionComment(),
- );
-}
-// '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)
-}}}
-
-== 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.
-
-{{{
-#!php
-<?php
-class Book extends BaseBook
-{
- public function isVersioningNecessary()
- {
- return $this->getISBN() !== null && parent::isVersioningNecessary();
- }
-}
-
-$book = new Book();
-$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
-}}}
-
-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:
-
-{{{
-#!php
-<?php
-BookPeer::disableVersioning();
-$book = new Book();
-$book->setTitle('Pride and Prejudice');
-$book->setVersion(1);
-$book->save(); // book is saved, no new version is created
-$book->addVersion(); // a new version is created
-
-// you can reenable versioning using the Peer static method enableVersioning()
-BookPeer::enableVersioning();
-}}}
-
-== Versioning Related objects ==
-
-If a model uses the versionable behavior, and is related to another model also using the versionable behavior, then each object automatically keeps track of the modifications of related objects. This means that calling `toVersion()` restores the state of the main object ''and of the related objects as well''.
-
-The following example assumes that both the `Book` model and the `Author` model are versionable - one `Author` has many `Books`:
-
-{{{
-#!php
-<?php
-$author = new Author();
-$author->setFirstName('Leo');
-$author->setLastName('Totoi');
-$book = new Book();
-$book->setTitle('War and Peas');
-$book->setAuthor($author);
-$book->save(); // version 1
-
-$book->setTitle('War and Peace');
-$book->save(); // version 2
-
-$author->setLastName('Tolstoi');
-$book->save(); // version 3
-
-$book->toVersion(1);
-echo $book->getTitle(); // 'War and Peas'
-echo $book->getAuthor()->getLastName(); // 'Totoi'
-$book->toVersion(3);
-echo $book->getTitle(); // 'War and Peace'
-echo $book->getAuthor()->getLastName(); // 'Tolstoi'
-}}}
-
-'''Tip''': Versioning of related objects is only possible for simple foreign keys. Relationships based on composite foreign keys cannot preserve relation versionning for now.
-
-== Parameters ==
-
-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:
-
-{{{
-#!xml
-<table name="book">
- <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
- <column name="title" type="VARCHAR" required="true" />
- <column name="my_version_column" type="BIGINT" description="Version column" />
- <behavior name="versionable">
- <parameter name="version_column" value="my_version_column" />
- </behavior>
-</table>
-}}}
-
-{{{
-#!php
-<?php
-$b = new Book();
-$b->setTitle('War And Peace');
-$b->save();
-echo $b->getMyVersionColumn(); // 1
-// For convenience and ease of use, Propel creates a getVersion() anyway
-echo $b->getVersion(); // 1
-}}}
-
-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:
-
-{{{
-#!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">
- <parameter name="version_table" value="my_book_version" />
- </behavior>
-</table>
-}}}
-
-The audit log abilities need to be enabled in the schema as well:
-
-{{{
-#!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">
- <!-- Log the version creation date -->
- <parameter name="log_created_at" value="true" />
- <!-- Log the version creator name, using setVersionCreatedBy() -->
- <parameter name="log_created_by" value="true" />
- <!-- Log the version comment, using setVersionComment() -->
- <parameter name="log_comment" value="true" />
- </behavior>
-</table>
-}}}
-
-== Public API ==
-
-=== !ActiveRecord class ===
-
- * `void save()`: Adds a new version to the object version history and increments the `version` property
- * `void delete()`: Deletes the object version history
- * `boolean isVersioningNecessary(PropelPDO $con = null)`: Checks whether a new version needs to be saved
- * `BaseObject toVersion(integer $version_number)`: Populates the properties of the current object with values from the requested version. Beware that saving the object afterwards will create a new version (and not update the previous version).
- * `integer getLastVersionNumber(PropelPDO $con)`: Queries the database for the highest version number recorded for this object
- * `boolean isLastVersion()`: Returns true if the current object is the last available version
- * `Version addVersion(PropelPDO $con)`: Creates a new Version record and saves it. To be used when isVersioningNecessary() is false. Beware that it doesn't take care of incrementinhg the version number of the main object, and that the main object must be saved prior to calling this method.
- * `array getAllVersions(PropelPDO $con)`: Returns all Version objects related to the main object in a collection
- * `Version getOneVersion(integer $versionNumber PropelPDO $con)`: Returns a given version object
- * `array compareVersions(integer $version1, integer $version2)`: Returns an array of differences showing which parts of a resource changed between two versions
- * `BaseObject populateFromVersion(Version $version, PropelPDO $con)`: Populates an ActiveRecord object based on a Version object
- * `array compareVersions(integer $version1, integer $version2)`: Returns an array of differences showing which parts of a resource changed between two versions
-
- * `BaseObject setVersionCreatedBy(string $createdBy)`: Defines the author name for the revision
- * `string getVersionCreatedBy()`: Gets the author name for the revision
- * `mixed getVersionCreatedAt()`: Gets the creation date for the revision (the behavior takes care of setting it)
- * `BaseObject setVersionComment(string $comment)`: Defines the comment for the revision
- * `string getVersioneComment()`: Gets the comment for the revision
-
-=== Peer class ===
-
-* `void enableVersioning()`: Enables versionning for all instances of the related !ActiveRecord class
-* `void disableVersioning()`: Disables versionning for all instances of the related !ActiveRecord class
-* `boolean isVersioningEnabled()`: Checks whether the versionnig is enabled
View
34 docs/build.xml
@@ -1,34 +0,0 @@
-<project name="propel-docs" default="phpdoc">
-
- <property name="runtime.dir" value="../runtime" />
- <property name="generator.dir" value="../generator" />
-
- <target name="phpdoc">
- <phingcall target="phpdoc-runtime"/>
- <phingcall target="phpdoc-generator"/>
- </target>
-
- <target name="phpdoc-runtime" description="build runtime docs">
- <phpdoc title="Propel Runtime" destdir="api/runtime" sourcecode="yes" output="HTML:Smarty:PHP">
- <fileset dir="${runtime.dir}/lib">
- <include name="**/*.php" />
- </fileset>
- </phpdoc>
- </target>
-
- <target name="phpdoc-generator" description="build generator docs">
- <phpdoc title="Propel Generator" destdir="api/generator" sourcecode="yes" output="HTML:Smarty:PHP">
- <fileset dir="${generator.dir}/lib">
- <include name="**/*.php" />
- </fileset>
- <!--
- <projdocfileset dir="${generator.dir}">
- <include name="README" />
- <include name="INSTALL" />
- <include name="CHANGELOG" />
- </projdocfileset>
- -->
- </phpdoc>
- </target>
-
-</project>
View
34 docs/cookbook/Add-Custom-SQL.txt
@@ -1,34 +0,0 @@
-= Adding Additional SQL Files =
-
-In many cases you may wish to have the ''insert-sql'' task perform additional SQL operations (e.g. add views, stored procedures, triggers, sample data, etc.). Rather than have to run additional SQL statements yourself every time you re-build your object model, you can have the Propel generator do this for you.
-
-== 1. Create the SQL DDL files ==
-
-Create any additional SQL files that you want executed against the database (after the base ''schema.sql'' file is applied).
-
-For example, if we wanted to add a default value to a column that was unsupported in the schema (e.g. where value is a SQL function):
-
-{{{
-#!sql
--- (for postgres)
-ALTER TABLE my_table ALTER COLUMN my_column SET DEFAULT CURRENT_TIMESTAMP;
-}}}
-
-Now we save that as '''my_column-default.sql''' in the same directory as the generated '''schema.sql''' file (usually in projectdir/build/sql/).
-
-== 2. Tell Propel Generator about the new file ==
-
-In that same directory (where your '''schema.sql''' is located), there is a '''sqldb.map''' file which contains a mapping of SQL DDL files to the database that they should be executed against. After running the propel generator, you will probably have a single entry in that file that looks like:
-
-{{{
-schema.sql=your-db-name
-}}}
-
-We want to simply add the new file we created to this file (future builds will preserve anything you add to this file). When we're done, the file will look like this:
-
-{{{
-schema.sql=your-db-name
-my_column-default.sql=your-db-name
-}}}
-
-Now when you execute the ''insert-sql'' Propel generator target, the '''my_column-default.sql''' file will be executed against the ''your-db-name'' database.
View
201 docs/cookbook/Advanced-Column-Types.txt
@@ -1,201 +0,0 @@
-= Working with Advanced Column Types =
-
-[[PageOutline]]
-
-Propel offers a set of advanced column types. The database-agnostic implementation allows these types to work on all supported RDBMS.
-
-== LOB Columns ==
-
-Propel uses PHP streams internally for storing ''Binary'' Locator Objects (BLOBs). This choice was made because PDO itself uses streams as a convention when returning LOB columns in a resultset and when binding values to prepared statements. Unfortunately, not all PDO drivers support this (see, for example, http://bugs.php.net/bug.php?id=40913); in those cases, Propel creates a {{{php://temp}}} stream to hold the LOB contents and thus provide a consistent API.
-
-Note that CLOB (''Character'' Locator Objects) are treated as strings in Propel, as there is no convention for them to be treated as streams by PDO.
-
-=== Getting BLOB Values ===
-
-BLOB values will be returned as PHP stream resources from the accessor methods. Alternatively, if the value is NULL in the database, then the accessors will return the PHP value NULL.
-
-{{{
-#!php
-<?php
-$media = MediaPeer::retrieveByPK(1);
-$fp = $media->getCoverImage();
-if ($fp !== null) {
- echo stream_get_contents($fp);
-}
-}}}
-
-=== Setting BLOB Values ===
-
-When setting a BLOB column, you can either pass in a stream or the blob contents.
-
-{{{
-#!php
-<?php
-// Setting using a stream
-$fp = fopen("/path/to/file.ext", "rb");
-$media = new Media();
-$media->setCoverImage($fp);
-
-// Setting using file contents
-$media = new Media();
-$media->setCoverImage(file_get_contents("/path/to/file.ext"));
-}}}
-
-Regardless of which setting method you choose, the BLOB will always be represented internally as a stream resource -- ''and subsequent calls to the accessor methods will return a stream.''
-
-For example:
-{{{
-#!php
-<?php
-$media = new Media();
-$media->setCoverImage(file_get_contents("/path/to/file.ext"));
-
-$fp = $media->getCoverImage();
-print gettype($fp); // "resource"
-}}}
-
-=== Setting BLOB columns and isModified() ===
-
-Note that because a stream contents may be externally modified, ''mutator methods for BLOB columns will always set the '''isModified()''' to report true'' -- even if the stream has the same identity as the stream that was returned.
-
-For example:
-{{{
-#!php
-<?php
-
-$media = MediaPeer::retrieveByPK(1);
-$fp = $media->getCoverImage();
-$media->setCoverImage($fp);
-
-var_export($media->isModified()); // TRUE
-}}}
-
-== ENUM Columns ==
-
-Although stored in the database as integers, ENUM columns let users manipulate a set of predefined values, without worrying about their storage.
-
-{{{
-#!xml
-<table name="book">
- ...
- <column name="style" type="ENUM" valueSet="novel, essay, poetry" />
-</table>
-}}}
-
-{{{
-#!php
-<?php
-// The ActiveRecord setter and getter let users use any value from the valueSet
-$book = new Book();
-$book->setStyle('novel');
-echo $book->getStyle(); // novel
-// Trying to set a value not in the valueSet throws an exception
-
-// ENUM columns are also searchable, using the generated filterByXXX() method
-// or other ModelCritera methods (like where(), condition())
-$books = BookQuery::create()