Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

- Changed project layout

- Included propel as submodule
- Created test environment, first tests
- Bugfixes for the written tests
  • Loading branch information...
commit cbb20431176dddd5ff99469c1801f3fcd796d67b 1 parent 838b2dc
Thomas Gossmann authored

Showing 277 changed files with 46 additions and 39,589 deletions. Show diff stats Hide diff stats

  1. +7 4 .buildpath
  2. +2 2 .settings/org.eclipse.php.core.prefs
  3. +2 7 {src → }/generator/ListenerBehavior.php
  4. +2 0  {src → }/generator/ListenerCollectionBehavior.php
  5. 0  {src → }/generator/ListenerTable.php
  6. +7 12 {src → }/generator/templates/ListenerCollection.php
  7. +25 25 {src → }/generator/templates/ObjectListener.php
  8. +1 0  lib/.gitignore
  9. +0 38 lib/propel-1.6.1/CHANGELOG
  10. +0 4 lib/propel-1.6.1/INSTALL
  11. +0 19 lib/propel-1.6.1/LICENSE
  12. +0 755 lib/propel-1.6.1/WHATS_NEW
  13. +0 70 lib/propel-1.6.1/generator/bin/propel-gen
  14. +0 32 lib/propel-1.6.1/generator/bin/propel-gen.bat
  15. +0 623 lib/propel-1.6.1/generator/build-propel.xml
  16. +0 190 lib/propel-1.6.1/generator/build.properties-sample
  17. +0 238 lib/propel-1.6.1/generator/build.xml
  18. +0 120 lib/propel-1.6.1/generator/build.xml-local
  19. +0 290 lib/propel-1.6.1/generator/default.properties
  20. +0 133 lib/propel-1.6.1/generator/lib/behavior/AlternativeCodingStandardsBehavior.php
  21. +0 53 lib/propel-1.6.1/generator/lib/behavior/AutoAddPkBehavior.php
  22. +0 487 lib/propel-1.6.1/generator/lib/behavior/SoftDeleteBehavior.php
  23. +0 176 lib/propel-1.6.1/generator/lib/behavior/TimestampableBehavior.php
  24. +0 133 lib/propel-1.6.1/generator/lib/behavior/aggregate_column/AggregateColumnBehavior.php
  25. +0 164 lib/propel-1.6.1/generator/lib/behavior/aggregate_column/AggregateColumnRelationBehavior.php
  26. +0 17 lib/propel-1.6.1/generator/lib/behavior/aggregate_column/templates/objectCompute.php
  27. +0 11 lib/propel-1.6.1/generator/lib/behavior/aggregate_column/templates/objectUpdate.php
  28. +0 16 lib/propel-1.6.1/generator/lib/behavior/aggregate_column/templates/objectUpdateRelated.php
  29. +0 20 lib/propel-1.6.1/generator/lib/behavior/aggregate_column/templates/queryFindRelated.php
  30. +0 8 lib/propel-1.6.1/generator/lib/behavior/aggregate_column/templates/queryUpdateRelated.php
  31. +0 244 lib/propel-1.6.1/generator/lib/behavior/concrete_inheritance/ConcreteInheritanceBehavior.php
  32. +0 89 lib/propel-1.6.1/generator/lib/behavior/concrete_inheritance/ConcreteInheritanceParentBehavior.php
  33. +0 269 lib/propel-1.6.1/generator/lib/behavior/i18n/I18nBehavior.php
  34. +0 208 lib/propel-1.6.1/generator/lib/behavior/i18n/I18nBehaviorObjectBuilderModifier.php
  35. +0 37 lib/propel-1.6.1/generator/lib/behavior/i18n/I18nBehaviorPeerBuilderModifier.php
  36. +0 74 lib/propel-1.6.1/generator/lib/behavior/i18n/I18nBehaviorQueryBuilderModifier.php
  37. +0 12 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectAttributes.php
  38. +0 2  lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectClearReferences.php
  39. +0 12 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectGetCurrentTranslation.php
  40. +0 10 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectGetLocale.php
  41. +0 11 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectGetLocaleAlias.php
  42. +0 34 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectGetTranslation.php
  43. +0 5 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectPostDelete.php
  44. +0 28 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectRemoveTranslation.php
  45. +0 14 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectSetLocale.php
  46. +0 13 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectSetLocaleAlias.php
  47. +0 17 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectSetTranslation.php
  48. +0 5 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectTranslatedColumnGetter.php
  49. +0 7 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/objectTranslatedColumnSetter.php
  50. +0 17 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/queryJoinI18n.php
  51. +0 18 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/queryJoinWithI18n.php
  52. +0 18 lib/propel-1.6.1/generator/lib/behavior/i18n/templates/queryUseI18nQuery.php
  53. +0 99 lib/propel-1.6.1/generator/lib/behavior/nestedset/NestedSetBehavior.php
  54. +0 1,591 lib/propel-1.6.1/generator/lib/behavior/nestedset/NestedSetBehaviorObjectBuilderModifier.php
  55. +0 560 lib/propel-1.6.1/generator/lib/behavior/nestedset/NestedSetBehaviorPeerBuilderModifier.php
  56. +0 379 lib/propel-1.6.1/generator/lib/behavior/nestedset/NestedSetBehaviorQueryBuilderModifier.php
  57. +0 264 lib/propel-1.6.1/generator/lib/behavior/query_cache/QueryCacheBehavior.php
  58. +0 332 lib/propel-1.6.1/generator/lib/behavior/sluggable/SluggableBehavior.php
  59. +0 83 lib/propel-1.6.1/generator/lib/behavior/sortable/SortableBehavior.php
  60. +0 636 lib/propel-1.6.1/generator/lib/behavior/sortable/SortableBehaviorObjectBuilderModifier.php
  61. +0 367 lib/propel-1.6.1/generator/lib/behavior/sortable/SortableBehaviorPeerBuilderModifier.php
  62. +0 285 lib/propel-1.6.1/generator/lib/behavior/sortable/SortableBehaviorQueryBuilderModifier.php
  63. +0 250 lib/propel-1.6.1/generator/lib/behavior/versionable/VersionableBehavior.php
  64. +0 514 lib/propel-1.6.1/generator/lib/behavior/versionable/VersionableBehaviorObjectBuilderModifier.php
  65. +0 79 lib/propel-1.6.1/generator/lib/behavior/versionable/VersionableBehaviorPeerBuilderModifier.php
  66. +0 120 lib/propel-1.6.1/generator/lib/behavior/versionable/VersionableBehaviorQueryBuilderModifier.php
  67. +0 622 lib/propel-1.6.1/generator/lib/builder/DataModelBuilder.php
  68. +0 120 lib/propel-1.6.1/generator/lib/builder/om/ClassTools.php
  69. +0 139 lib/propel-1.6.1/generator/lib/builder/om/ExtensionQueryBuilder.php
  70. +0 147 lib/propel-1.6.1/generator/lib/builder/om/ExtensionQueryInheritanceBuilder.php
  71. +0 533 lib/propel-1.6.1/generator/lib/builder/om/OMBuilder.php
  72. +0 206 lib/propel-1.6.1/generator/lib/builder/om/ObjectBuilder.php
  73. +0 108 lib/propel-1.6.1/generator/lib/builder/om/PHP5ExtensionNodeBuilder.php
  74. +0 109 lib/propel-1.6.1/generator/lib/builder/om/PHP5ExtensionNodePeerBuilder.php
  75. +0 130 lib/propel-1.6.1/generator/lib/builder/om/PHP5ExtensionObjectBuilder.php
  76. +0 133 lib/propel-1.6.1/generator/lib/builder/om/PHP5ExtensionPeerBuilder.php
  77. +0 105 lib/propel-1.6.1/generator/lib/builder/om/PHP5InterfaceBuilder.php
  78. +0 198 lib/propel-1.6.1/generator/lib/builder/om/PHP5MultiExtendObjectBuilder.php
  79. +0 1,136 lib/propel-1.6.1/generator/lib/builder/om/PHP5NestedSetBuilder.php
  80. +0 1,724 lib/propel-1.6.1/generator/lib/builder/om/PHP5NestedSetPeerBuilder.php
  81. +0 1,101 lib/propel-1.6.1/generator/lib/builder/om/PHP5NodeBuilder.php
  82. +0 751 lib/propel-1.6.1/generator/lib/builder/om/PHP5NodePeerBuilder.php
  83. +0 4,758 lib/propel-1.6.1/generator/lib/builder/om/PHP5ObjectBuilder.php
  84. +0 969 lib/propel-1.6.1/generator/lib/builder/om/PHP5ObjectNoCollectionBuilder.php
  85. +0 2,872 lib/propel-1.6.1/generator/lib/builder/om/PHP5PeerBuilder.php
  86. +0 355 lib/propel-1.6.1/generator/lib/builder/om/PHP5TableMapBuilder.php
  87. +0 310 lib/propel-1.6.1/generator/lib/builder/om/PeerBuilder.php
  88. +0 1,291 lib/propel-1.6.1/generator/lib/builder/om/QueryBuilder.php
  89. +0 296 lib/propel-1.6.1/generator/lib/builder/om/QueryInheritanceBuilder.php
  90. +0 253 lib/propel-1.6.1/generator/lib/builder/sql/DataSQLBuilder.php
  91. +0 37 lib/propel-1.6.1/generator/lib/builder/sql/mssql/MssqlDataSQLBuilder.php
  92. +0 22 lib/propel-1.6.1/generator/lib/builder/sql/mysql/MysqlDataSQLBuilder.php
  93. +0 22 lib/propel-1.6.1/generator/lib/builder/sql/oracle/OracleDataSQLBuilder.php
  94. +0 102 lib/propel-1.6.1/generator/lib/builder/sql/pgsql/PgsqlDataSQLBuilder.php
  95. +0 36 lib/propel-1.6.1/generator/lib/builder/sql/sqlite/SqliteDataSQLBuilder.php
  96. +0 22 lib/propel-1.6.1/generator/lib/builder/sql/sqlsrv/SqlsrvDataSQLBuilder.php
  97. +0 33 lib/propel-1.6.1/generator/lib/builder/util/DefaultEnglishPluralizer.php
  98. +0 28 lib/propel-1.6.1/generator/lib/builder/util/Pluralizer.php
  99. +0 91 lib/propel-1.6.1/generator/lib/builder/util/PropelStringReader.php
  100. +0 92 lib/propel-1.6.1/generator/lib/builder/util/PropelTemplate.php
  101. +0 130 lib/propel-1.6.1/generator/lib/builder/util/StandardEnglishPluralizer.php
  102. +0 404 lib/propel-1.6.1/generator/lib/builder/util/XmlToAppData.php
  103. +0 265 lib/propel-1.6.1/generator/lib/builder/util/XmlToDataSQL.php
  104. +0 308 lib/propel-1.6.1/generator/lib/config/GeneratorConfig.php
  105. +0 49 lib/propel-1.6.1/generator/lib/config/GeneratorConfigInterface.php
  106. +0 148 lib/propel-1.6.1/generator/lib/config/QuickGeneratorConfig.php
  107. +0 22 lib/propel-1.6.1/generator/lib/exception/EngineException.php
  108. +0 17 lib/propel-1.6.1/generator/lib/exception/SchemaException.php
  109. +0 326 lib/propel-1.6.1/generator/lib/model/AppData.php
  110. +0 270 lib/propel-1.6.1/generator/lib/model/Behavior.php
  111. +0 1,279 lib/propel-1.6.1/generator/lib/model/Column.php
  112. +0 114 lib/propel-1.6.1/generator/lib/model/ColumnDefaultValue.php
  113. +0 72 lib/propel-1.6.1/generator/lib/model/ConstraintNameGenerator.php
  114. +0 650 lib/propel-1.6.1/generator/lib/model/Database.php
  115. +0 386 lib/propel-1.6.1/generator/lib/model/Domain.php
  116. +0 683 lib/propel-1.6.1/generator/lib/model/ForeignKey.php
  117. +0 35 lib/propel-1.6.1/generator/lib/model/IDMethod.php
  118. +0 108 lib/propel-1.6.1/generator/lib/model/IdMethodParameter.php
  119. +0 324 lib/propel-1.6.1/generator/lib/model/Index.php
  120. +0 147 lib/propel-1.6.1/generator/lib/model/Inheritance.php
  121. +0 77 lib/propel-1.6.1/generator/lib/model/NameFactory.php
  122. +0 73 lib/propel-1.6.1/generator/lib/model/NameGenerator.php
  123. +0 167 lib/propel-1.6.1/generator/lib/model/PhpNameGenerator.php
  124. +0 357 lib/propel-1.6.1/generator/lib/model/PropelTypes.php
  125. +0 194 lib/propel-1.6.1/generator/lib/model/Rule.php
  126. +0 141 lib/propel-1.6.1/generator/lib/model/ScopedElement.php
  127. +0 1,901 lib/propel-1.6.1/generator/lib/model/Table.php
  128. +0 58 lib/propel-1.6.1/generator/lib/model/Unique.php
  129. +0 184 lib/propel-1.6.1/generator/lib/model/Validator.php
  130. +0 182 lib/propel-1.6.1/generator/lib/model/VendorInfo.php
  131. +0 182 lib/propel-1.6.1/generator/lib/model/XMLElement.php
  132. +0 93 lib/propel-1.6.1/generator/lib/model/diff/PropelColumnComparator.php
  133. +0 121 lib/propel-1.6.1/generator/lib/model/diff/PropelColumnDiff.php
  134. +0 159 lib/propel-1.6.1/generator/lib/model/diff/PropelDatabaseComparator.php
  135. +0 318 lib/propel-1.6.1/generator/lib/model/diff/PropelDatabaseDiff.php
  136. +0 73 lib/propel-1.6.1/generator/lib/model/diff/PropelForeignKeyComparator.php
  137. +0 60 lib/propel-1.6.1/generator/lib/model/diff/PropelIndexComparator.php
  138. +0 311 lib/propel-1.6.1/generator/lib/model/diff/PropelTableComparator.php
