prado3 /framework/TComponent.php

Language PHP Lines 2414
MD5 Hash 5b995e2637e9a205f42ac5d37137bebe Estimated Cost $26,762 (why?)
Repository http://prado3.googlecode.com/svn/trunk/ View Raw File
   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
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
<?php
/**
 * TComponent, TPropertyValue classes
 * @author Qiang Xue <qiang.xue@gmail.com>
 * 
 * Global Events, intra-object events, Class behaviors, expanded behaviors
 * @author Brad Anderson <javalizard@mac.com>
 * 
 * @link http://www.pradosoft.com/
 * @copyright Copyright &copy; 2005-2012 PradoSoft
 * @license http://www.pradosoft.com/license/
 * @version $Id: TComponent.php 3212 2012-10-31 09:40:15Z ctrlaltca $
 * @package System
 */

/**
 * TComponent class
 *
 * TComponent is the base class for all PRADO components.
 * TComponent implements the protocol of defining, using properties, behaviors,
 * and events.
 *
 * A property is defined by a getter method, and/or a setter method.
 * Properties can be accessed in the way like accessing normal object members.
 * Reading or writing a property will cause the invocation of the corresponding
 * getter or setter method, e.g.,
 * <code>
 * $a=$this->Text;     // equivalent to $a=$this->getText();
 * $this->Text='abc';  // equivalent to $this->setText('abc');
 * </code>
 * The signatures of getter and setter methods are as follows,
 * <code>
 * // getter, defines a readable property 'Text'
 * function getText() { ... }
 * // setter, defines a writable property 'Text', with $value being the value to be set to the property
 * function setText($value) { ... }
 * </code>
 * Property names are case-insensitive. It is recommended that they are written
 * in the format of concatenated words, with the first letter of each word
 * capitalized (e.g. DisplayMode, ItemStyle).
 *
 * Javascript Get and Set
 *
 * Since Prado 3.2 a new class of javascript-friendly properties have been introduced
 * to better deal with potential security problems like cross-site scripting issues.
 * All the data that gets sent clientside inside a javascript block is now encoded by default.
 * Sometimes there's the need to bypass this encoding and be able to send raw javascript code.
 * This new class of javascript-friendly properties are identified by their name
 * starting with 'js' (case insensitive):
 * <code>
 * // getter, defines a readable property 'Text'
 * function getJsText() { ... }
 * // setter, defines a writable property 'Text', with $value being the value to be set to the property
 * function setJsText(TJavaScriptLiteral $value) { ... }
 * </code>
 * Js-friendly properties can be accessed using both their Js-less name and their Js-enabled name:
 * <code>
 * // set some simple text as property value 
 * $component->Text = 'text';
 * // set some javascript code as property value
 * $component->JsText = 'raw javascript';
 * </code>
 * In the first case, the property value will automatically gets encoded when sent
 * clientside inside a javascript block.
 * In the second case, the property will be 'marked' as being a safe javascript
 * statement and will not be encoded when rendered inside a javascript block.
 * This special handling makes use of the {@link TJavaScriptLiteral} class. 
 *
 * Events
 *
 * An event is defined by the presence of a method whose name starts with 'on'.
 * The event name is the method name and is thus case-insensitive.
 * An event can be attached with one or several methods (called event handlers).
 * An event can be raised by calling {@link raiseEvent} method, upon which
 * the attached event handlers will be invoked automatically in the order they
 * are attached to the event. Event handlers must have the following signature,
 * <code>
 * function eventHandlerFuncName($sender,$param) { ... }
 * </code>
 * where $sender refers to the object who is responsible for the raising of the event,
 * and $param refers to a structure that may contain event-specific information.
 * To raise an event (assuming named as 'Click') of a component, use
 * <code>
 * $component->raiseEvent('OnClick');
 * $component->raiseEvent('OnClick', $this, $param);
 * </code>
 * To attach an event handler to an event, use one of the following ways,
 * <code>
 * $component->OnClick=$callback;  // or $component->OnClick->add($callback);
 * $component->attachEventHandler('OnClick',$callback);
 * </code>
 * The first two ways make use of the fact that $component->OnClick refers to
 * the event handler list {@link TPriorityList} for the 'OnClick' event.
 * The variable $callback contains the definition of the event handler that can
 * be either a string referring to a global function name, or an array whose
 * first element refers to an object and second element a method name/path that
 * is reachable by the object, e.g.
 * - 'buttonClicked' : buttonClicked($sender,$param);
 * - array($object,'buttonClicked') : $object->buttonClicked($sender,$param);
 * - array($object,'MainContent.SubmitButton.buttonClicked') :
 *   $object->MainContent->SubmitButton->buttonClicked($sender,$param);
 * 
 * @author Qiang Xue <qiang.xue@gmail.com>
 * 
 * With the addition of behaviors, a more expansive event model is needed.  There 
 * are two new event types (global and dynamic events) as well as a more comprehensive 
 * behavior model that includes class wide behaviors.
 *
 * A global event is defined by all events whose name starts with 'fx'.
 * The event name is potentially a method name and is thus case-insensitive. All 'fx' events 
 * are valid as the whole 'fx' event/method space is global in nature. Any object may patch into
 * any global event by defining that event as a method. Global events have priorities 
 * just like 'on' events; so as to be able to order the event execution. Due to the 
 * nature of all events which start with 'fx' being valid, in effect, every object 
 * has every 'fx' global event. It is simply an issue of tapping into the desired 
 * global event.
 *
 * A global event that starts with 'fx' can be called even if the object does not
 * implement the method of the global event.  A call to a non-existing 'fx' method
 * will, at minimal, function and return null.  If a method argument list has a first 
 * parameter, it will be returned instead of null.  This allows filtering and chaining.
 * 'fx' methods do not automatically install and uninstall. To install and uninstall an
 * object's global event listeners, call the object's {@link listen} and 
 * {@link unlisten} methods, respectively.  An object may auto-install its global event
 * during {@link __construct} by overriding {@link getAutoGlobalListen} and returning true.
 * 
 * As of PHP version 5.3, nulled objects without code references will still continue to persist
 * in the global event queue because {@link __destruct} is not automatically called.  In the common
 * __destruct method, if an object is listening to global events, then {@link unlisten} is called.
 * {@link unlisten} is required to be manually called before an object is
 * left without references if it is currently listening to any global events. This includes 
 * class wide behaviors.
 *
 * An object that contains a method that starts with 'fx' will have those functions 
 * automatically receive those events of the same name after {@link listen} is called on the object.
 *
 * An object may listen to a global event without defining an 'fx' method of the same name by 
 * adding an object method to the global event list.  For example
 * <code>
 * $component->fxGlobalCheck=$callback;  // or $component->OnClick->add($callback);
 * $component->attachEventHandler('fxGlobalCheck',array($object, 'someMethod'));
 * </code>
 *
 * Events between Objects and their behaviors, Dynamic Events
 *
 * An intra-object/behavior event is defined by methods that start with 'dy'.  Just as with 
 * 'fx' global events, every object has every dynamic event.  Any call to a method that
 * starts with 'dy' will be handled, regardless of whether it is implemented.  These 
 * events are for communicating with attached behaviors.
 * 
 * Dynamic events can be used in a variety of ways.  They can be used to tell behaviors
 * when a non-behavior method is called.  Dynamic events could be used as data filters.
 * They could also be used to specify when a piece of code is to be run, eg. should the 
 * loop process be performed on a particular piece of data.  In this way, some control
 * is handed to the behaviors over the process and/or data.
 * 
 * If there are no handlers for an 'fx' or 'dy' event, it will return the first
 * parameter of the argument list.  If there are no arguments, these events
 * will return null.  If there are handlers an 'fx' method will be called directly
 * within the object.  Global 'fx' events are triggered by calling {@link raiseEvent}.
 * For dynamic events where there are behaviors that respond to the dynamic events, a 
 * {@link TCallChain} is developed.  A call chain allows the behavior dynamic event
 * implementations to call further implementing behaviors within a chain.
 * 
 * If an object implements {@link IDynamicMethods}, all global and object dynamic 
 * events will be sent to {@link __dycall}.  In the case of global events, all 
 * global events will trigger this method.  In the case of behaviors, all undefined
 * dynamic events  which are called will be passed through to this method.
 *
 *
 * Behaviors
 *
 * There are two types of behaviors.  There are individual object behaviors and
 * there are class wide behaviors.  Class behaviors depend upon object behaviors.
 * 
 * When a new class implements {@link IBehavior} or {@link IClassBehavior} or
 * extends {@link TBehavior} or {@link TClassBehavior}, it may be added to an 
 * object by calling the object's {@link attachBehavior}.  The behaviors associated
 * name can then be used to {@link enableBehavior} or {@link disableBehavior} 
 * the specific behavior.
 *
 * All behaviors may be turned on and off via {@link enableBehaviors} and 
 * {@link disableBehaviors}, respectively.  To check if behaviors are on or off
 * a call to {@link getBehaviorsEnabled} will provide the variable.
 * 
 * Attaching and detaching whole sets of behaviors is done using 
 * {@link attachBehaviors} and {@link detachBehaviors}.  {@link clearBehaviors}
 * removes all of an object's behaviors.
 *
 * {@link asa} returns a behavior of a specific name.  {@link isa} is the
 * behavior inclusive function that acts as the PHP operator {@link instanceof}.
 * A behavior could provide the functionality of a specific class thus causing
 * the host object to act similarly to a completely different class.  A behavior 
 * would then implement {@link IInstanceCheck} to provide the identity of the 
 * different class.
 *
 * Class behaviors are similar to object behaviors except that the class behavior 
 * is the implementation for all instances of the class.  A class behavior
 * will have the object upon which is being called be prepended to the parameter
 * list.  This way the object is known across the class behavior implementation.
 *
 * Class behaviors are attached using {@link attachClassBehavior} and detached
 * using {@link detachClassBehavior}.  Class behaviors are important in that
 * they will be applied to all new instances of a particular class.  In this way
 * class behaviors become default behaviors to a new instances of a class in
 * {@link __construct}.  Detaching a class behavior will remove the behavior 
 * from the default set of behaviors created for an object when the object
 * is instanced.
 *
 * Class behaviors are also added to all existing instances via the global 'fx' 
 * event mechanism.  When a new class behavior is added, the event 
 * {@link fxAttachClassBehavior} is raised and all existing instances that are
 * listening to this global event (primarily after {@link listen} is called)
 * will have this new behavior attached.  A similar process is used when
 * detaching class behaviors.  Any objects listening to the global 'fx' event
 * {@link fxDetachClassBehavior} will have a class behavior removed.
 *
 * Dynamic Intra-Object Events
 *
 * Dynamic events start with 'dy'.  This mechanism is used to allow objects
 * to communicate with their behaviors directly.  The entire 'dy' event space
 * is valid.  All attached, enabled behaviors that implement a dynamic event 
 * are called when the host object calls the dynamic event.  If there is no 
 * implementation or behaviors, this returns null when no parameters are
 * supplied and will return the first parameter when there is at least one
 * parameter in the dynamic event.
 * <code>
 *	 null == $this->dyBehaviorEvent();
 *	 5 == $this->dyBehaviorEvent(5); //when no behaviors implement this dynamic event
 * </code>
 *
 * Dynamic events can be chained together within behaviors to allow for data 
 * filtering. Dynamic events are implemented within behaviors by defining the
 * event as a method.
 * <code>
 * class TObjectBehavior extends TBehavior {
 *     public function dyBehaviorEvent($param1, $callchain) {
 *			//Do something, eg:  $param1 += 13;
 *			return $callchain->dyBehaviorEvent($param1);
 *     }
 * }
 * </code>
 * This implementation of a behavior and dynamic event will flow through to the 
 * next behavior implementing the dynamic event.  The first parameter is always 
 * return when it is supplied.  Otherwise a dynamic event returns null.
 *
 * In the case of a class behavior, the object is also prepended to the dynamic
 * event.
 * <code>
 * class TObjectClassBehavior extends TClassBehavior {
 *     public function dyBehaviorEvent($hostobject, $param1, $callchain) {
 *			//Do something, eg:  $param1 += $hostobject->getNumber();
 *			return $callchain->dyBehaviorEvent($param1);
 *     }
 * }
 * </code>
 * When calling a dynamic event, only the parameters are passed.  The host object
 * and the call chain are built into the framework.
 *
 * Global Event and Dynamic event catching
 *
 * Given that all global 'fx' events and dynamic 'dy' events are valid and 
 * operational, there is a mechanism for catching events called that are not
 * implemented (similar to the built-in PHP method {@link __call}).  When
 * a dynamic or global event is called but a behavior does not implement it, 
 * yet desires to know when an undefined dynamic event is run, the behavior 
 * implements the interface {@link IDynamicMethods} and method {@link __dycall}.
 *
 * In the case of dynamic events, {@link __dycall} is supplied with the method 
 * name and its parameters.  When a global event is raised, via {@link raiseEvent},
 * the method is the event name and the parameters are supplied.
 *
 * When implemented, this catch-all mechanism is called for event global event event
 * when implemented outside of a behavior.  Within a behavior, it will also be called
 * when the object to which the behavior is attached calls any unimplemented dynamic 
 * event.  This is the fall-back mechanism for informing a class and/or behavior 
 * of when an global and/or undefined dynamic event is executed.
 * 
 * @author Brad Anderson <javalizard@mac.com>
 * @version $Id: TComponent.php 3212 2012-10-31 09:40:15Z ctrlaltca $
 * @package System
 * @since 3.0
 */
