/
AbstractOMBuilder.php
823 lines (721 loc) · 27.8 KB
/
AbstractOMBuilder.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
<?php
/**
* This file is part of the Propel package.
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @license MIT License
*/
namespace Propel\Generator\Builder\Om;
use Propel\Generator\Builder\DataModelBuilder;
use Propel\Generator\Builder\Util\PropelTemplate;
use Propel\Generator\Exception\InvalidArgumentException;
use Propel\Generator\Exception\LogicException;
use Propel\Generator\Exception\RuntimeException;
use Propel\Generator\Model\Column;
use Propel\Generator\Model\ForeignKey;
use Propel\Generator\Model\Table;
/**
* Baseclass for OM-building classes.
*
* OM-building classes are those that build a PHP (or other) class to service
* a single table. This includes Peer classes, Entity classes, Map classes,
* Node classes, Nested Set classes, etc.
*
* @author Hans Lellelid <hans@xmpl.org>
*/
abstract class AbstractOMBuilder extends DataModelBuilder
{
/**
* Declared fully qualified classnames, to build the 'namespace' statements
* according to this table's namespace.
*
* @var array
*/
protected $declaredClasses = array();
/**
* Mapping between fully qualified classnames and their short classname or alias
*
* @var array
*/
protected $declaredShortClassesOrAlias = array();
/**
* List of classes that can be use without alias when model don't have namespace
*
* @var array
*/
protected $whiteListOfDeclaredClasses = array('PDO', 'Exception', 'DateTime');
/**
* Builds the PHP source for current class and returns it as a string.
*
* This is the main entry point and defines a basic structure that classes should follow.
* In most cases this method will not need to be overridden by subclasses. This method
* does assume that the output language is PHP code, so it will need to be overridden if
* this is not the case.
*
* @return string The resulting PHP sourcecode.
*/
public function build()
{
$this->validateModel();
$this->declareClass($this->getFullyQualifiedClassName());
$script = '';
$this->addClassOpen($script);
$this->addClassBody($script);
$this->addClassClose($script);
$ignoredNamespace = $this->getNamespace();
if ($useStatements = $this->getUseStatements($ignoredNamespace ?: 'namespace')) {
$script = $useStatements . $script;
}
if ($namespaceStatement = $this->getNamespaceStatement()) {
$script = $namespaceStatement . $script;
}
$script = "<?php
" . $script;
return $this->clean($script);
}
/**
* Validates the current table to make sure that it won't
* result in generated code that will not parse.
*
* This method may emit warnings for code which may cause problems
* and will throw exceptions for errors that will definitely cause
* problems.
*/
protected function validateModel()
{
// Validation is currently only implemented in the subclasses.
}
/**
* Creates a $obj = new Book(); code snippet. Can be used by frameworks, for instance, to
* extend this behavior, e.g. initialize the object after creating the instance or so.
*
* @return string Some code
*/
public function buildObjectInstanceCreationCode($objName, $clsName)
{
return "$objName = new $clsName();";
}
/**
* Returns the qualified (prefixed) classname that is being built by the current class.
* This method must be implemented by child classes.
*
* @return string
*/
abstract public function getUnprefixedClassName();
/**
* Returns the unqualified classname (e.g. Book)
*
* @return string
*/
public function getUnqualifiedClassName()
{
return $this->getUnprefixedClassName();
}
/**
* Returns the qualified classname (e.g. Model\Book)
*
* @return string
*/
public function getQualifiedClassName()
{
if ($namespace = $this->getNamespace()) {
return $namespace . '\\' . $this->getUnqualifiedClassName();
}
return $this->getUnqualifiedClassName();
}
/**
* Returns the fully qualified classname (e.g. \Model\Book)
*
* @return string
*/
public function getFullyQualifiedClassName()
{
return '\\' . $this->getQualifiedClassName();
}
/**
* Returns FQCN alias of getFullyQualifiedClassName
*
* @return string
*/
public function getClassName()
{
return $this->getFullyQualifiedClassName();
}
/**
* Gets the dot-path representation of current class being built.
*
* @return string
*/
public function getClasspath()
{
if ($this->getPackage()) {
return $this->getPackage() . '.' . $this->getUnqualifiedClassName();
}
return $this->getUnqualifiedClassName();
}
/**
* Gets the full path to the file for the current class.
*
* @return string
*/
public function getClassFilePath()
{
return ClassTools::createFilePath($this->getPackagePath(), $this->getUnqualifiedClassName());
}
/**
* Gets package name for this table.
* This is overridden by child classes that have different packages.
* @return string
*/
public function getPackage()
{
$pkg = ($this->getTable()->getPackage() ? $this->getTable()->getPackage() : $this->getDatabase()->getPackage());
if (!$pkg) {
$pkg = $this->getBuildProperty('targetPackage');
}
return $pkg;
}
/**
* Returns filesystem path for current package.
* @return string
*/
public function getPackagePath()
{
$pkg = $this->getPackage();
if (false !== strpos($pkg, '/')) {
$pkg = preg_replace('#\.(map|om)$#', '/\1', $pkg);
$pkg = preg_replace('#\.(Map|Om)$#', '/\1', $pkg);
return $pkg;
}
return strtr($pkg, '.', '/');
}
/**
* Returns the user-defined namespace for this table,
* or the database namespace otherwise.
*
* @return string
*/
public function getNamespace()
{
return $this->getTable()->getNamespace();
}
/**
* This declare the class use and get the correct name to use (short classname, Alias, or FQCN)
*
* @param AbstractOMBuilder $builder
* @param boolean $fqcn true to return the $fqcn classname
* @return string ClassName, Alias or FQCN
*/
public function getClassNameFromBuilder($builder, $fqcn = false)
{
if ($fqcn) {
return $builder->getFullyQualifiedClassName();
}
$namespace = $builder->getNamespace();
$class = $builder->getUnqualifiedClassName();
if (isset($this->declaredClasses[$namespace])
&& isset($this->declaredClasses[$namespace][$class])) {
return $this->declaredClasses[$namespace][$class];
}
return $this->declareClassNamespace($class, $namespace, true);
}
/**
* Declare a class to be use and return it's name or it's alias
*
* @param string $class the class name
* @param string $namespace the namespace
* @param string|boolean $alias the alias wanted, if set to True, it automatically adds an alias when needed
* @return string the class name or it's alias
*/
public function declareClassNamespace($class, $namespace = '', $alias = false)
{
//check if the class is already declared
if (isset($this->declaredClasses[$namespace])
&& isset($this->declaredClasses[$namespace][$class])) {
return $this->declaredClasses[$namespace][$class];
}
$forcedAlias = $this->needAliasForClassName($class, $namespace);
if (false === $alias || true === $alias || null === $alias) {
$aliasWanted = $class;
$alias = $alias || $forcedAlias;
} else {
$aliasWanted = $alias;
$forcedAlias = false;
}
if (!$forcedAlias && !isset($this->declaredShortClassesOrAlias[$aliasWanted])) {
if (!isset($this->declaredClasses[$namespace])) {
$this->declaredClasses[$namespace] = array();
}
$this->declaredClasses[$namespace][$class] = $aliasWanted;
$this->declaredShortClassesOrAlias[$aliasWanted] = $namespace . '\\' . $class;
return $aliasWanted;
}
// we have a duplicate class and asked for an automatic Alias
if (false !== $alias) {
if ('\\Base' == substr($namespace, -5) || 'Base' == $namespace) {
return $this->declareClassNamespace($class, $namespace, 'Base' . $class);
}
return $this->declareClassNamespace($class, $namespace, 'Child' . $class);
}
throw new LogicException(
sprintf('The class %s duplicates the class %s and can\'t be used without alias',
$namespace . '\\' . $class, $this->declaredShortClassesOrAlias[$aliasWanted])
);
}
/**
* check if the current $class need an alias or if the class could be used with a shortname without conflict
* @param string $class
* @param string $namespace
*/
protected function needAliasForClassName($class, $namespace)
{
if ($namespace == $this->getNamespace()) {
return false;
}
if (str_replace('\\Base', '', $namespace) == str_replace('\\Base', '', $this->getNamespace())) {
return true;
}
if (empty($namespace) && 'Base' === $this->getNamespace()) {
if (str_replace(array('Peer','Query'), '', $class) == str_replace(array('Peer','Query'), '', $this->getUnqualifiedClassName())) {
return true;
} elseif ((false !== strpos($class,'Peer') || false !== strpos($class,'Query'))) {
return true;
} elseif (false === array_search($class, $this->whiteListOfDeclaredClasses, true)) { //force alias for model without namespace
return true;
}
}
if ('Base' == $namespace && '' == $this->getNamespace()) {
if (false === array_search($class, $this->whiteListOfDeclaredClasses, true)) { //force alias for model without namespace
return true;
}
}
return false;
}
/**
* Declare a use statement for a $class with a $namespace and an $aliasPrefix
* This return the short ClassName or an alias
*
* @param string $class the class
* @param string $namespace the namespace
* @param mixed $aliasPrefix optionally an alias or True to force an automatic alias prefix (Base or Child)
* @return string the short ClassName or an alias
*/
public function declareClassNamespacePrefix($class, $namespace = '', $aliasPrefix = false)
{
if (false !== $aliasPrefix && true !== $aliasPrefix) {
$alias = $aliasPrefix . $class;
} else {
$alias = $aliasPrefix;
}
return $this->declareClassNamespace($class, $namespace, $alias);
}
/**
* Declare a Fully qualified classname with an $aliasPrefix
* This return the short ClassName to use or an alias
*
* @param string $fullyQualifiedClassName the fully qualified classname
* @param mixed $aliasPrefix optionally an alias or True to force an automatic alias prefix (Base or Child)
* @return string the short ClassName or an alias
*/
public function declareClass($fullyQualifiedClassName, $aliasPrefix = false)
{
$fullyQualifiedClassName = trim($fullyQualifiedClassName, '\\');
if (($pos = strrpos($fullyQualifiedClassName, '\\')) !== false) {
return $this->declareClassNamespacePrefix(substr($fullyQualifiedClassName, $pos + 1), substr($fullyQualifiedClassName, 0, $pos), $aliasPrefix);
}
// root namespace
return $this->declareClassNamespacePrefix($fullyQualifiedClassName, '', $aliasPrefix);
}
/**
* @param $builder
* @param boolean|string $aliasPrefix the prefix for the Alias or True for auto generation of the Alias
*/
public function declareClassFromBuilder($builder, $aliasPrefix = false)
{
return $this->declareClassNamespacePrefix($builder->getUnqualifiedClassName(), $builder->getNamespace(), $aliasPrefix);
}
public function declareClasses()
{
$args = func_get_args();
foreach ($args as $class) {
$this->declareClass($class);
}
}
/**
* Get the list of declared classes for a given $namespace or all declared classes
*
* @param string $namespace the namespace or null
* @return array list of declared classes
*/
public function getDeclaredClasses($namespace = null)
{
if (null !== $namespace && isset($this->declaredClasses[$namespace])) {
return $this->declaredClasses[$namespace];
}
return $this->declaredClasses;
}
/**
* return the string for the class namespace
*
* @return string
*/
public function getNamespaceStatement()
{
$namespace = $this->getNamespace();
if (!empty($namespace)) {
return sprintf("namespace %s;
", $namespace);
}
}
/**
* Return all the use statement of the class
*
* @param string $ignoredNamespace the ignored namespace
* @return string
*/
public function getUseStatements($ignoredNamespace = null)
{
$script = '';
$declaredClasses = $this->declaredClasses;
unset($declaredClasses[$ignoredNamespace]);
ksort($declaredClasses);
foreach ($declaredClasses as $namespace => $classes) {
asort($classes);
foreach ($classes as $class => $alias) {
//Don't use our own class
if ($class == $this->getUnqualifiedClassName() && $namespace == $this->getNamespace()) {
continue;
}
if ($class == $alias) {
$script .= sprintf("use %s\\%s;
", $namespace, $class);
} else {
$script .= sprintf("use %s\\%s as %s;
", $namespace, $class, $alias);
}
}
}
return $script;
}
/**
* Shortcut method to return the [stub] peer classname for current table.
* This is the classname that is used whenever object or peer classes want
* to invoke methods of the peer classes.
* @param boolean $fqcn
* @return string (e.g. 'MyPeer')
*/
public function getPeerClassName($fqcn = false)
{
return $this->getClassNameFromBuilder($this->getStubPeerBuilder(), $fqcn);
}
/**
* Shortcut method to return the [stub] query classname for current table.
* This is the classname that is used whenever object or peer classes want
* to invoke methods of the query classes.
* @param boolean $fqcn
* @return string (e.g. 'Myquery')
*/
public function getQueryClassName($fqcn = false)
{
return $this->getClassNameFromBuilder($this->getStubQueryBuilder(), $fqcn);
}
/**
* Returns the object classname for current table.
* This is the classname that is used whenever object or peer classes want
* to invoke methods of the object classes.
* @param boolean $fqcn
* @return string (e.g. 'My')
*/
public function getObjectClassName($fqcn = false)
{
return $this->getClassNameFromBuilder($this->getStubObjectBuilder(), $fqcn);
}
/**
* Get the column constant name (e.g. PeerName::COLUMN_NAME).
*
* @param Column $col The column we need a name for.
* @param string $classname The Peer classname to use.
*
* @return string If $classname is provided, then will return $classname::COLUMN_NAME; if not, then the peername is looked up for current table to yield $currTablePeer::COLUMN_NAME.
*/
public function getColumnConstant($col, $classname = null)
{
if (null === $col) {
throw new InvalidArgumentException('No columns were specified.');
}
if (null === $classname) {
return $this->getBuildProperty('classPrefix') . $col->getConstantName();
}
// was it overridden in schema.xml ?
if ($col->getPeerName()) {
$const = strtoupper($col->getPeerName());
} else {
$const = strtoupper($col->getName());
}
return $classname.'::'.$const;
}
/**
* Gets the basePeer path if specified for table/db.
* If not, will return 'propel.util.BasePeer'
* @return string
*/
public function getBasePeer(Table $table)
{
$class = $table->getBasePeer();
if (null === $class) {
$class = 'propel.util.BasePeer';
}
return $class;
}
/**
* Convenience method to get the foreign Table object for an fkey.
* @deprecated use ForeignKey::getForeignTable() instead
* @return Table
*/
protected function getForeignTable(ForeignKey $fk)
{
return $this->getTable()->getDatabase()->getTable($fk->getForeignTableName());
}
/**
* Convenience method to get the default Join Type for a relation.
* If the key is required, an INNER JOIN will be returned, else a LEFT JOIN will be suggested,
* unless the schema is provided with the DefaultJoin attribute, which overrules the default Join Type
*
* @param ForeignKey $fk
* @return string
*/
protected function getJoinType(ForeignKey $fk)
{
if ($defaultJoin = $fk->getDefaultJoin()) {
return "'" . $defaultJoin . "'";
}
if ($fk->isLocalColumnsRequired()) {
return 'Criteria::INNER_JOIN';
}
return 'Criteria::LEFT_JOIN';
}
/**
* Gets the PHP method name affix to be used for fkeys for the current table (not referrers to this table).
*
* The difference between this method and the getRefFKPhpNameAffix() method is that in this method the
* classname in the affix is the foreign table classname.
*
* @param ForeignKey $fk The local FK that we need a name for.
* @param boolean $plural Whether the php name should be plural (e.g. initRelatedObjs() vs. addRelatedObj()
* @return string
*/
public function getFKPhpNameAffix(ForeignKey $fk, $plural = false)
{
if ($fk->getPhpName()) {
if ($plural) {
return $this->getPluralizer()->getPluralForm($fk->getPhpName());
}
return $fk->getPhpName();
}
$className = $fk->getForeignTable()->getPhpName();
if ($plural) {
$className = $this->getPluralizer()->getPluralForm($className);
}
return $className . $this->getRelatedBySuffix($fk);
}
/**
* Gets the "RelatedBy*" suffix (if needed) that is attached to method and variable names.
*
* The related by suffix is based on the local columns of the foreign key. If there is more than
* one column in a table that points to the same foreign table, then a 'RelatedByLocalColName' suffix
* will be appended.
*
* @return string
*/
protected static function getRelatedBySuffix(ForeignKey $fk)
{
$relCol = '';
foreach ($fk->getLocalForeignMapping() as $localColumnName => $foreignColumnName) {
$localTable = $fk->getTable();
$localColumn = $localTable->getColumn($localColumnName);
if (!$localColumn) {
throw new RuntimeException(sprintf('Could not fetch column: %s in table %s.', $localColumnName, $localTable->getName()));
}
if (count($localTable->getForeignKeysReferencingTable($fk->getForeignTableName())) > 1
|| count($fk->getForeignTable()->getForeignKeysReferencingTable($fk->getTableName())) > 0
|| $fk->getForeignTableName() == $fk->getTableName()) {
// self referential foreign key, or several foreign keys to the same table, or cross-reference fkey
$relCol .= $localColumn->getPhpName();
}
}
if (!empty($relCol)) {
$relCol = 'RelatedBy' . $relCol;
}
return $relCol;
}
/**
* Gets the PHP method name affix to be used for referencing foreign key methods and variable names (e.g. set????(), $coll???).
*
* The difference between this method and the getFKPhpNameAffix() method is that in this method the
* classname in the affix is the classname of the local fkey table.
*
* @param ForeignKey $fk The referrer FK that we need a name for.
* @param boolean $plural Whether the php name should be plural (e.g. initRelatedObjs() vs. addRelatedObj()
* @return string
*/
public function getRefFKPhpNameAffix(ForeignKey $fk, $plural = false)
{
$pluralizer = $this->getPluralizer();
if ($fk->getRefPhpName()) {
return $plural ? $pluralizer->getPluralForm($fk->getRefPhpName()) : $fk->getRefPhpName();
}
$className = $fk->getTable()->getPhpName();
if ($plural) {
$className = $pluralizer->getPluralForm($className);
}
return $className . $this->getRefRelatedBySuffix($fk);
}
protected static function getRefRelatedBySuffix(ForeignKey $fk)
{
$relCol = '';
foreach ($fk->getLocalForeignMapping() as $localColumnName => $foreignColumnName) {
$localTable = $fk->getTable();
$localColumn = $localTable->getColumn($localColumnName);
if (!$localColumn) {
throw new RuntimeException(sprintf('Could not fetch column: %s in table %s.', $localColumnName, $localTable->getName()));
}
$foreignKeysToForeignTable = $localTable->getForeignKeysReferencingTable($fk->getForeignTableName());
if ($fk->getForeignTableName() == $fk->getTableName()) {
// self referential foreign key
$relCol .= $fk->getForeignTable()->getColumn($foreignColumnName)->getPhpName();
if (count($foreignKeysToForeignTable) > 1) {
// several self-referential foreign keys
$relCol .= array_search($fk, $foreignKeysToForeignTable);
}
} elseif (count($foreignKeysToForeignTable) > 1 || count($fk->getForeignTable()->getForeignKeysReferencingTable($fk->getTableName())) > 0) {
// several foreign keys to the same table, or symmetrical foreign key in foreign table
$relCol .= $localColumn->getPhpName();
}
}
if (!empty($relCol)) {
$relCol = 'RelatedBy' . $relCol;
}
return $relCol;
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string $modifier The name of the modifier object providing the method in the behavior
* @return boolean
*/
public function hasBehaviorModifier($hookName, $modifier)
{
$modifierGetter = 'get' . $modifier;
foreach ($this->getTable()->getBehaviors() as $behavior) {
if (method_exists($behavior->$modifierGetter(), $hookName)) {
return true;
}
}
return false;
}
/**
* Checks whether any registered behavior on that table has a modifier for a hook
* @param string $hookName The name of the hook as called from one of this class methods, e.g. "preSave"
* @param string $modifier The name of the modifier object providing the method in the behavior
* @param string &$script The script will be modified in this method.
*/
public function applyBehaviorModifierBase($hookName, $modifier, &$script, $tab = " ")
{
$modifierGetter = 'get' . $modifier;
foreach ($this->getTable()->getBehaviors() as $behavior) {
$modifier = $behavior->$modifierGetter();
if (method_exists($modifier, $hookName)) {
if (strpos($hookName, 'Filter') !== false) {
// filter hook: the script string will be modified by the behavior
$modifier->$hookName($script, $this);
} else {
// regular hook: the behavior returns a string to append to the script string
if (!$addedScript = $modifier->$hookName($this)) {
continue;
}
$script .= "
" . $tab . '// ' . $behavior->getName() . " behavior
";
$script .= preg_replace('/^/m', $tab, $addedScript);
}
}
}
}
/**
* Checks whether any registered behavior content creator on that table exists a contentName
* @param string $contentName The name of the content as called from one of this class methods, e.g. "parentClassName"
* @param string $modifier The name of the modifier object providing the method in the behavior
*/
public function getBehaviorContentBase($contentName, $modifier)
{
$modifierGetter = 'get' . $modifier;
foreach ($this->getTable()->getBehaviors() as $behavior) {
$modifier = $behavior->$modifierGetter();
if (method_exists($modifier, $contentName)) {
return $modifier->$contentName($this);
}
}
}
/**
* Use Propel simple templating system to render a PHP file using variables
* passed as arguments. The template file name is relative to the behavior's
* directory name.
*
* @param string $filename
* @param array $vars
* @param string $templateDir
* @return string
*/
public function renderTemplate($filename, $vars = array(), $templateDir = '/templates/')
{
$filePath = __DIR__ . $templateDir . $filename;
if (!file_exists($filePath)) {
// try with '.php' at the end
$filePath = $filePath . '.php';
if (!file_exists($filePath)) {
throw new \InvalidArgumentException(sprintf('Template "%s" not found in "%s" directory',
$filename,
__DIR__ . $templateDir
));
}
}
$template = new PropelTemplate();
$template->setTemplateFile($filePath);
$vars = array_merge($vars, array('behavior' => $this));
return $template->render($vars);
}
/**
* Most of the code comes from the PHP-CS-Fixer project
*/
private function clean($content)
{
// trailing whitespaces
$content = preg_replace('/[ \t]*$/m', '', $content);
// indentation
$content = preg_replace_callback('/^([ \t]+)/m', function ($matches) use ($content) {
return str_replace("\t", ' ', $matches[0]);
}, $content);
// line feed
$content = str_replace("\r\n", "\n", $content);
// Unused "use" statements
preg_match_all('/^use (?P<class>[^\s;]+)(?:\s+as\s+(?P<alias>.*))?;/m', $content, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
if (isset($match['alias'])) {
$short = $match['alias'];
} else {
$parts = explode('\\', $match['class']);
$short = array_pop($parts);
}
preg_match_all('/\b'.$short.'\b/i', str_replace($match[0]."\n", '', $content), $m);
if (!count($m[0])) {
$content = str_replace($match[0]."\n", '', $content);
}
}
// end of line
if (strlen($content) && "\n" != substr($content, -1)) {
$content = $content."\n";
}
return $content;
}
}