Sorry, we could not display the entire diff because it was too big.
11 .buildpath
... ... @@ -1,8 +1,11 @@
1 1 <?xml version="1.0" encoding="UTF-8"?>
2 2 <buildpath>
3   - <buildpathentry kind="src" path="src"/>
  3 + <buildpathentry kind="src" path="test/fixtures/listener-behavior/build/classes"/>
  4 + <buildpathentry kind="src" path="runtime"/>
  5 + <buildpathentry kind="src" path="lib/propel-1.6.2/runtime/lib"/>
  6 + <buildpathentry external="true" kind="lib" path="/usr/local/Cellar/php/5.3.6/lib/php/PHPUnit"/>
4 7 <buildpathentry kind="con" path="org.eclipse.php.core.LANGUAGE"/>
5   - <buildpathentry kind="src" path="lib/propel-1.6.1/generator/lib"/>
6   - <buildpathentry kind="src" path="lib/propel-1.6.1/runtime/lib"/>
7   - <buildpathentry kind="src" path="build/propel"/>
  8 + <buildpathentry kind="src" path="generator"/>
  9 + <buildpathentry kind="src" path="lib/propel-1.6.2/generator/lib"/>
  10 + <buildpathentry kind="src" path="test/listener-behavior"/>
8 11 </buildpath>
4 .settings/org.eclipse.php.core.prefs
... ... @@ -1,5 +1,5 @@
1   -#Fri Jul 15 22:15:26 CEST 2011
  1 +#Mon Oct 03 17:45:45 CEST 2011