class TComponent
{
	/**
	 * @var array event handler lists
	 */
	private $_e=array();
	
	/**
	 * @var boolean if listening is enabled.  Automatically turned on or off in 
	 * constructor according to {@link getAutoGlobalListen}.  Default false, off
	 */
	private $_listeningenabled=false;
	
	/**
	 * @var array static registered global event handler lists
	 */
	private static $_ue=array();
	
	/**
	 * @var boolean if object behaviors are on or off.  default true, on
	 */
	private $_behaviorsenabled=true;

	/**
	 * @var TPriorityMap list of object behaviors
	 */
	private $_m=null;
	
	/**
	 * @var array static global class behaviors, these behaviors are added upon instantiation of a class
	 */
	private static $_um=array();
	
	
	/**
	 * @const string the name of the global {@link raiseEvent} listener
	 */
	const GLOBAL_RAISE_EVENT_LISTENER='fxGlobalListener';


	/**
	 * The common __construct
	 * If desired by the new object, this will auto install and listen to global event functions 
	 * as defined by the object via 'fx' methods. This also attaches any predefined behaviors.
	 * This function installs all class behaviors in a class hierarchy from the deepest subclass
	 * through each parent to the top most class, TComponent.
	 */
	public function __construct() {
		if($this->getAutoGlobalListen())
			$this->listen();
		
		$classes=array_reverse($this->getClassHierarchy(true));
		foreach($classes as $class) {
			if(isset(self::$_um[$class]))
				$this->attachBehaviors(self::$_um[$class]);
		}
	}
	
	
	/**
	 * Tells TComponent whether or not to automatically listen to global events.
	 * Defaults to false because PHP variable cleanup is affected if this is true.
	 * When unsetting a variable that is listening to global events, {@link unlisten}
	 * must explicitly be called when cleaning variables allocation or else the global
	 * event registry will contain references to the old object. This is true for PHP 5.4
	 * 
	 * Override this method by a subclass to change the setting.  When set to true, this
	 * will enable {@link __construct} to call {@link listen}.
	 *
	 * @return boolean whether or not to auto listen to global events during {@link __construct}, default false
	 */
	public function getAutoGlobalListen() {
		return false;
	}