2 2 eclipse.preferences.version=1
3   -include_path=0;/propel-listener-behavior/src\u00050;/propel-listener-behavior/build/propel\u00050;/propel-listener-behavior/lib/propel-1.6.1/generator/lib\u00050;/propel-listener-behavior/lib/propel-1.6.1/runtime/lib
  3 +include_path=0;/propel-listener-behavior/generator\u00050;/propel-listener-behavior/test/fixtures/listener-behavior/build/classes\u00050;/propel-listener-behavior/lib/propel-1.6.2/generator/lib\u00050;/propel-listener-behavior/runtime\u00050;/propel-listener-behavior/lib/propel-1.6.2/runtime/lib\u00050;/propel-listener-behavior/test/listener-behavior\u00051;/usr/local/Cellar/php/5.3.6/lib/php/PHPUnit
4 4 phpVersion=php5.3
5 5 use_asp_tags_as_php=false
9 src/generator/ListenerBehavior.php → generator/ListenerBehavior.php
@@ -55,10 +55,6 @@ private function createListenerTable()
55 55 $callback->setSize(100);
56 56
57 57 $params = new Column('json_params');
58   -
59   - // arrays don't work properly, see ticket: http://www.propelorm.org/ticket/1482
60   - // use text and json_encode and json_decode as workaround
61   -// $params->getDomain()->copy($db->getPlatform()->getDomainForType(PropelTypes::PHP_ARRAY));
62 58 $params->getDomain()->copy($db->getPlatform()->getDomainForType(PropelTypes::LONGVARCHAR));
63 59
64 60 $event = new Column('event');
@@ -128,8 +124,7 @@ public function preInsert()
128 124
129 125 public function postInsert()
130 126 {
131   - return '$this->notifyListener(\'postInsert\');
132   -$this->saveEnqueuedListeners();';
  127 + return '$this->notifyListener(\'postInsert\');';
133 128 }
134 129
135 130 public function preSave()
@@ -139,7 +134,7 @@ public function preSave()
139 134
140 135 public function postSave()
141 136 {
142   - return '$this->notifyListener(\'postSave\');';
  137 + return '$this->notifyListener(\'postSave\');'."\n".'$this->saveEnqueuedListeners();';
143 138 }
144 139
145 140 public function preUpdate()
2  src/generator/ListenerCollectionBehavior.php → generator/ListenerCollectionBehavior.php
... ... @@ -1,5 +1,7 @@
1 1 <?php
2 2
  3 +require_once 'ListenerTable.php';
  4 +