	/**
	 * The common __destruct
	 * This unlistens from the global event routines if listening
	 *
	 * PHP 5.3 does not __destruct objects when they are nulled and thus unlisten must be
	 * called must be explicitly called.
	 */
	public function __destruct() {
		if($this->_listeningenabled)
			$this->unlisten();
	}
	
	
	/**
	 * This utility function is a private array filter method.  The array values 
	 * that start with 'fx' are filtered in.
	 */
	private function filter_prado_fx($name) {
		return strncasecmp($name,'fx',2)===0;
	}
	
	
	/**
	 * This returns an array of the class name and the names of all its parents.  The base object first, 
	 * {@link TComponent}, and the deepest subclass is last.
	 * @param boolean optional should the names be all lowercase true/false
	 * @return array array of strings being the class hierarchy of $this.
	 */
	public function getClassHierarchy($lowercase = false)
	{
		$class=get_class($this);
		$classes=array($class);
		while($class=get_parent_class($class)){array_unshift($classes,$class);}
		if($lowercase)
			return array_map('strtolower',$classes);
		return $classes;
	}
	
	
	/**
	 * This adds an object's fx event handlers into the global broadcaster to listen into any 
	 * broadcast global events called through {@link raiseEvent}
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyListen($globalEvents[, $chain]) {
	 * 		$this->listen(); //eg
	 * }
	 * </code>
	 * to be executed when listen is called.  All attached behaviors are notified through dyListen.
	 *
	 * @return numeric the number of global events that were registered to the global event registry
	 */
	public function listen() {
		if($this->_listeningenabled)
			return;
		
		$fx=array_filter(get_class_methods($this),array($this,'filter_prado_fx'));
		
		foreach($fx as $func)
			$this->attachEventHandler($func,array($this,$func));
		
		if(is_a($this,'IDynamicMethods')) {
			$this->attachEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER,array($this,'__dycall'));
			array_push($fx,TComponent::GLOBAL_RAISE_EVENT_LISTENER);
		}
		
		$this->_listeningenabled=true;
		
		$this->dyListen($fx);
		