3 5 class ListenerCollectionBehavior extends Behavior
4 6 {
5 7 public function objectMethods()
0  src/generator/ListenerTable.php → generator/ListenerTable.php
File renamed without changes
0  generator/ListenerTable.php
Sorry, we could not display the changes to this file because there were too many other changes to display.
19 src/generator/templates/ListenerCollection.php → generator/templates/ListenerCollection.php
@@ -25,7 +25,7 @@ private static function implode_recursive($glue, $pieces)
25 25 * @param mixed $listener information about the listener
26 26 * @param String $event the event at which the listener fires
27 27 */
28   -public static function getListenerInfo($listener, $target, $refId = null)
  28 +public static function getListenerConfig($listener, $target, $refId = null)
29 29 {
30 30 $default = array(
31 31 'on' => null,
@@ -36,8 +36,8 @@ public static function getListenerInfo($listener, $target, $refId = null)
36 36 'ref_id' => $refId,
37 37 );
38 38
39   - if ($listener instanceof ListenerInfo) {
40   - $listener = $listener->getListenerInfo();
  39 + if ($listener instanceof ListenerConfigInterface) {
  40 + $listener = $listener->getListenerConfig();
41 41 } else if (is_string($listener) && function_exists($listener)) {
42 42 $listener = array('callback' => $listener);
43 43 } else if (is_string($listener) && class_exists($listener)) {
@@ -94,7 +94,7 @@ public static function addListenerToRuntime(<?php echo $listenerName; ?> $l) {
94 94 }
95 95
96 96 if (!in_array($l, self::$globalListeners[$l->getTarget()][$l->getEvent()])) {
97   - self::$globalListeners[$l->getTarget()][$l->getEvent()][] = $l;
  97 + self::$globalListeners[$l->getTarget()][$l->getEvent()][$l->getId()] = $l;
98 98 }
99 99 }
100 100
@@ -105,13 +105,8 @@ public static function addListenerToRuntime(<?php echo $listenerName; ?> $l) {
105 105 * @param <?php echo $listenerName; ?> $l
106 106 */
107 107 public static function removeListenerFromRuntime(<?php echo $listenerName; ?> $l) {
108   - try {
109   - self::getGlobalListeners();
110   - $key = array_search($l, self::$globalListeners[$l->getTarget()][$l->getEvent()]);
111   - if ($key) {
112   - unset(self::$globalListeners[$l->getTarget()][$l->getEvent()][$key]);
113   - }
114   - } catch (Exception $e) {}
  108 + self::getGlobalListeners();
  109 + unset(self::$globalListeners[$l->getTarget()][$l->getEvent()][$l->getId()]);
115 110 }
116 111
117 112 /**
@@ -150,7 +145,7 @@ public function setParams($v)
150 145 * Adds a listener to the static collection, to keep the collection in sync during runtime.
151 146 */
152 147 public function postInsert(PropelPDO $con = null) {
153   - if ($this->target == '') {
  148 + if ($this->target == '') {
154 149 self::addListenerToRuntime($this);
155 150 }
156 151 }
50 src/generator/templates/ObjectListener.php → generator/templates/ObjectListener.php
... ... @@ -1,11 +1,11 @@
1 1 /**
2   -* Stores dynamic listeners
  2 +* Stores local listeners
3 3 * @type array
4 4 */
5 5 private $listeners = null;
6 6
7 7 /**
8   -* Stores dynamic listeners queue
  8 +* Stores local listeners queue
9 9 * @type array
10 10 */
11 11 private $listenerQueue = null;
@@ -13,25 +13,20 @@
13 13 /**
14 14 * Saves a listener in the database
15 15 *
16   -* @param mixed $listener information about the listener
  16 +* @param mixed $listener listener-config
  17 +* @param int $refId reference id for binding a local listener to a tupel
17 18 */
18 19 private static function saveListener($listener, $refId = null)
19 20 {
20   - $listener = <?php echo $listenerName; ?>::getListenerInfo($listener, get_called_class(), $refId);
21   -
22   - // prepare for saving
23   - $todb = array();
24   - foreach (array_keys($listener) as $key) {
25   - $todb[ucfirst($key)] = $listener[$key];
26   - }
27   -
  21 + $listener = <?php echo $listenerName; ?>::getListenerConfig($listener, get_called_class(), $refId);
  22 +
28 23 // save listener
29 24 $l = <?php echo $listenerName; ?>Query::create()->findOneById($listener['id']);
30 25 if (is_null($l)) {
31 26 $l = new <?php echo $listenerName; ?>();
32   - $l->fromArray($todb);
33   - if (array_key_exists('Params', $todb)) {
34   - $l->setParams($todb['Params']);
  27 + $l->fromArray($listener, BasePeer::TYPE_FIELDNAME);
  28 + if (array_key_exists('params', $listener)) {
  29 + $l->setParams($listener['params']);
35 30 }
36 31 $l->save();
37 32 }
@@ -42,7 +37,7 @@ private static function saveListener($listener, $refId = null)
42 37 /**
43 38 * Adds a global listener to the collection
44 39 *
45   -* @param mixed $listener information about the listener
  40 +* @param mixed $listener listener-config
46 41 */
47 42 public static function addGlobalListener($listener)
48 43 {
@@ -52,7 +47,7 @@ public static function addGlobalListener($listener)
52 47 /**
53 48 * Adds a local listener to the collection
54 49 *
55   -* @param mixed $listener information about the listener
  50 +* @param mixed $listener listener-config
56 51 */
57 52 public function addListener($listener)
58 53 {
@@ -61,7 +56,12 @@ public function addListener($listener)
61 56 }
62 57
63 58 if (is_array($this->getPrimaryKey())) {
64   - throw new PropelException('Cannot add dynamic listener on an object with a composite primary key');
  59 + throw new PropelException('Cannot add local listener on an object with a composite primary key');
  60 + }
  61 +
  62 + // pre fill $this->listeners. So new listeners won't be saved here once the object isn't saved itself
  63 + if (is_null($this->listeners)) {
  64 + $this->getListeners();
65 65 }
66 66
67 67 // enqueue listener, if this is new
@@ -74,7 +74,6 @@ public function addListener($listener)
74 74
75 75 // anyway save it
76 76 else {
77   - $listeners = $this->getListeners();
78 77 $this->listeners[] = self::saveListener($listener, $this->getPrimaryKey());
79 78 }
80 79 }
@@ -82,11 +81,11 @@ public function addListener($listener)
82 81 /**
83 82 * Removes a global listener from the collection
84 83 *
85   -* @param mixed $listener information about the listener
  84 +* @param mixed $listener listener-config
86 85 */
87 86 public static function removeGlobalListener($listener)
88 87 {
89   - $listener = $this->getListenerInfo($listener, get_called_class());
  88 + $listener = <?php echo $listenerName; ?>::getListenerConfig($listener, get_called_class());
90 89
91 90 $l = <?php echo $listenerName; ?>Query::create()->findOneById($listener['id']);
92 91
@@ -99,10 +98,10 @@ public static function removeGlobalListener($listener)
99 98 /**
100 99 * Removes a local listener from the collection
101 100 *
102   -* @param mixed $listener information about the listener
  101 +* @param mixed $listener listener-config
103 102 */
104 103 public function removeListener($listener) {
105   - $listener = $this->getListenerInfo($listener, get_class($this));
  104 + $listener = <?php echo $listenerName; ?>::getListenerConfig($listener, get_class($this), $this->getPrimaryKey());
106 105
107 106 $l = <?php echo $listenerName; ?>Query::create()->findOneById($listener['id']);
108 107
@@ -135,7 +134,7 @@ private function notifyListener($event) {
135 134 $listeners = array_merge($listeners, $allListeners[<?php echo $listenerName; ?>::ALL]);
136 135 }
137 136
138   - // grab dynamic listeners
  137 + // grab local listeners
139 138 $listeners = array_merge($listeners, $this->getListeners());
140 139
141 140 if (count($listeners)) {
@@ -164,7 +163,7 @@ private function notifyListener($event) {
164 163 }
165 164
166 165 /**
167   -* Returns the dynamic listeners
  166 +* Returns the local listeners
168 167 *
169 168 * @return array
170 169 */
@@ -185,8 +184,9 @@ private function saveEnqueuedListeners() {
185 184 if (is_array($this->listenerQueue)) {
186 185 $this->getListeners();
187 186 foreach ($this->listenerQueue as $l) {
188   - $this->listeners = array_merge($this->listeners, self::saveListener($l, $this->getPrimaryKey()));
  187 + $this->listeners[] = self::saveListener($l, $this->getPrimaryKey());
189 188 }
  189 + $this->listenerQueue = null;
190 190 }
191 191 }
192 192
1  lib/.gitignore
... ... @@ -0,0 +1 @@
  1 +/propel
38 lib/propel-1.6.1/CHANGELOG
... ... @@ -1,38 +0,0 @@
1   -= Changelog Of The Propel 1.6 Branch =
2   -
3   -== 2011-06-14: Version 1.6.1 ==
4   -
5   - * [2318] Fixed handling of custom sqlType in migrations (closes #1348)
6   - * [2317] fixed `PropelObjectCollection::populateRelation()` when using classPrefix or namespaces (based on a patch by mattleff) (closes #1402)
7   - * [2316] Made `PropelObjectCollection::populateRelation()` initialize empty collections on entities having no related entity in a one-to-many relationship (closes #1182)
8   - * [2315] Added all supported MySQL table options (closes #1447)
9   - * [2314] Fixed phpDoc of generated ActiveRecord getter and setter methods for nested set models
10   - * [2313] Fixed autoloading of namespaced models when using `useQuery()` (closes #1444)
11   - * [2312] Fixed formatting issues in generated TableMap classes
12   - * [2311] Fixed location of FKeys in PostgreSQL migrations (closes #1411)
13   - * [2310] Fixed handling of empty string values on boolean columns for ActiveRecord mutator and ActiveQuery filter (closes #1437)
14   - * [2309] fixed inconsistent EOL types in builder classes (closes #1436)
15   - * [2308] fixed inconsistent EOL types in builder classes (closes #1436)
16   - * [2307] Fixed "Nesting level too deep" error when similar schemas are used (patch from gepo) (closes #1426)
17   - * [2306] Improved runtime/exception phpDoc formatting (patch by kupokomapa) (closes #1429)
18   - * [2305] Improved runtime/logger phpDoc formatting (patch by kupokomapa) (closes #1428)
19   - * [2304] Improved runtime/connection phpDoc blocks (based on a patch by kupokomapa) (closes #1425)
20   - * [2303] Added `ModelCriteria::getSelect()` (closes #1412)
21   - * [2302] Added `PropelOnDemandCollection::toArray()` (closes #1415)
22   - * [2301] Fixed subquery bug with select (closes #1417)
23   - * [2300] Added test to prove subquery bug with select (refs #1417)
24   - * [2299] Fixed `PropelObjectCollection` and `PropelArrayCollection` would throw a fatal error when calling save() in conjunction with readOnly entities (closes #1422)
25   - * [2298] Improved runtime/config phpDoc blocks (patch by kupokomapa) (closes #1424)
26   - * [2297] Improved runtime/collections phpDoc blocks (based on a patch by kupokomapa) (closes #1423)
27   - * [2296] Fixed coding standards in DBAdapter (closes #1421)
28   - * [2295] Improved runtime/adapter phpDoc blocks (patch by kupokomapa) (refs #1421)
29   - * [2294] Fixed soft delete via Peer class executes a wrong query (closes #1405)
30   - * [2293] Fixed `forceDelete()` enables soft delete behavior even when disabled (closes #1404)
31   - * [2292] Fixed tests under PHP 5.2 (closes #1388)
32   - * [2291] Fixed minor formatting issue in generated Peer class
33   - * [2290] Fixed generated column filters for enum columns when passed an arry (closes #1381)
34   - * [2289] Fixed strict standards error in soft delete behavior (closes #1398)
35   - * [2288] Added missing `findRoots()` method to nested_set behavior with scope (closes #1397)
36   - * [2287] Fixed bad binding with SQLSRV adapter (refs #1199) (closes #1400)
37   - * [2286] Fixed DATE column with defaultValue of 0000-00-00 generates fatal (closes #1389)
38   - * [2285] Fixed typo in README
4 lib/propel-1.6.1/INSTALL
... ... @@ -1,4 +0,0 @@
1   -I N S T A L L I N G P R O P E L
2   -==================================
3   -
4   -See docs/guide/01-Installation.txt for detailed installation instructions.
19 lib/propel-1.6.1/LICENSE
... ... @@ -1,19 +0,0 @@
1   -Copyright (c) 2005-2010 Hans Lellelid, David Zuelke, Francois Zaninotto
2   -
3   -Permission is hereby granted, free of charge, to any person obtaining a copy
4   -of this software and associated documentation files (the "Software"), to deal
5   -in the Software without restriction, including without limitation the rights
6   -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7   -copies of the Software, and to permit persons to whom the Software is
8   -furnished to do so, subject to the following conditions:
9   -
10   -The above copyright notice and this permission notice shall be included in
11   -all copies or substantial portions of the Software.
12   -
13   -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14   -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15   -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16   -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17   -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18   -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19   -THE SOFTWARE.
755 lib/propel-1.6.1/WHATS_NEW
... ... @@ -1,755 +0,0 @@
1   -= What's new in Propel 1.6? =
2   -
3   -[[PageOutline]]
4   -
5   -Propel 1.6 is a new backwards compatible iteration of the Propel 1.x branch. As usual, don't forget to rebuild your model once you upgrade to this new version.
6   -
7   -== Migrations ==
8   -
9   -How do you manage changes to your database as the Model evolves and the schema changes? Calling the `sql` and `insert-sql` task each time the schema is updated has one dreadful drawback: it erases all the data in the database.
10   -
11   -Starting with Propel 1.6, the `sql`-`insert-sql` sequence is replaced by the `diff`-`migrate` sequence:
12   -
13   -{{{
14   -> propel-gen diff
15   -
16   -[propel-sql-diff] Reading databases structure...
17   -[propel-sql-diff] 1 tables imported from databases.
18   -[propel-sql-diff] Loading XML schema files...
19   -[propel-sql-diff] 2 tables found in 1 schema file.
20   -[propel-sql-diff] Comparing models...
21   -[propel-sql-diff] Structure of database was modified: 1 added table, 1 modified table
22   -[propel-sql-diff] "PropelMigration_1286484196.php" file successfully created in /path/to/project/build/migrations
23   -[propel-sql-diff] Please review the generated SQL statements, and add data migration code if necessary.
24   -[propel-sql-diff] Once the migration class is valid, call the "migrate" task to execute it.
25   -
26   -> propel-gen migrate
27   -
28   -[propel-migration] Executing migration PropelMigration_1286484196 up
29   -[propel-migration] 4 of 4 SQL statements executed successfully on datasource "bookstore"
30   -[propel-migration] Migration complete. No further migration to execute.
31   -}}}
32   -
33   -`diff` compares the schema to the database, and generates a class with all the required `ALTER TABLE` and `CREATE TABLE` statements to update the database structure. This migration class then feeds the `migrate` task, which connects to the database and executes the migrations - with no data loss.
34   -
35   -Migrations are a fantastic way to work on complex projects with always evolving models ; they are also a great tool for team work, since migration classes can be shared among all developers. That way, when a developer adds a table to the model, a second developer just needs to run the related migration to have the table added to the table.
36   -
37   -Propel migrations can also be executed incrementally - the new `up` and `down` tasks are there for that. And when you're lost in migration, call the `status` task to chack which migrations were already executed, and which ones should be executed to update the database structure.
38   -
39   -The Propel guide offers [wiki:Documentation/1.6/Migrations an entire chapter on Migrations] to explain how to use them and how they work.
40   -
41   -Migrations only work on MySQL and PostgreSQL for now. On other platforms, you should continue to use `sql` and `insert-sql`.
42   -
43   -== New Behaviors ==
44   -
45   -Propel 1.6 ships with more core behaviors than ever.
46   -
47   -=== Versionable behavior ===
48   -
49   -Once enabled on a table, the `versionable` behavior will store a copy of the !ActiveRecord object in a separate table each time it is saved. This allows to keep track of the changes made on an object, whether to review modifications, or revert to a previous state.
50   -
51   -The classic Wiki example is a good illustration of the utility of the `versionable` behavior:
52   -
53   -{{{
54   -#!xml
55   -<table name="wiki_page">
56   - <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
57   - <column name="title" type="VARCHAR" required="true" />
58   - <column name="body" type="LONGVARCHAR" />
59   - <behavior name="versionable" />
60   -</table>
61   -}}}
62   -
63   -After rebuild, the `WikiPage` model has versioning abilities:
64   -
65   -{{{
66   -#!php
67   -<?php
68   -$page = new WikiPage();
69   -
70   -// automatic version increment
71   -$page->setTitle('Propel');
72   -$page->setBody('Propel is a CRM built in PHP');
73   -$page->save();
74   -echo $page->getVersion(); // 1
75   -$page->setBody('Propel is an ORM built in PHP5');
76   -$page->save();
77   -echo $page->getVersion(); // 2
78   -
79   -// reverting to a previous version
80   -$page->toVersion(1);
81   -echo $page->getBody(); // 'Propel is a CRM built in PHP'
82   -// saving a previous version creates a new one
83   -$page->save();
84   -echo $page->getVersion(); // 3
85   -
86   -// checking differences between versions
87   -print_r($page->compareVersions(1, 2));
88   -// array(
89   -// 'Body' => array(1 => 'Propel is a CRM built in PHP', 2 => 'Propel is an ORM built in PHP5'),
90   -// );
91   -
92   -// deleting an object also deletes all its versions
93   -$page->delete();
94   -}}}
95   -
96   -The `versionable` behavior offers audit log functionality, so you can track who made a modification, when, and why:
97   -
98   -{{{
99   -#!php
100   -<?php
101   -$page = new WikiPage();
102   -$page->setTitle('PEAR');
103   -$page->setBody('PEAR is a framework and distribution system for reusable PHP components');
104   -$page->setVersionCreatedBy('John Doe');
105   -$page->setVersionComment('First draft');
106   -$page->save();
107   -// do more modifications...
108   -
109   -// list all modifications
110   -foreach ($page->getAllVersions() as $pageVersion) {
111   - echo sprintf("'%s', Version %d, updated by %s on %s (%s)\n",
112   - $pageVersion->getTitle(),
113   - $pageVersion->getVersion(),
114   - $pageVersion->getVersionCreatedBy(),
115   - $pageVersion->getVersionCreatedAt(),
116   - $pageVersion->getVersionComment(),
117   - );
118   -}
119   -// 'PEAR', Version 1, updated by John Doe on 2010-12-21 22:53:02 (First draft)
120   -// 'PEAR', Version 2, updated by ...
121   -}}}
122   -
123   -If it was just for that, the `versionable` behavior would already be awesome. Versioning is a very common feature, and there is no doubt that this behavior will replace lots of boilerplate code. Consider the fact that it's very configurable, [wiki:Documentation/1.6/Behaviors/versionable fully documented], and unit tested, and there is no reason to develop your own versioning layer.
124   -
125   -But there is more. The `versionable` behavior also works on relationships. If the `WikiPage` has one `Category`, and if the `Category` model also uses the `versionable` behavior, then each time a `WikiPage` is saved, it saves the version of the related `Category` it is related to, and it is able to restore it:
126   -
127   -{{{
128   -#!php
129   -<?php
130   -$category = new Category();
131   -$category->setName('Libraries');
132   -$page = new WikiPage();
133   -$page->setTitle('PEAR');
134   -$page->setBody('PEAR is a framework and distribution system for reusable PHP components');
135   -$page->setCategory($category);
136   -$page->save(); // version 1
137   -
138   -$page->setTitle('PEAR - PHP Extension and Application Repository');
139   -$page->save(); // version 2
140   -
141   -$category->setName('PHP Libraries');
142   -$page->save(); // version 3
143   -
144   -$page->toVersion(1);
145   -echo $page->getTitle(); // 'PEAR'
146   -echo $page->getCategory()->getName(); // 'Libraries'
147   -$page->toVersion(3);
148   -echo $page->getTitle(); // 'PEAR - PHP Extension and Application Repository'
149   -echo $page->getCategory()->getName(); // 'PHP Libraries'
150   -}}}
151   -
152   -Now the versioning is not limited to a single class anymore. You can even design a fully versionable '''application''' - it all depends on your imagination.
153   -
154   -=== I18n behavior ===
155   -
156   -The `i18n` behavior provides support for internationalization on the model. Using this behavior, the text columns of an !ActiveRecord object can have several translations.
157   -
158   -This is useful in multilingual applications, such as an e-commerce website selling home appliances across the world. This website should keep the name and description of each item separated from the other details, and keep one version for each supported language.
159   -
160   -Starting with Propel 1.6, this is possible by adding a simple `<behavior>` tag to the table that needs internationalization:
161   -
162   -{{{
163   -#!xml
164   -<table name="item">
165   - <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
166   - <column name="name" type="VARCHAR" required="true" />
167   - <column name="description" type="LONGVARCHAR" />
168   - <column name="price" type="FLOAT" />
169   - <column name="is_in_store" type="BOOLEAN" />
170   - <behavior name="i18n">
171   - <parameter name="i18n_columns" value="name, description" />
172   - </behavior>
173   -</table>
174   -}}}
175   -
176   -In this example, the `name` and `description` columns are moved to a new table, called `item_i18n`, which shares a many-to-one relationship with Item - one Item has many Item translations. But all this happens in the background; for the end user, everything happens as if there were only one main `Item` object:
177   -
178   -{{{
179   -#!php
180   -<?php
181   -$item = new Item();
182   -$item->setPrice('12.99');
183   -$item->setName('Microwave oven');
184   -$item->save();
185   -}}}
186   -
187   -This creates one record in the `item` table with the price, and another in the `item_i18n` table with the English (default language) translation for the name. Of course, you can add more translations:
188   -
189   -{{{
190   -#!php
191   -<?php
192   -$item->setLocale('fr_FR');
193   -$item->setName('Four micro-ondes');
194   -$item->setLocale('es_ES');
195   -$item->setName('Microondas');
196   -$item->save();
197   -}}}
198   -
199   -This works both for setting AND for getting internationalized columns:
200   -
201   -{{{
202   -#!php
203   -<?php
204   -$item->setLocale('en_EN');
205   -echo $item->getName(); //'Microwave oven'
206   -$item->setLocale('fr_FR');
207   -echo $item->getName(); // 'Four micro-ondes'
208   -}}}
209   -
210   -'''Tip''': The big advantage of Propel behaviors is that they use code generation. Even though it's only a proxy method to the `ItemI18n` class, `Item::getName()` has all the phpDoc required to make your IDE happy.
211   -
212   -This new behavior also adds special capabiliies to the Query objects. The most interesting allows you to execute less queries when you need to query for an Item and one of its translations - which is common to display a list of items in the locale of the user:
213   -
214   -{{{
215   -#!php
216   -<?php
217   -$items = ItemQuery::create()->find(); // one query to retrieve all items
218   -$locale = 'en_EN';
219   -foreach ($items as $item) {
220   - echo $item->getPrice();
221   - $item->setLocale($locale);
222   - echo $item->getName(); // one query to retrieve the English translation
223   -}
224   -}}}
225   -
226   -This code snippet requires 1+n queries, n being the number of items. But just add one more method call to the query, and the SQL query count drops to 1:
227   -
228   -{{{
229   -#!php
230   -<?php
231   -$items = ItemQuery::create()
232   - ->joinWithI18n('en_EN')
233   - ->find(); // one query to retrieve both all items and their translations
234   -foreach ($items as $item) {
235   - echo $item->getPrice();
236   - echo $item->getName(); // no additional query
237   -}
238   -}}}
239   -
240   -In addition to hydrating translations, `joinWithI18n()` sets the correct locale on results, so you don't need to call `setLocale()` for each result.
241   -
242   -'''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()`.
243   -
244   -Last but not least, Propel's `i18n` behavior is a drop-in replacement for symfony's `i18n` behavior. That means that with a couple more parameters, the locale can be accessed using `setCulture()`, and the `i18n_columns` parameter can be omitted if you explicit the `i18n` table.
245   -
246   -Just like the `versionable` behavior, the `i18n` behavior is thoroughly unit-tested and [wiki:Documentation/1.6/Behaviors/i18n fully documented].
247   -
248   -== XML/YAML/JSON/CSV Parsing and Dumping ==
249   -
250   -ActiveRecord and Collection objects now have the ability to be converted to and from a string, using any of the XML, YAML, JSON, and CSV formats.
251   -
252   -The syntax is very intuitive: ActiveRecord and collection objects now offer a `toXML()` and a `fromXML()` method (same for YAML, JSON, and CSV). Here are a few examples:
253   -
254   -{{{
255   -#!php
256   -<?php
257   -// dump a collection to YAML
258   -$books = BookQuery::create()
259   - ->orderByTitle()
260   - ->joinWith('Author')
261   - ->find();
262   -echo $books->toYAML();
263   -// Book_1:
264   -// Id: 123
265   -// Title: Pride and Prejudice
266   -// AuthorId: 456
267   -// Author:
268   -// Id: 456
269   -// FirstName: Jane
270   -// LastName: Austen
271   -// Book_2:
272   -// Id: 789
273   -// Title: War and Peace
274   -// AuthorId: 147
275   -// Author:
276   -// Id: 147
277   -// FirstName: Leo
278   -// LastName: Tolstoi
279   -
280   -// parse an XML string into an object
281   -$bookString = <<<EOF
282   -<?xml version="1.0" encoding="UTF-8"?>
283   -<data>
284   - <Id>9012</Id>
285   - <Title><![CDATA[Don Juan]]></Title>
286   - <ISBN><![CDATA[0140422161]]></ISBN>
287   - <Price>12.99</Price>
288   - <PublisherId>1234</PublisherId>
289   - <AuthorId>5678</AuthorId>
290   -</data>
291   -EOF;
292   -$book = new Book();
293   -$book->fromXML($bookString);
294   -echo $book->getTitle(); // Don Juan
295   -}}}
296   -
297   -== Model Objects String Representation ==
298   -
299   -Taking advantage of the dumping abilities just introduced, all ActiveRecord objects now have a string representation based on a YAML dump of their properties:
300   -
301   -{{{
302   -#!php
303   -<?php
304   -$author = new Author();
305   -$author->setFirstName('Leo');
306   -$author->setLastName('Tolstoi');
307   -echo $author;
308   -// Id: null
309   -// FirstName: Leo
310   -// LastName: Tolstoi
311   -// Email: null
312   -// Age: null
313   -}}}
314   -
315   -'''Tip''': Tables with a column using the `isPrimaryString` attribute still output the value of a single column as string representation.
316   -
317   -`PropelCollection` objects also take advantage from this possibility:
318   -
319   -{{{
320   -#!php
321   -<?php
322   -$authors = AuthorQuery::create()
323   - ->orderByLastName()
324   - ->find();
325   -echo $authors;
326   -// Author_0:
327   -// Id: 456
328   -// FirstName: Jane
329   -// LastName: Austen
330   -// Email: null
331   -// Age: null
332   -// Author_1:
333   -// Id: 147
334   -// FirstName: Leo
335   -// LastName: Tolstoi
336   -// Email: null
337   -// Age: null
338   -}}}
339   -
340   -If you want to use another format for the default string representation instead of YAML, you can set the `defaultStringFormat` attribute to any of the supported formats in either the `<database>` or the `<table>` elements in the XML schema:
341   -
342   -{{{
343   -#!xml
344   -<table name="publisher" defaultStringFormat="XML">
345   - <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
346   - <column name="name" required="true" type="VARCHAR" size="128" />
347   -</table>
348   -}}}
349   -
350   -{{{
351   -#!php
352   -<?php
353   -$publisher = new Publisher();
354   -$publisher->setName('Penguin');
355   -echo $publisher;
356   -// <?xml version="1.0" encoding="UTF-8"?>
357   -// <data>
358   -// <Id></Id>
359   -// <Name><![CDATA[Peguin]]></Name>
360   -// </data>
361   -}}}
362   -
363   -== Easier OR in Queries ==
364   -
365   -Combining two generated filters with a logical `OR` used to be impossible in previous Propel versions - the alternative was to use `orWhere()` or `combine()`, but that meant losing all the smart defaults of generated filters.
366   -
367   -Propel 1.6 introduces a new method for Query objects: `_or()`. It just specifies that the next condition will be combined with a logical `OR` rather than an `AND`.
368   -
369   -{{{
370   -#!php
371   -<?php
372   -// Basic usage: _or() as a drop-in replacement for orWhere()
373   -$books = BookQuery::create()
374   - ->where('Book.Title = ?', 'War And Peace')
375   - ->_or()
376   - ->where('Book.Title LIKE ?', 'War%')
377   - ->find();
378   -// SELECT * FROM book WHERE book.TITLE = 'War And Peace' OR book.TITLE LIKE 'War%'
379   -
380   -// _or() also works on generated filters:
381   -$books = BookQuery::create()
382   - ->filterByTitle('War And Peace')
383   - ->_or()
384   - ->filterByTitle('War%')
385   - ->find();
386   -// SELECT * FROM book WHERE book.TITLE = 'War And Peace' OR book.TITLE LIKE 'War%'
387   -
388   -// _or() also works on embedded queries
389   -$books = BookQuery::create()
390   - ->filterByTitle('War and Peace')
391   - ->_or()
392   - ->useAuthorQuery()
393   - ->filterByName('Leo Tolstoi')
394   - ->endUse()
395   - ->find();
396   -// SELECT book.* from book
397   -// INNER JOIN author ON book.AUTHOR_ID = author.ID
398   -// WHERE book.TITLE = 'War and Peace'
399   -// OR author.NAME = 'Leo Tolstoi'
400   -}}}
401   -
402   -This new method is implemented in the `Criteria` class, so it also works for the old-style queries (using `add()` for conditions).
403   -
404   -'''Tip''': Since `ModelCriteria::orWhere()` is a synonym for `->_or()->where()`, it is now deprecated.
405   -
406   -== Multiple Buildtime Connections ==
407   -
408   -Propel 1.5 used the `build.properties` for buildtime connection settings. This had one major drawback: it used to be impossible to deal with several connections at buildtime, let alone several RDBMS.
409   -
410   -In Propel 1.6, you can write your buildtime connection settings in a `buildtime-conf.xml` file. The format is the same as the `runtime-conf.xml` file, so a good starting point is to copy the runtime conf, and change the settings for users wit hgreater privileges.
411   -
412   -Here is an example buildtime configuration file that defines a MySQL and a SQLite connection:
413   -
414   -{{{
415   -#!xml
416   -<?xml version="1.0"?>
417   -<config>
418   - <propel>
419   - <datasources default="bookstore">
420   - <datasource id="bookstore">
421   - <adapter>mysql</adapter>
422   - <connection>
423   - <dsn>mysql:host=localhost;dbname=bookstore</dsn>
424   - <user>testuser</user>
425   - <password>password</password>
426   - </connection>
427   - </datasource>
428   - <datasource id="cms">
429   - <adapter>sqlite</adapter>
430   - <connection>
431   - <dsn>sqlite:/opt/databases/mydb.sq3</dsn>
432   - </connection>
433   - </datasource>
434   - </datasources>
435   - </propel>
436   -</config>
437   -}}}
438   -
439   -Now that Propel can deal with database vendors at buildtime more accurately, the generated classes offer more optimizations for the database they rely one. Incidentally, that means that you should rebuild your model if you use different database vendors. Thats includes cases when your developement and production environments use different vendors.
440   -
441   -== Support For SQL Schemas ==
442   -
443   -For complex models showing a large number of tables, database administrators often like to group tables into "SQL schemas", which are namespaces in the SQL server. Starting with Propel 1.6, it is now possible to assign tables to SQL schemas using the `schema` attribute in the `<database>` of the `<table>` tag:
444   -
445   -{{{
446   -#!xml
447   -<database name="my_connection">
448   - <table name="book" schema="bookstore">
449   - <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
450   - <column name="title" type="VARCHAR" required="true" />
451   - <column name="author_id" type="INTGER" />
452   - <foreign-key foreignTable="author" foreignSchema="people" onDelete="setnull" onUpdate="cascade">
453   - <reference local="author_id" foreign="id" />
454   - </foreign-key>
455   - </table>
456   - <table name="author" schema="people">
457   - <column name="id" required="true" primaryKey="true" autoIncrement="true" type="INTEGER" />
458   - <column name="name" type="VARCHAR" required="true" />
459   - </table>
460   -</database>
461   -}}}
462   -
463   -'''Tip''': This feature is only available in PostgreSQL, MSSQL, and MySQL. The `schema` attribute is simply ignored in Oracle and SQLite.
464   -
465   -Propel also supports foreign keys between tables assigned to two different schemas. For MySQL, where "SQL schema" is a synonym for "database", this allows for cross-database queries.
466   -
467   -The Propel documentation contains a new tutorial about the SQL schema attributes and usage, called [wiki:Documentation/1.6/Using-SQL-Schemas Using SQL Schemas].
468   -
469   -== Foreign Key Filters Now Accept a Collection ==
470   -
471   -The generated `filterByRelationName()` methods in the model queries now accept a `PropelCollection` as argument. This will allow you to keep using objects and avoid dealing with foreign keys completely:
472   -
473   -{{{
474   -#!php
475   -<?php
476   -// get young authors
477   -$authors = AuthorQuery::create()
478   - ->filterByAge(array('max' => 35))
479   - ->find(); // $authors is a PropelObjectCollection
480   -// get all books by young authors
481   -$books = BookQuery::create()
482   - ->filterByAuthor($authors) // <= That's new
483   - ->find();
484   -}}}
485   -
486   -== Join With Several Conditions ==
487   -
488   -Creating a Join with more than one connection is now very easy. Just call `ModelCriteria::addJoinCondition($joinName, $condition)` after a `ModelCriteria::join()` to add further conditions to a join:
489   -
490   -{{{
491   -#!php
492   -<?php
493   -$authors = AuthorQuery::create()
494   - ->join('Author.Book')
495   - ->addJoinCondition('Book', 'Book.Title IS NOT NULL')
496   - ->find();
497   -// SELECT * FROM author
498   -// INNER JOIN book ON (author.ID=book.AUTHOR_ID AND book.TITLE IS NOT NULL);
499   -}}}
500   -
501   -If you need to bind a variable to the condition, set the variable as last parameter of the `addJoinCondition()` call. Propel correctly binds the value using PDO:
502   -
503   -{{{
504   -#!php
505   -<?php
506   -$authors = AuthorQuery::create()
507   - ->join('Author.Book')
508   - ->addJoinCondition('Book', 'Book.Title LIKE ?', 'War%')
509   - ->find();
510   -// SELECT * FROM author
511   -// INNER JOIN book ON (author.ID=book.AUTHOR_ID AND book.TITLE LIKE 'War%');
512   -}}}
513   -
514   -'''Tip''': `Criteria::addMultipleJoin()`, which allowed the same feature to some extent in previous versions, is now deprecated, since it was vulnerable in SQL injection attacks.
515   -
516   -== Model-Only Relationships ==
517   -
518   -Propel models can share relationships even though the underlying tables aren't linked by a foreign key. This ability may be of great use when using Propel on top of a legacy database.
519   -
520   -For example, a `review` table designed for a MyISAM database engine is linked to a `book` table by a simple `book_id` column:
521   -
522   -{{{
523   -#!xml
524   -<table name="review">
525   - <column name="review_id" type="INTEGER" primaryKey="true" required="true"/>
526   - <column name="reviewer" type="VARCHAR" size="50" required="true"/>
527   - <column name="book_id" required="true" type="INTEGER"/>
528   -</table>
529   -}}}
530   -
531   -To enable a model-only relationship, add a `<foreign-key>` tag using the `skipSql` attribute, as follows:
532   -
533   -{{{
534   -#!xml
535   -<table name="review">
536   - <column name="review_id" type="INTEGER" primaryKey="true" required="true"/>
537   - <column name="reviewer" type="VARCHAR" size="50" required="true"/>
538   - <column name="book_id" required="true" type="INTEGER"/>
539   - <!-- Model-only relationship -->
540   - <foreign-key foreignTable="book" onDelete="CASCADE" skipSql="true">
541   - <reference local="book_id" foreign="id"/>
542   - </foreign-key>
543   -</table>
544   -}}}
545   -
546   -Such a foreign key is not translated into SQL when Propel builds the table creation or table migration code. It can be seen as a "virtual foreign key". However, on the PHP side, the `Book` model actually has a one-to-many relationship with the `Review` model. The generated !ActiveRecord and !ActiveQuery classes take advantage of this relationship to offer smart getters and filters.
547   -
548   -== Advanced Column Types ==
549   -
550   -Propel 1.6 introduces a new set of column types. The database-agnostic implementation allows these column types to work on all supported RDBMS.
551   -
552   -=== ENUM Columns ===
553   -
554   -Although stored in the database as integers, ENUM columns let users manipulate a set of predefined values, without worrying about their storage.
555   -
556   -{{{
557   -#!xml
558   -<table name="book">
559   - ...
560   - <column name="style" type="ENUM" valueSet="novel, essay, poetry" />
561   -</table>
562   -}}}
563   -
564   -{{{
565   -#!php
566   -<?php
567   -// The ActiveRecord setter and getter let users use any value from the valueSet
568   -$book = new Book();
569   -$book->setStyle('novel');
570   -echo $book->getStyle(); // novel
571   -// Trying to set a value not in the valueSet throws an exception
572   -
573   -// Each value in an ENUM column has a related constant in the Peer class
574   -// Your IDE with code completion should love this
575   -echo BookPeer::STYLE_NOVEL; // 'novel'
576   -echo BookPeer::STYLE_ESSAY; // 'essay'
577   -echo BookPeer::STYLE_POETRY; // 'poetry'
578   -// The Peer class also gives access to list of available values
579   -print_r(BookPeer::getValueSet(BookPeer::STYLE)); // array('novel', 'essay', 'poetry')
580   -
581   -// ENUM columns are also searchable, using the generated filterByXXX() method
582   -// or other ModelCritera methods (like where(), orWhere(), condition())
583   -$books = BookQuery::create()
584   - ->filterByStyle('novel')
585   - ->find();
586   -}}}
587   -
588   -=== OBJECT Columns ===
589   -
590   -An `OBJECT` column can store PHP objects (mostly Value Objects) in the database. The column setter serializes the object, which is later stored to the database as a string. The column getter unserializes the string and returns the object. Therefore, for the end user, the column contains an object.
591   -
592   -{{{
593   -#!php
594   -<?php
595   -class GeographicCoordinates
596   -{
597   - public $latitude, $longitude;
598   -
599   - public function __construct($latitude, $longitude)
600   - {
601   - $this->latitude = $latitude;
602   - $this->longitude = $longitude;
603   - }
604   -
605   - public function isInNorthernHemisphere()
606   - {
607   - return $this->latitude > 0;
608   - }
609   -}
610   -
611   -// The 'house' table has a 'coordinates' column of type OBJECT
612   -$house = new House();
613   -$house->setCoordinates(new GeographicCoordinates(48.8527, 2.3510));
614   -echo $house->getCoordinates()->isInNorthernHemisphere(); // true
615   -$house->save();
616   -}}}
617   -
618   -Not only do `OBJECT` columns benefit from these smart getter and setter in the generated Active Record class, they are also searchable using the generated `filterByXXX()` method in the query class:
619   -
620   -{{{
621   -#!php
622   -<?php
623   -$house = HouseQuery::create()
624   - ->filterByCoordinates(new GeographicCoordinates(48.8527, 2.3510))
625   - ->find();
626   -}}}
627   -
628   -Propel looks in the database for a serialized version of the object passed as parameter of the `filterByXXX()` method.
629   -
630   -=== ARRAY Columns ===
631   -
632   -An `ARRAY` column can store a simple PHP array in the database (nested arrays and associative arrays are not accepted). The column setter serializes the array, which is later stored to the database as a string. The column getter unserializes the string and returns the array. Therefore, for the end user, the column contains an array.
633   -
634   -{{{
635   -#!php
636   -<?php
637   -// The 'book' table has a 'tags' column of type ARRAY
638   -$book = new Book();
639   -$book->setTags(array('novel', 'russian'));
640   -print_r($book->getTags()); // array('novel', 'russian')
641   -
642   -// If the column name is plural, Propel also generates hasXXX(), addXXX(),
643   -// and removeXXX() methods, where XXX is the singular column name
644   -echo $book->hasTag('novel'); // true
645   -$book->addTag('romantic');
646   -print_r($book->getTags()); // array('novel', 'russian', 'romantic')
647   -$book->removeTag('russian');
648   -print_r($book->getTags()); // array('novel', 'romantic')
649   -}}}
650   -
651   -Propel doesn't use `serialize()` to transform the array into a string. Instead, it uses a special serialization function, that makes it possible to search for values of `ARRAY` columns.
652   -
653   -{{{
654   -#!php
655   -<?php
656   -// Search books that contain all the specified tags
657   -$books = BookQuery::create()
658   - ->filterByTags(array('novel', 'russian'), Criteria::CONTAINS_ALL)
659   - ->find();
660   -
661   -// Search books that contain at least one of the specified tags
662   -$books = BookQuery::create()
663   - ->filterByTags(array('novel', 'russian'), Criteria::CONTAINS_SOME)
664   - ->find();
665   -
666   -// Search books that don't contain any of the specified tags
667   -$books = BookQuery::create()
668   - ->filterByTags(array('novel', 'russian'), Criteria::CONTAINS_NONE)
669   - ->find();
670   -
671   -// If the column name is plural, Propel also generates singular filter methods
672   -// expecting a scalar parameter instead of an array
673   -$books = BookQuery::create()
674   - ->filterByTag('russian')
675   - ->find();
676   -}}}
677   -
678   -'''Tip''': Filters on array columns translate to SQL as LIKE conditions. That means that the resulting query often requires a full table scan, and is not suited for large tables.
679   -
680   -'''Warning''': Only generated Query classes (through generated `filterByXXX()` methods) and `ModelCriteria` (through `where()`, `orWhere()`, and `condition()`) allow conditions on `ENUM`, `OBJECT`, and `ARRAY` columns. `Criteria` alone (through `add()`, `addAnd()`, and `addOr()`) does not support conditions on such columns.
681   -
682   -== Table Subqueries (a.k.a "Inline Views") ==
683   -
684   -SQL supports table subqueries to solve complex cases that a single query can't solve, or to optimize slow queries with several joins. For instance, to find the latest book written by every author in SQL, it usually takes a query like the following:
685   -
686   -{{{
687   -#!sql
688   -SELECT book.ID, book.TITLE, book.AUTHOR_ID, book.PRICE, book.CREATED_AT, MAX(book.CREATED_AT)
689   -FROM book
690   -GROUP BY book.AUTHOR_ID
691   -}}}
692   -
693   -Now if you want only the cheapest latest books with a single query, you need a subquery:
694   -{{{
695   -#!sql
696   -SELECT lastBook.ID, lastBook.TITLE, lastBook.AUTHOR_ID, lastBook.PRICE, lastBook.CREATED_AT
697   -FROM
698   -(