		return count($fx);
	}
	
	/**
	 * this removes an object's fx events from the global broadcaster
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyUnlisten($globalEvents[, $chain]) {
	 * 		$this->behaviorUnlisten(); //eg
	 * }
	 * </code>
	 * to be executed when listen is called.  All attached behaviors are notified through dyUnlisten.
	 *
	 * @return numeric the number of global events that were unregistered from the global event registry
	 */
	public function unlisten() {
		if(!$this->_listeningenabled)
			return;
		
		$fx=array_filter(get_class_methods($this),array($this,'filter_prado_fx'));
			
		foreach($fx as $func)
			$this->detachEventHandler($func,array($this,$func));
			
		if(is_a($this,'IDynamicMethods')) {
			$this->detachEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER,array($this,'__dycall'));
			array_push($fx,TComponent::GLOBAL_RAISE_EVENT_LISTENER);
		}
		
		$this->_listeningenabled=false;
		
		$this->dyUnlisten($fx);
		
		return count($fx);
	}
	
	/**
	 * Gets the state of listening to global events
	 * @return boolean is Listening to global broadcast enabled
	 */
	public function getListeningToGlobalEvents()
	{
		return $this->_listeningenabled;
	}
	

	/**
	 * Calls a method.
	 * Do not call this method directly. This is a PHP magic method that we override
	 * to allow behaviors, dynamic events (intra-object/behavior events), 
	 * undefined dynamic and global events, and
	 * to allow using the following syntax to call a property setter or getter.
	 * <code>
	 * $this->getPropertyName($value); // if there's a $this->getjsPropertyName() method
	 * $this->setPropertyName($value); // if there's a $this->setjsPropertyName() method
	 * </code>
	 *
	 * Additional object behaviors override class behaviors.
	 * dynamic and global events do not fail even if they aren't implemented.
	 * Any intra-object/behavior dynamic events that are not implemented by the behavior
	 * return the first function paramater or null when no parameters are specified.
	 *
	 * @param string method name that doesn't exist and is being called on the object
	 * @param mixed method parameters
	 * @throws TInvalidOperationException If the property is not defined or read-only or
	 * 		method is undefined
	 * @return mixed result of the method call, or false if 'fx' or 'dy' function but 
	 *		is not found in the class, otherwise it runs
	 */
	public function __call($method, $args)
	{
		$getset=substr($method,0,3);
		if(($getset=='get')||($getset=='set'))
		{
			$propname=substr($method,3);
			$jsmethod=$getset.'js'.$propname;
			if(method_exists($this,$jsmethod))
			{
				if(count($args)>0)
					if($args[0]&&!($args[0] instanceof TJavaScriptString))
						$args[0]=new TJavaScriptString($args[0]);
				return call_user_func_array(array($this,$jsmethod),$args);
			}

			if (($getset=='set')&&method_exists($this,'getjs'.$propname))
				throw new TInvalidOperationException('component_property_readonly',get_class($this),$method);
		}
		
		if($this->_m!==null&&$this->_behaviorsenabled)
		{
			if(strncasecmp($method,'dy',2)===0)
			{
				$callchain=new TCallChain($method);
				foreach($this->_m->toArray() as $behavior)
				{
					if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&(method_exists($behavior,$method)||($behavior instanceof IDynamicMethods)))
					{
						$behavior_args=$args;
						if($behavior instanceof IClassBehavior)
							array_unshift($behavior_args,$this);
						$callchain->addCall(array($behavior,$method),$behavior_args);
					}
					
				}
				if($callchain->getCount()>0)
					return call_user_func_array(array($callchain,'call'),$args);
			}
			else
			{
				foreach($this->_m->toArray() as $behavior)
				{
					if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&method_exists($behavior,$method))
					{
						if($behavior instanceof IClassBehavior)
							array_unshift($args,$this);
						return call_user_func_array(array($behavior,$method),$args);
					}
				}
			}
		}
		
		if(strncasecmp($method,'dy',2)===0||strncasecmp($method,'fx',2)===0)
		{
			if($this instanceof IDynamicMethods)
				return $this->__dycall($method,$args);
			return isset($args[0])?$args[0]:null;
		}
		
		throw new TApplicationException('component_method_undefined',get_class($this),$method);
	}


	/**
	 * Returns a property value or an event handler list by property or event name.
	 * Do not call this method. This is a PHP magic method that we override
	 * to allow using the following syntax to read a property:
	 * <code>
	 * $value=$component->PropertyName;
	 * $value=$component->jsPropertyName; // return JavaScript literal
	 * </code>
	 * and to obtain the event handler list for an event,
	 * <code>
	 * $eventHandlerList=$component->EventName;
	 * </code>
	 * This will also return the global event handler list when specifing an 'fx'
	 * event,
	 * <code>
	 * $globalEventHandlerList=$component->fxEventName;
	 * </code>
	 * When behaviors are enabled, this will return the behavior of a specific
	 * name, a property of a behavior, or an object 'on' event defined by the behavior.
	 * @param string the property name or the event name
	 * @return mixed the property value or the event handler list as {@link TPriorityList}
	 * @throws TInvalidOperationException if the property/event is not defined.
	 */
	public function __get($name)
	{
		if(method_exists($this,$getter='get'.$name))
		{
			// getting a property
			return $this->$getter();
		}
		else if(method_exists($this,$jsgetter='getjs'.$name))
		{
			// getting a javascript property
			return (string)$this->$jsgetter();
		}
		else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
		{
			// getting an event (handler list)
			$name=strtolower($name);
			if(!isset($this->_e[$name]))
				$this->_e[$name]=new TPriorityList;
			return $this->_e[$name];
		}
		else if(strncasecmp($name,'fx',2)===0)
		{
			// getting a global event (handler list)
			$name=strtolower($name);
			if(!isset(self::$_ue[$name]))
				self::$_ue[$name]=new TPriorityList;
			return self::$_ue[$name];
		}
		else if($this->_behaviorsenabled)
		{
			// getting a behavior property/event (handler list)
			if(isset($this->_m[$name]))
				return $this->_m[$name];
			else if($this->_m!==null)
			{
				foreach($this->_m->toArray() as $behavior)
				{
					if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&
						(property_exists($behavior,$name)||$behavior->canGetProperty($name)||$behavior->hasEvent($name)))
						return $behavior->$name;
				}
			}
		}
		throw new TInvalidOperationException('component_property_undefined',get_class($this),$name);
	}

	/**
	 * Sets value of a component property.
	 * Do not call this method. This is a PHP magic method that we override
	 * to allow using the following syntax to set a property or attach an event handler.
	 * <code>
	 * $this->PropertyName=$value;
	 * $this->jsPropertyName=$value; // $value will be treated as a JavaScript literal
	 * $this->EventName=$handler;
	 * $this->fxEventName=$handler; //global event listener
	 * </code>
	 * When behaviors are enabled, this will also set a behaviors properties and events.
	 * @param string the property name or event name
	 * @param mixed the property value or event handler
	 * @throws TInvalidOperationException If the property is not defined or read-only.
	 */
	public function __set($name,$value)
	{
		if(method_exists($this,$setter='set'.$name))
		{
			if(strncasecmp($name,'js',2)===0&&$value&&!($value instanceof TJavaScriptLiteral))
				$value = new TJavaScriptLiteral($value);
			return $this->$setter($value);
		}
		else if(method_exists($this,$jssetter='setjs'.$name))
		{
			if($value&&!($value instanceof TJavaScriptString))
				$value=new TJavaScriptString($value);
			return $this->$jssetter($value);
		}
		else if((strncasecmp($name,'on',2)===0&&method_exists($this,$name))||strncasecmp($name,'fx',2)===0)
		{
			return $this->attachEventHandler($name,$value);
		}
		else if($this->_m!==null&&$this->_m->getCount()>0&&$this->_behaviorsenabled)
		{
			$sets=0;
			foreach($this->_m->toArray() as $behavior)
			{
				if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&
					(property_exists($behavior,$name)||$behavior->canSetProperty($name)||$behavior->hasEvent($name))) {
					$behavior->$name=$value;
					$sets++;
				}
			}
			if($sets)return $value;
			
		}
		
		if(method_exists($this,'get'.$name)||method_exists($this,'getjs'.$name))
		{
			throw new TInvalidOperationException('component_property_readonly',get_class($this),$name);
		}
		else
		{
			throw new TInvalidOperationException('component_property_undefined',get_class($this),$name);
		}
	}

	/**
	 * Checks if a property value is null, there are no events in the object
	 * event list or global event list registered under the name, and, if 
	 * behaviors are enabled, 
	 * Do not call this method. This is a PHP magic method that we override
	 * to allow using isset() to detect if a component property is set or not.
	 * This also works for global events.  When behaviors are enabled, it 
	 * will check for a behavior of the specified name, and also check 
	 * the behavior for events and properties.
	 * @param string the property name or the event name
	 * @since 3.2.1
	 */
	public function __isset($name)
	{
		if(method_exists($this,$getter='get'.$name))
			return $this->$getter()!==null;
		else if(method_exists($this,$jsgetter='getjs'.$name))
			return $this->$jsgetter()!==null;
		else if(strncasecmp($name,'on',2)===0&&method_exists($this,$name))
		{
			$name=strtolower($name);
			return isset($this->_e[$name])&&$this->_e[$name]->getCount();
		}
		else if(strncasecmp($name,'fx',2)===0)
		{
			$name=strtolower($name);
			return isset(self::$_ue[$name])&&self::$_ue[$name]->getCount();
		}
		else if($this->_m!==null&&$this->_m->getCount()>0&&$this->_behaviorsenabled)
		{
			if(isset($this->_m[$name]))
				return true;
			foreach($this->_m->toArray() as $behavior)
			{
				if((!($behavior instanceof IBehavior)||$behavior->getEnabled()))
					return isset($behavior->$name);
			}
			
		}
		else
			return false;
	}

	/**
	 * Sets a component property to be null.  Clears the object or global
	 * events. When enabled, loops through all behaviors and unsets the 
	 * property or event.
	 * Do not call this method. This is a PHP magic method that we override
	 * to allow using unset() to set a component property to be null.
	 * @param string the property name or the event name
	 * @throws TInvalidOperationException if the property is read only.
	 * @since 3.2.1
	 */
	public function __unset($name)
	{
		if(method_exists($this,$setter='set'.$name))
			$this->$setter(null);
		else if(method_exists($this,$jssetter='setjs'.$name))
			$this->$jssetter(null);
		else if(strncasecmp($name,'on',2)===0&&method_exists($this,$name))
			$this->_e[strtolower($name)]->clear();
		else if(strncasecmp($name,'fx',2)===0)
			$this->getEventHandlers($name)->remove(array($this, $name));
		else if($this->_m!==null&&$this->_m->getCount()>0&&$this->_behaviorsenabled)
		{
			if(isset($this->_m[$name]))
				$this->detachBehavior($name);
			else {
				$unset=0;
				foreach($this->_m->toArray() as $behavior)
				{
					if((!($behavior instanceof IBehavior)||$behavior->getEnabled())) {
						unset($behavior->$name);
						$unset++;
					}
				}
				if(!$unset&&method_exists($this,'get'.$name))
					throw new TInvalidOperationException('component_property_readonly',get_class($this),$name);
			}
		} else if(method_exists($this,'get'.$name))
			throw new TInvalidOperationException('component_property_readonly',get_class($this),$name);
	}

	/**
	 * Determines whether a property is defined.
	 * A property is defined if there is a getter or setter method
	 * defined in the class. Note, property names are case-insensitive.
	 * @param string the property name
	 * @return boolean whether the property is defined
	 */
	public function hasProperty($name)
	{
		return $this->canGetProperty($name)||$this->canSetProperty($name);
	}

	/**
	 * Determines whether a property can be read.
	 * A property can be read if the class has a getter method
	 * for the property name. Note, property name is case-insensitive.
	 * This also checks for getjs.  When enabled, it loops through all
	 * active behaviors for the get property when undefined by the object.
	 * @param string the property name
	 * @return boolean whether the property can be read
	 */
	public function canGetProperty($name)
	{
		if(method_exists($this,'get'.$name)||method_exists($this,'getjs'.$name))
			return true;
		else if($this->_m!==null&&$this->_behaviorsenabled)
		{
			foreach($this->_m->toArray() as $behavior)
			{
				if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->canGetProperty($name))
					return true;
			}
		}
		return false;
	}

	/**
	 * Determines whether a property can be set.
	 * A property can be written if the class has a setter method
	 * for the property name. Note, property name is case-insensitive.
	 * This also checks for setjs.  When enabled, it loops through all
	 * active behaviors for the set property when undefined by the object.
	 * @param string the property name
	 * @return boolean whether the property can be written
	 */
	public function canSetProperty($name)
	{
		if(method_exists($this,'set'.$name)||method_exists($this,'setjs'.$name))
			return true;
		else if($this->_m!==null&&$this->_behaviorsenabled)
		{
			foreach($this->_m->toArray() as $behavior)
			{
				if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->canSetProperty($name))
					return true;
			}
		}
		return false;
	}

	/**
	 * Evaluates a property path.
	 * A property path is a sequence of property names concatenated by '.' character.
	 * For example, 'Parent.Page' refers to the 'Page' property of the component's
	 * 'Parent' property value (which should be a component also).
	 * When a property is not defined by an object, this also loops through all
	 * active behaviors of the object.
	 * @param string property path
	 * @return mixed the property path value
	 */
	public function getSubProperty($path)
	{
		$object=$this;
		foreach(explode('.',$path) as $property)
			$object=$object->$property;
		return $object;
	}

	/**
	 * Sets a value to a property path.
	 * A property path is a sequence of property names concatenated by '.' character.
	 * For example, 'Parent.Page' refers to the 'Page' property of the component's
	 * 'Parent' property value (which should be a component also).
	 * When a property is not defined by an object, this also loops through all
	 * active behaviors of the object.
	 * @param string property path
	 * @param mixed the property path value
	 */
	public function setSubProperty($path,$value)
	{
		$object=$this;
		if(($pos=strrpos($path,'.'))===false)
			$property=$path;
		else
		{
			$object=$this->getSubProperty(substr($path,0,$pos));
			$property=substr($path,$pos+1);
		}
		$object->$property=$value;
	}

	/**
	 * Determines whether an event is defined.
	 * An event is defined if the class has a method whose name is the event name 
	 * prefixed with 'on', 'fx', or 'dy'.
	 * Every object responds to every 'fx' and 'dy' event as they are in a universally 
	 * accepted event space.  'on' event must be declared by the object.
	 * When enabled, this will loop through all active behaviors for 'on' events
	 * defined by the behavior.
	 * Note, event name is case-insensitive.
	 * @param string the event name
	 * @return boolean
	 */
	public function hasEvent($name)
	{
		if((strncasecmp($name,'on',2)===0&&method_exists($this,$name))||strncasecmp($name,'fx',2)===0||strncasecmp($name,'dy',2)===0)
			return true;
			
		else if($this->_m!==null&&$this->_behaviorsenabled)
		{
			foreach($this->_m->toArray() as $behavior)
			{
				if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->hasEvent($name))
					return true;
			}
		}
		return false;
	}

	/**
	 * Checks if an event has any handlers.  This function also checks through all 
	 * the behaviors for 'on' events when behaviors are enabled.
	 * 'dy' dynamic events are not handled by this function.  
	 * @param string the event name
	 * @return boolean whether an event has been attached one or several handlers
	 */
	public function hasEventHandler($name)
	{
		$name=strtolower($name);
		if(strncasecmp($name,'fx',2)===0)
			return isset(self::$_ue[$name])&&self::$_ue[$name]->getCount()>0;
		else
		{
			if(isset($this->_e[$name])&&$this->_e[$name]->getCount()>0)
				return true;
			else if($this->_m!==null&&$this->_behaviorsenabled) {
				foreach($this->_m->toArray() as $behavior)
				{
					if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->hasEventHandler($name))
						return true;
				}
			}
		}
		return false;
	}

	/**
	 * Returns the list of attached event handlers for an 'on' or 'fx' event.   This function also 
	 * checks through all the behaviors for 'on' event lists when behaviors are enabled.
	 * @return TPriorityList list of attached event handlers for an event
	 * @throws TInvalidOperationException if the event is not defined
	 */
	public function getEventHandlers($name)
	{
		if(strncasecmp($name,'on',2)===0&&method_exists($this,$name))
		{
			$name=strtolower($name);
			if(!isset($this->_e[$name]))
				$this->_e[$name]=new TPriorityList;
			return $this->_e[$name];
		}
		else if(strncasecmp($name,'fx',2)===0)
		{
			$name=strtolower($name);
			if(!isset(self::$_ue[$name]))
				self::$_ue[$name]=new TPriorityList;
			return self::$_ue[$name];
		}
		else if($this->_m!==null&&$this->_behaviorsenabled)
		{
			foreach($this->_m->toArray() as $behavior)
			{
				if((!($behavior instanceof IBehavior)||$behavior->getEnabled())&&$behavior->hasEvent($name))
					return $behavior->getEventHandlers($name);
			}
		}
		throw new TInvalidOperationException('component_event_undefined',get_class($this),$name);
	}

	/**
	 * Attaches an event handler to an event.
	 *
	 * The handler must be a valid PHP callback, i.e., a string referring to
	 * a global function name, or an array containing two elements with
	 * the first element being an object and the second element a method name
	 * of the object. In Prado, you can also use method path to refer to
	 * an event handler. For example, array($object,'Parent.buttonClicked')
	 * uses a method path that refers to the method $object->Parent->buttonClicked(...).
	 *
	 * The event handler must be of the following signature,
	 * <code>
	 * function handlerName($sender, $param) {}
	 * function handlerName($sender, $param, $name) {}
	 * </code>
	 * where $sender represents the object that raises the event,
	 * and $param is the event parameter. $name refers to the event name 
	 * being handled.
	 *
	 * This is a convenient method to add an event handler.
	 * It is equivalent to {@link getEventHandlers}($name)->add($handler).
	 * For complete management of event handlers, use {@link getEventHandlers}
	 * to get the event handler list first, and then do various
	 * {@link TPriorityList} operations to append, insert or remove
	 * event handlers. You may also do these operations like
	 * getting and setting properties, e.g.,
	 * <code>
	 * $component->OnClick[]=array($object,'buttonClicked');
	 * $component->OnClick->insertAt(0,array($object,'buttonClicked'));
	 * </code>
	 * which are equivalent to the following
	 * <code>
	 * $component->getEventHandlers('OnClick')->add(array($object,'buttonClicked'));
	 * $component->getEventHandlers('OnClick')->insertAt(0,array($object,'buttonClicked'));
	 * </code>
	 *
	 * Due to the nature of {@link getEventHandlers}, any active behaviors defining
	 * new 'on' events, this method will pass through to the behavior transparently.
	 *
	 * @param string the event name
	 * @param callback the event handler
	 * @param numeric|null the priority of the handler, defaults to null which translates into the 
	 * default priority of 10.0 within {@link TPriorityList}
	 * @throws TInvalidOperationException if the event does not exist
	 */
	public function attachEventHandler($name,$handler,$priority=null)
	{
		$this->getEventHandlers($name)->add($handler,$priority);
	}

	/**
	 * Detaches an existing event handler.
	 * This method is the opposite of {@link attachEventHandler}.  It will detach 
	 * any 'on' events definedb by an objects active behaviors as well.
	 * @param string event name
	 * @param callback the event handler to be removed
	 * @param numeric|false|null the priority of the handler, defaults to false which translates 
	 * to an item of any priority within {@link TPriorityList}; null means the default priority
	 * @return boolean if the removal is successful
	 */
	public function detachEventHandler($name,$handler,$priority=false)
	{
		if($this->hasEventHandler($name))
		{
			try
			{
				$this->getEventHandlers($name)->remove($handler,$priority);
				return true;
			}
			catch(Exception $e)
			{
			}
		}
		return false;
	}

	/**
	 * Raises an event.  This raises both inter-object 'on' events and global 'fx' events.
	 * This method represents the happening of an event and will
	 * invoke all attached event handlers for the event in {@link TPriorityList} order.
	 * This method does not handle intra-object/behavior dynamic 'dy' events.
	 * 
	 * There are ways to handle event responses.  By defailt {@link EVENT_RESULT_FILTER}, 
	 * all event responses are stored in an array, filtered for null responses, and returned.  
	 * If {@link EVENT_RESULT_ALL} is specified, all returned results will be stored along 
	 * with the sender and param in an array
	 * <code>
	 * 		$result[] = array('sender'=>$sender,'param'=>$param,'response'=>$response);
	 * </code>
	 *
	 * If {@link EVENT_RESULT_FEED_FORWARD} is specified, then each handler result is then
	 * fed forward as the parameters for the next event.  This allows for events to filter data
	 * directly by affecting the event parameters
	 *
	 * If a callable function is set in the response type or the post function filter is specified then the 
	 * result of each called event handler is post processed by the callable function.  Used in
	 * combination with {@link EVENT_RESULT_FEED_FORWARD}, any event (and its result) can be chained.
	 *
	 * When raising a global 'fx' event, registered handlers in the global event list for 
	 * {@link GLOBAL_RAISE_EVENT_LISTENER} are always added into the set of event handlers.  In this way,
	 * these global events are always raised for every global 'fx' event.  The registered handlers for global 
	 * raiseEvent events have priorities.  Any registered global raiseEvent event handlers with a priority less than zero 
	 * are added before the main event handlers being raised and any registered global raiseEvent event handlers
	 * with a priority equal or greater than zero are added after the main event handlers being raised.  In this way
	 * all {@link GLOBAL_RAISE_EVENT_LISTENER} handlers are always called for every raised 'fx' event.
	 *
	 * Behaviors may implement the following functions:
	 * <code>
	 *	public function dyPreRaiseEvent($name,$sender,$param,$responsetype,$postfunction[, $chain]) {
	 *  	return $name; //eg, the event name may be filtered/changed
	 *  }
	 *	public function dyIntraRaiseEventTestHandler($handler,$sender,$param,$name[, $chain]) {
	 *  	return true; //should this particular handler be executed?  true/false
	 *  }
	 *  public function dyIntraRaiseEventPostHandler($name,$sender,$param,$handler,$response[, $chain]) {
	 *		//contains the per handler response
	 *  }
	 *  public function dyPostRaiseEvent($responses,$name,$sender,$param,$responsetype,$postfunction[, $chain]) {
	 *		return $responses;
	 *  }
	 * </code>
	 * to be executed when raiseEvent is called.  The 'intra' dynamic events are called per handler in
	 * the handler loop.
	 *
	 * dyPreRaiseEvent has the effect of being able to change the event being raised.  This intra
	 * object/behavior event returns the name of the desired event to be raised.  It will pass through
	 * if no dynamic event is specified, or if the original event name is returned.
	 * dyIntraRaiseEventTestHandler returns true or false as to whether a specific handler should be 
	 * called for a specific raised event (and associated event arguments)
	 * dyIntraRaiseEventPostHandler does not return anything.  This allows behaviors to access the results
	 * of an event handler in the per handler loop.
	 * dyPostRaiseEvent returns the responses.  This allows for any post processing of the event
	 * results from the sum of all event handlers
	 *
	 * When handling a catch-all {@link __dycall}, the method name is the name of the event 
	 * and the parameters are the sender, the param, and then the name of the event.
	 * 
	 * @param string the event name
	 * @param mixed the event sender object
	 * @param TEventParameter the event parameter
	 * @param numeric how the results of the event are tabulated.  default: {@link EVENT_RESULT_FILTER}  The default filters out
	 *		null responses. optional
	 * @param function any per handler filtering of the response result needed is passed through 
	 *		this if not null. default: null.  optional
	 * @return mixed the results of the event
	 * @throws TInvalidOperationException if the event is undefined
	 * @throws TInvalidDataValueException If an event handler is invalid
	 */
	public function raiseEvent($name,$sender,$param,$responsetype=null,$postfunction=null)
	{
		$p=$param;
		if(is_callable($responsetype))
		{
			$postfunction=$responsetype;
			$responsetype=null;
		}
		
		if($responsetype===null)
			$responsetype=TEventResults::EVENT_RESULT_FILTER;
		
		$name=strtolower($name);
		$responses=array();
		
		$name=$this->dyPreRaiseEvent($name,$sender,$param,$responsetype,$postfunction);
		
		if($this->hasEventHandler($name)||$this->hasEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER))
		{
			$handlers=$this->getEventHandlers($name);
			$handlerArray=$handlers->toArray();
			if(strncasecmp($name,'fx',2)===0&&$this->hasEventHandler(TComponent::GLOBAL_RAISE_EVENT_LISTENER))
			{
				$globalhandlers=$this->getEventHandlers(TComponent::GLOBAL_RAISE_EVENT_LISTENER);
				$handlerArray=array_merge($globalhandlers->toArrayBelowPriority(0),$handlerArray,$globalhandlers->toArrayAbovePriority(0));
			}
			$response=null;
			foreach($handlerArray as $handler)
			{
				if($this->dyIntraRaiseEventTestHandler($handler,$sender,$param,$name)===false)
					continue;
				
				if(is_string($handler))
				{
					if(($pos=strrpos($handler,'.'))!==false)
					{
						$object=$this->getSubProperty(substr($handler,0,$pos));
						$method=substr($handler,$pos+1);
						if(method_exists($object,$method)||strncasecmp($method,'dy',2)===0||strncasecmp($method,'fx',2)===0)
						{
							if($method=='__dycall')
								$response=$object->__dycall($name,array($sender,$param,$name));
							else
								$response=$object->$method($sender,$param,$name);
						}
						else
							throw new TInvalidDataValueException('component_eventhandler_invalid',get_class($this),$name,$handler);
					}
					else
						$response=call_user_func($handler,$sender,$param,$name);
				}
				else if(is_callable($handler,true))
				{
					list($object,$method)=$handler;
					if(is_string($object))
						$response=call_user_func($handler,$sender,$param,$name);
					else
					{
						if(($pos=strrpos($method,'.'))!==false)
						{
							$object=$this->getSubProperty(substr($method,0,$pos));
							$method=substr($method,$pos+1);
						}
						if(method_exists($object,$method)||strncasecmp($method,'dy',2)===0||strncasecmp($method,'fx',2)===0)
						{
							if($method=='__dycall')
								$response=$object->__dycall($name,array($sender,$param,$name));
							else
								$response=$object->$method($sender,$param,$name);
						}
						else
							throw new TInvalidDataValueException('component_eventhandler_invalid',get_class($this),$name,$handler[1]);
					}
				}
				else
					throw new TInvalidDataValueException('component_eventhandler_invalid',get_class($this),$name,gettype($handler));
				
				$this->dyIntraRaiseEventPostHandler($name,$sender,$param,$handler,$response);
				
				if($postfunction)
					$response=call_user_func_array($postfunction,array($sender,$param,$this,$response));
				
				if($responsetype&TEventResults::EVENT_RESULT_ALL)
					$responses[]=array('sender'=>$sender,'param'=>$param,'response'=>$response);
				else
					$responses[]=$response;
				
				if($response!==null&&($responsetype&TEventResults::EVENT_RESULT_FEED_FORWARD))
					$param=$response;
				
			}
		}
		else if(strncasecmp($name,'on',2)===0&&!$this->hasEvent($name))
			throw new TInvalidOperationException('component_event_undefined',get_class($this),$name);
		
		if($responsetype&TEventResults::EVENT_RESULT_FILTER)
			$responses=array_filter($responses);
			
		$responses=$this->dyPostRaiseEvent($responses,$name,$sender,$param,$responsetype,$postfunction);
		
		return $responses;
	}

	/**
	 * Evaluates a PHP expression in the context of this control.
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyEvaluateExpressionFilter($expression, $chain) {
	 * 		return $chain->dyEvaluateExpressionFilter(str_replace('foo', 'bar', $expression)); //example
	 * }
	 * </code>
	 * to be executed when evaluateExpression is called.  All attached behaviors are notified through 
	 * dyEvaluateExpressionFilter.  The chaining is important in this function due to the filtering
	 * pass-through effect.
	 *
	 * @param string PHP expression
	 * @return mixed the expression result
	 * @throws TInvalidOperationException if the expression is invalid
	 */
	public function evaluateExpression($expression)
	{
		$expression=$this->dyEvaluateExpressionFilter($expression);
		try
		{
			if(eval("\$result=$expression;")===false)
				throw new Exception('');
			return $result;
		}
		catch(Exception $e)
		{
			throw new TInvalidOperationException('component_expression_invalid',get_class($this),$expression,$e->getMessage());
		}
	}

	/**
	 * Evaluates a list of PHP statements.
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyEvaluateStatementsFilter($statements, $chain) {
	 * 		return $chain->dyEvaluateStatementsFilter(str_replace('foo', 'bar', $statements)); //example
	 * }
	 * </code>
	 * to be executed when evaluateStatements is called.  All attached behaviors are notified through 
	 * dyEvaluateStatementsFilter.  The chaining is important in this function due to the filtering
	 * pass-through effect.
	 *
	 * @param string PHP statements
	 * @return string content echoed or printed by the PHP statements
	 * @throws TInvalidOperationException if the statements are invalid
	 */
	public function evaluateStatements($statements)
	{
		$statements=$this->dyEvaluateStatementsFilter($statements);
		try
		{
			ob_start();
			if(eval($statements)===false)
				throw new Exception('');
			$content=ob_get_contents();
			ob_end_clean();
			return $content;
		}
		catch(Exception $e)
		{
			throw new TInvalidOperationException('component_statements_invalid',get_class($this),$statements,$e->getMessage());
		}
	}

	/**
	 * This method is invoked after the component is instantiated by a template.
	 * When this method is invoked, the component's properties have been initialized.
	 * The default implementation of this method will invoke
	 * the potential parent component's {@link addParsedObject}.
	 * This method can be overridden.
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyCreatedOnTemplate($parent, $chain) {
	 * 		return $chain->dyCreatedOnTemplate($parent); //example
	 *  }
	 * </code>
	 * to be executed when createdOnTemplate is called.  All attached behaviors are notified through 
	 * dyCreatedOnTemplate.
	 *
	 * @param TComponent potential parent of this control
	 * @see addParsedObject
	 */
	public function createdOnTemplate($parent)
	{
		$parent=$this->dyCreatedOnTemplate($parent);
		$parent->addParsedObject($this);
	}

	/**
	 * Processes an object that is created during parsing template.
	 * The object can be either a component or a static text string.
	 * This method can be overridden to customize the handling of newly created objects in template.
	 * Only framework developers and control developers should use this method.
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyAddParsedObject($object[, $chain]) {
	 *  }
	 * </code>
	 * to be executed when addParsedObject is called.  All attached behaviors are notified through 
	 * dyAddParsedObject.
	 *
	 * @param string|TComponent text string or component parsed and instantiated in template
	 * @see createdOnTemplate
	 */
	public function addParsedObject($object)
	{
		$this->dyAddParsedObject($object);
	}
	
	
	/**
	 *	This is the method registered for all instanced objects should a class behavior be added after 
	 * the class is instanced.  Only when the class to which the behavior is being added is in this
	 * object's class hierarchy, via {@link getClassHierarchy}, is the behavior added to this instance.
	 * @param $sender the application
	 * @param $param TClassBehaviorEventParameter
	 * @since 3.2.1
	 */
	public function fxAttachClassBehavior($sender,$param) {
		if(in_array($param->getClass(),$this->getClassHierarchy(true)))
			return $this->attachBehavior($param->getName(),$param->getBehavior(),$param->getPriority());
	}
	
	
	/**
	 *	This is the method registered for all instanced objects should a class behavior be removed after 
	 * the class is instanced.  Only when the class to which the behavior is being added is in this
	 * object's class hierarchy, via {@link getClassHierarchy}, is the behavior removed from this instance.
	 * @param $sender the application
	 * @param $param TClassBehaviorEventParameter
	 * @since 3.2.1
	 */
	public function fxDetachClassBehavior($sender,$param) {
		if(in_array($param->getClass(),$this->getClassHierarchy(true)))
			return $this->detachBehavior($param->getName(),$param->getPriority());
	}
	
	
	/**
	 *	This will add a class behavior to all classes instanced (that are listening) and future newly instanced objects.  
	 * This registers the behavior for future instances and pushes the changes to all the instances that are listening as well. 
	 * The universal class behaviors are stored in an inverted stack with the latest class behavior being at the first position in the array.
	 * This is done so class behaviors are added last first.
	 * @param string name the key of the class behavior
	 * @param object|string class behavior or name of the object behavior per instance
	 * @param string|class string of class or class on which to attach this behavior.  Defaults to null which will error
	 *	but more important, if this is on PHP 5.3 it will use Late Static Binding to derive the class 
	 * it should extend.
	 * <code>
	 * TPanel::attachClassBehavior('javascripts', (new TJsPanelBehavior())->init($this));
	 * </code>
	 * @param numeric|null priority of behavior, default: null the default priority of the {@link TPriorityList}  Optional.
	 * @throws TInvalidOperationException if the class behavior is being added to a {@link TComponent}; due to recursion.
	 * @throws TInvalidOperationException if the class behavior is already defined
	 * @since 3.2.1
	 */
	public static function attachClassBehavior($name,$behavior,$class=null,$priority=null) {
		if(!$class&&function_exists('get_called_class'))
			$class=get_called_class();
		if(!$class)
			throw new TInvalidOperationException('component_no_class_provided_nor_late_binding');
		
		if(!is_string($name))
			$name=get_class($name);
		$class=strtolower($class);
		if($class==='tcomponent')
			throw new TInvalidOperationException('component_no_tcomponent_class_behaviors');
		if(empty(self::$_um[$class]))
			self::$_um[$class]=array();
		if(isset(self::$_um[$class][$name]))
			throw new TInvalidOperationException('component_class_behavior_defined',$class,$name);
		$param=new TClassBehaviorEventParameter($class,$name,$behavior,$priority);
		self::$_um[$class]=array($name=>$param)+self::$_um[$class];
		$behaviorObject=is_string($behavior)?new $behavior:$behavior;
		return $behaviorObject->raiseEvent('fxAttachClassBehavior',null,$param);
	}
	
	
	/**
	 *	This will remove a behavior from a class.  It unregisters it from future instances and
	 * pulls the changes from all the instances that are listening as well.
	 * PHP 5.3 uses Late Static Binding to derive the static class upon which this method is called.
	 * @param $name the key of the class behavior
	 * @param $class string class on which to attach this behavior.  Defaults to null.  
	 * @param $priority numeric|null|false priority.  false is any priority, null is default 
	 *		{@link TPriorityList} priority, and numeric is a specific priority.  
	 * @throws Exception if the the class cannot be derived from Late Static Binding and is not
	 * not supplied as a parameter.
	 * @since 3.2.1
	 */
	public static function detachClassBehavior($name,$class=null,$priority=false) {
		if(!$class&&function_exists('get_called_class'))
			$class=get_called_class();
		if(!$class)
			throw new TInvalidOperationException('component_no_class_provided_nor_late_binding');
		
		$class=strtolower($class);
		if(!is_string($name))
			$name=get_class($name);
		if(empty(self::$_um[$class])||!isset(self::$_um[$class][$name]))
			return false;
		$param=self::$_um[$class][$name];
		$behavior=$param->getBehavior();
		unset(self::$_um[$class][$name]);
		$behaviorObject=is_string($behavior)?new $behavior:$behavior;
		return $behaviorObject->raiseEvent('fxDetachClassBehavior',null,$param);
	}

	/**
	 * Returns the named behavior object.
	 * The name 'asa' stands for 'as a'.
	 * @param string the behavior name
	 * @return IBehavior the behavior object, or null if the behavior does not exist
	 * @since 3.2.1
	 */
	public function asa($behaviorname)
	{
		return isset($this->_m[$behaviorname])?$this->_m[$behaviorname]:null;
	}

	/**
	 * Returns whether or not the object or any of the behaviors are of a particular class.
	 * The name 'isa' stands for 'is a'.  This first checks if $this is an instanceof the class.
	 * It then checks each Behavior.  If a behavior implements {@link IInstanceCheck},
	 * then the behavior can determine what it is an instanceof.  If this behavior function returns true,
	 * then this method returns true.  If the behavior instance checking function returns false,
	 * then no further checking is performed as it is assumed to be correct.
	 * 
	 * If the behavior instance check function returns nothing or null or the behavior 
	 * doesn't implement the {@link IInstanceCheck} interface, then the default instanceof occurs.
	 * The default isa behavior is to check if the behavior is an instanceof the class.
	 *
	 * The behavior {@link IInstanceCheck} is to allow a behavior to have the host object
	 * act as a completely different object.
	 *
	 * @param class or string
	 * @return boolean whether or not the object or a behavior is an instance of a particular class
	 * @since 3.2.1
	 */
	public function isa($class)
	{
		if($this instanceof $class)
			return true;
		if($this->_m!==null&&$this->_behaviorsenabled)
			foreach($this->_m->toArray() as $behavior){
				if(($behavior instanceof IBehavior)&&!$behavior->getEnabled())
					continue;
				
				$check = null;
				if(($behavior->isa('IInstanceCheck'))&&$check=$behavior->isinstanceof($class,$this))
					return true;
				if($check===null&&($behavior->isa($class)))
					return true;
			}
		return false;
	}

	/**
	 * Attaches a list of behaviors to the component.
	 * Each behavior is indexed by its name and should be an instance of
	 * {@link IBehavior}, a string specifying the behavior class, or a
	 * {@link TClassBehaviorEventParameter}.
	 * @param array list of behaviors to be attached to the component
	 * @since 3.2.1
	 */
	public function attachBehaviors($behaviors)
	{
		foreach($behaviors as $name=>$behavior)
			if($behavior instanceof TClassBehaviorEventParameter)
				$this->attachBehavior($behavior->getName(),$behavior->getBehavior(),$behavior->getPriority());
			else
				$this->attachBehavior($name,$behavior);
	}

	/**
	 * Detaches select behaviors from the component.
	 * Each behavior is indexed by its name and should be an instance of
	 * {@link IBehavior}, a string specifying the behavior class, or a
	 * {@link TClassBehaviorEventParameter}.
	 * @param array list of behaviors to be detached from the component
	 * @since 3.2.1
	 */
	public function detachBehaviors($behaviors)
	{
		if($this->_m!==null)
		{
			foreach($behaviors as $name=>$behavior)
				if($behavior instanceof TClassBehaviorEventParameter)
					$this->detachBehavior($behavior->getName(),$behavior->getPriority());
				else
					$this->detachBehavior(is_string($behavior)?$behavior:$name);
		}
	}

	/**
	 * Detaches all behaviors from the component.
	 * @since 3.2.1
	 */
	public function clearBehaviors()
	{
		if($this->_m!==null)
		{
			foreach($this->_m->toArray() as $name=>$behavior)
				$this->detachBehavior($name);
			$this->_m=null;
		}
	}

	/**
	 * Attaches a behavior to this component.
	 * This method will create the behavior object based on the given
	 * configuration. After that, the behavior object will be initialized
	 * by calling its {@link IBehavior::attach} method.
	 *
	 * Already attached behaviors may implement the function:
	 * <code>
	 *	public function dyAttachBehavior($name,$behavior[, $chain]) {
	 *  }
	 * </code>
	 * to be executed when attachBehavior is called.  All attached behaviors are notified through 
	 * dyAttachBehavior.
	 *
	 * @param string the behavior's name. It should uniquely identify this behavior.
	 * @param mixed the behavior configuration. This is passed as the first
	 * parameter to {@link YiiBase::createComponent} to create the behavior object.
	 * @return IBehavior the behavior object
	 * @since 3.2.1
	 */
	public function attachBehavior($name,$behavior,$priority=null)
	{
		if(is_string($behavior))
			$behavior=Prado::createComponent($behavior);
		if(!($behavior instanceof IBaseBehavior))
			throw new TInvalidDataTypeException('component_not_a_behavior',get_class($behavior));
		if($behavior instanceof IBehavior)
			$behavior->setEnabled(true);
		if($this->_m===null)
			$this->_m=new TPriorityMap;
		$behavior->attach($this);
		$this->dyAttachBehavior($name,$behavior);
		$this->_m->add($name,$behavior,$priority);
		return $behavior;
	}

	/**
	 * Detaches a behavior from the component.
	 * The behavior's {@link IBehavior::detach} method will be invoked.
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyDetachBehavior($name,$behavior[, $chain]) {
	 *  }
	 * </code>
	 * to be executed when detachBehavior is called.  All attached behaviors are notified through 
	 * dyDetachBehavior.
	 *
	 * @param string the behavior's name. It uniquely identifies the behavior.
	 * @param numeric the behavior's priority. This defaults to false, aka any priority.
	 * @return IBehavior the detached behavior. Null if the behavior does not exist.
	 * @since 3.2.1
	 */
	public function detachBehavior($name,$priority=false)
	{
		if($this->_m!=null&&isset($this->_m[$name]))
		{
			$this->_m[$name]->detach($this);
			$behavior=$this->_m->itemAt($name);
			$this->_m->remove($name,$priority);
			$this->dyDetachBehavior($name,$behavior);
			return $behavior;
		}
	}

	/**
	 * Enables all behaviors attached to this component independent of the behaviors
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyEnableBehaviors($name,$behavior[, $chain]) {
	 *  }
	 * </code>
	 * to be executed when enableBehaviors is called.  All attached behaviors are notified through 
	 * dyEnableBehaviors.
	 *
	 * @since 3.2.1
	 */
	public function enableBehaviors()
	{
		if(!$this->_behaviorsenabled)
		{
			$this->_behaviorsenabled=true;
			$this->dyEnableBehaviors();
		}
	}

	/**
	 * Disables all behaviors attached to this component independent of the behaviors
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyDisableBehaviors($name,$behavior[, $chain]) {
	 *  }
	 * </code>
	 * to be executed when disableBehaviors is called.  All attached behaviors are notified through 
	 * dyDisableBehaviors.
	 *
	 * @since 3.2.1
	 */
	public function disableBehaviors()
	{
		if($this->_behaviorsenabled)
		{
			$this->dyDisableBehaviors();
			$this->_behaviorsenabled=false;
		}
	}
	

	/**
	 * Returns if all the behaviors are turned on or off for the object.
	 * @return boolean whether or not all behaviors are enabled (true) or not (false)
	 * @since 3.2.1
	 */
	public function getBehaviorsEnabled()
	{
		return $this->_behaviorsenabled;
	}

	/**
	 * Enables an attached object behavior.  This cannot enable or disable whole class behaviors.
	 * A behavior is only effective when it is enabled.
	 * A behavior is enabled when first attached.
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyEnableBehavior($name,$behavior[, $chain]) {
	 *  }
	 * </code>
	 * to be executed when enableBehavior is called.  All attached behaviors are notified through 
	 * dyEnableBehavior.
	 *
	 * @param string the behavior's name. It uniquely identifies the behavior.
	 * @since 3.2.1
	 */
	public function enableBehavior($name)
	{
		if($this->_m!=null&&isset($this->_m[$name])){
			if($this->_m[$name] instanceof IBehavior) {
				$this->_m[$name]->setEnabled(true);
				$this->dyEnableBehavior($name,$this->_m[$name]);
				return true;
			}
			return false;
		}
		return null;
	}

	/**
	 * Disables an attached behavior.  This cannot enable or disable whole class behaviors.
	 * A behavior is only effective when it is enabled.
	 *
	 * Behaviors may implement the function:
	 * <code>
	 *	public function dyDisableBehavior($name,$behavior[, $chain]) {
	 *  }
	 * </code>
	 * to be executed when disableBehavior is called.  All attached behaviors are notified through 
	 * dyDisableBehavior.
	 *
	 * @param string the behavior's name. It uniquely identifies the behavior.
	 * @since 3.2.1
	 */
	public function disableBehavior($name)
	{
		if($this->_m!=null&&isset($this->_m[$name])){
			if($this->_m[$n
Back to Top