my-simon 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/README.md +3 -20
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/my-simon.gemspec +3 -78
  5. metadata +2 -77
  6. data/DOC/Launch Check List.docx +0 -0
  7. data/DOC/Launch Check List.pdf +0 -0
  8. data/build/rakefile.rb +0 -12
  9. data/config.rb +0 -24
  10. data/scaffolding/simon/controller.tpl +0 -9
  11. data/scaffolding/simon/model.tpl +0 -10
  12. data/scaffolding/simon/view.tpl +0 -5
  13. data/scaffolding/standards/html_template.html +0 -44
  14. data/scaffolding/standards/html_template.php +0 -44
  15. data/scaffolding/standards/jquery_plugin_template.js +0 -45
  16. data/scaffolding/standards/js_template.js +0 -43
  17. data/www/.htaccess +0 -488
  18. data/www/404.html +0 -32
  19. data/www/crossdomain.xml +0 -25
  20. data/www/favicon.ico +0 -0
  21. data/www/index.php +0 -17
  22. data/www/lib/js/homePage.js +0 -43
  23. data/www/lib/js/jquery/JQbook.js +0 -809
  24. data/www/lib/js/jquery/jquery-1.8.0.min.js +0 -27
  25. data/www/lib/js/jquery/jquery.alphanumeric.js +0 -82
  26. data/www/lib/js/jquery/jquery.cookie.js +0 -96
  27. data/www/lib/js/jquery/jquery.easing.1.3.js +0 -207
  28. data/www/lib/js/main.js +0 -117
  29. data/www/lib/js/master.js +0 -6
  30. data/www/lib/js/plugins/handlebars-1.0.rc.1.js +0 -1920
  31. data/www/lib/js/plugins/modernizr-1.7.min.js +0 -2
  32. data/www/lib/js/plugins/swfobject.js +0 -777
  33. data/www/lib/js/plugins_mod/README.txt +0 -3
  34. data/www/lib/php/app.php +0 -53
  35. data/www/lib/php/controller/index.php +0 -10
  36. data/www/lib/php/controller/regex.php +0 -23
  37. data/www/lib/php/model/Book.php +0 -8
  38. data/www/lib/php/model/Model.php +0 -8
  39. data/www/lib/php/plugins/php-activerecord/ActiveRecord.php +0 -44
  40. data/www/lib/php/plugins/php-activerecord/lib/CallBack.php +0 -226
  41. data/www/lib/php/plugins/php-activerecord/lib/Column.php +0 -155
  42. data/www/lib/php/plugins/php-activerecord/lib/Config.php +0 -288
  43. data/www/lib/php/plugins/php-activerecord/lib/Connection.php +0 -456
  44. data/www/lib/php/plugins/php-activerecord/lib/ConnectionManager.php +0 -38
  45. data/www/lib/php/plugins/php-activerecord/lib/DateTime.php +0 -45
  46. data/www/lib/php/plugins/php-activerecord/lib/Exceptions.php +0 -137
  47. data/www/lib/php/plugins/php-activerecord/lib/Expressions.php +0 -183
  48. data/www/lib/php/plugins/php-activerecord/lib/Inflector.php +0 -115
  49. data/www/lib/php/plugins/php-activerecord/lib/Model.php +0 -1673
  50. data/www/lib/php/plugins/php-activerecord/lib/Reflections.php +0 -86
  51. data/www/lib/php/plugins/php-activerecord/lib/Relationship.php +0 -637
  52. data/www/lib/php/plugins/php-activerecord/lib/SQLBuilder.php +0 -396
  53. data/www/lib/php/plugins/php-activerecord/lib/Serialization.php +0 -302
  54. data/www/lib/php/plugins/php-activerecord/lib/Singleton.php +0 -57
  55. data/www/lib/php/plugins/php-activerecord/lib/Table.php +0 -547
  56. data/www/lib/php/plugins/php-activerecord/lib/Utils.php +0 -351
  57. data/www/lib/php/plugins/php-activerecord/lib/Validations.php +0 -833
  58. data/www/lib/php/plugins/php-activerecord/lib/adapters/MysqlAdapter.php +0 -73
  59. data/www/lib/php/plugins/php-activerecord/lib/adapters/OciAdapter.php +0 -121
  60. data/www/lib/php/plugins/php-activerecord/lib/adapters/PgsqlAdapter.php +0 -104
  61. data/www/lib/php/plugins/php-activerecord/lib/adapters/SqliteAdapter.php +0 -81
  62. data/www/lib/php/system/Config.php +0 -174
  63. data/www/lib/php/system/config.routes.php +0 -29
  64. data/www/lib/php/system/router.php +0 -220
  65. data/www/lib/php/template/footer.php +0 -59
  66. data/www/lib/php/template/header.php +0 -74
  67. data/www/lib/php/view/index.php +0 -5
  68. data/www/media/images/facebook_share.jpg +0 -0
  69. data/www/robots.txt +0 -5
  70. data/www/sandbox/readme.txt +0 -3
  71. data/www/sass/javascript.scss +0 -1
  72. data/www/sass/layout.scss +0 -128
  73. data/www/sass/master.scss +0 -4
  74. data/www/sass/reset.scss +0 -47
  75. data/www/sass/typography.scss +0 -24
  76. data/www/styles/javascript.css +0 -1
  77. data/www/styles/layout.css +0 -186
  78. data/www/styles/master.css +0 -4
  79. data/www/styles/reset.css +0 -60
  80. data/www/styles/typography.css +0 -24
@@ -1,1673 +0,0 @@
1
- <?php
2
- /**
3
- * @package ActiveRecord
4
- */
5
- namespace ActiveRecord;
6
-
7
- /**
8
- * The base class for your models.
9
- *
10
- * Defining an ActiveRecord model for a table called people and orders:
11
- *
12
- * <code>
13
- * CREATE TABLE people(
14
- * id int primary key auto_increment,
15
- * parent_id int,
16
- * first_name varchar(50),
17
- * last_name varchar(50)
18
- * );
19
- *
20
- * CREATE TABLE orders(
21
- * id int primary key auto_increment,
22
- * person_id int not null,
23
- * cost decimal(10,2),
24
- * total decimal(10,2)
25
- * );
26
- * </code>
27
- *
28
- * <code>
29
- * class Person extends ActiveRecord\Model {
30
- * static $belongs_to = array(
31
- * array('parent', 'foreign_key' => 'parent_id', 'class_name' => 'Person')
32
- * );
33
- *
34
- * static $has_many = array(
35
- * array('children', 'foreign_key' => 'parent_id', 'class_name' => 'Person'),
36
- * array('orders')
37
- * );
38
- *
39
- * static $validates_length_of = array(
40
- * array('first_name', 'within' => array(1,50)),
41
- * array('last_name', 'within' => array(1,50))
42
- * );
43
- * }
44
- *
45
- * class Order extends ActiveRecord\Model {
46
- * static $belongs_to = array(
47
- * array('person')
48
- * );
49
- *
50
- * static $validates_numericality_of = array(
51
- * array('cost', 'greater_than' => 0),
52
- * array('total', 'greater_than' => 0)
53
- * );
54
- *
55
- * static $before_save = array('calculate_total_with_tax');
56
- *
57
- * public function calculate_total_with_tax() {
58
- * $this->total = $this->cost * 0.045;
59
- * }
60
- * }
61
- * </code>
62
- *
63
- * For a more in-depth look at defining models, relationships, callbacks and many other things
64
- * please consult our {@link http://www.phpactiverecord.org/guides Guides}.
65
- *
66
- * @package ActiveRecord
67
- * @see BelongsTo
68
- * @see CallBack
69
- * @see HasMany
70
- * @see HasAndBelongsToMany
71
- * @see Serialization
72
- * @see Validations
73
- */
74
- class Model
75
- {
76
- /**
77
- * An instance of {@link Errors} and will be instantiated once a write method is called.
78
- *
79
- * @var Errors
80
- */
81
- public $errors;
82
-
83
- /**
84
- * Contains model values as column_name => value
85
- *
86
- * @var array
87
- */
88
- private $attributes = array();
89
-
90
- /**
91
- * Flag whether or not this model's attributes have been modified since it will either be null or an array of column_names that have been modified
92
- *
93
- * @var array
94
- */
95
- private $__dirty = null;
96
-
97
- /**
98
- * Flag that determines of this model can have a writer method invoked such as: save/update/insert/delete
99
- *
100
- * @var boolean
101
- */
102
- private $__readonly = false;
103
-
104
- /**
105
- * Array of relationship objects as model_attribute_name => relationship
106
- *
107
- * @var array
108
- */
109
- private $__relationships = array();
110
-
111
- /**
112
- * Flag that determines if a call to save() should issue an insert or an update sql statement
113
- *
114
- * @var boolean
115
- */
116
- private $__new_record = true;
117
-
118
- /**
119
- * Set to the name of the connection this {@link Model} should use.
120
- *
121
- * @var string
122
- */
123
- static $connection;
124
-
125
- /**
126
- * Set to the name of the database this Model's table is in.
127
- *
128
- * @var string
129
- */
130
- static $db;
131
-
132
- /**
133
- * Set this to explicitly specify the model's table name if different from inferred name.
134
- *
135
- * If your table doesn't follow our table name convention you can set this to the
136
- * name of your table to explicitly tell ActiveRecord what your table is called.
137
- *
138
- * @var string
139
- */
140
- static $table_name;
141
-
142
- /**
143
- * Set this to override the default primary key name if different from default name of "id".
144
- *
145
- * @var string
146
- */
147
- static $primary_key;
148
-
149
- /**
150
- * Set this to explicitly specify the sequence name for the table.
151
- *
152
- * @var string
153
- */
154
- static $sequence;
155
-
156
- /**
157
- * Allows you to create aliases for attributes.
158
- *
159
- * <code>
160
- * class Person extends ActiveRecord\Model {
161
- * static $alias_attribute = array(
162
- * 'the_first_name' => 'first_name',
163
- * 'the_last_name' => 'last_name');
164
- * }
165
- *
166
- * $person = Person::first();
167
- * $person->the_first_name = 'Tito';
168
- * echo $person->the_first_name;
169
- * </code>
170
- *
171
- * @var array
172
- */
173
- static $alias_attribute = array();
174
-
175
- /**
176
- * Whitelist of attributes that are checked from mass-assignment calls such as constructing a model or using update_attributes.
177
- *
178
- * This is the opposite of {@link attr_protected $attr_protected}.
179
- *
180
- * <code>
181
- * class Person extends ActiveRecord\Model {
182
- * static $attr_accessible = array('first_name','last_name');
183
- * }
184
- *
185
- * $person = new Person(array(
186
- * 'first_name' => 'Tito',
187
- * 'last_name' => 'the Grief',
188
- * 'id' => 11111));
189
- *
190
- * echo $person->id; # => null
191
- * </code>
192
- *
193
- * @var array
194
- */
195
- static $attr_accessible = array();
196
-
197
- /**
198
- * Blacklist of attributes that cannot be mass-assigned.
199
- *
200
- * This is the opposite of {@link attr_accessible $attr_accessible} and the format
201
- * for defining these are exactly the same.
202
- *
203
- * @var array
204
- */
205
- static $attr_protected = array();
206
-
207
- /**
208
- * Delegates calls to a relationship.
209
- *
210
- * <code>
211
- * class Person extends ActiveRecord\Model {
212
- * static $belongs_to = array(array('venue'),array('host'));
213
- * static $delegate = array(
214
- * array('name', 'state', 'to' => 'venue'),
215
- * array('name', 'to' => 'host', 'prefix' => 'woot'));
216
- * }
217
- * </code>
218
- *
219
- * Can then do:
220
- *
221
- * <code>
222
- * $person->state # same as calling $person->venue->state
223
- * $person->name # same as calling $person->venue->name
224
- * $person->woot_name # same as calling $person->host->name
225
- * </code>
226
- *
227
- * @var array
228
- */
229
- static $delegate = array();
230
-
231
- /**
232
- * Define customer setters methods for the model.
233
- *
234
- * You can also use this to define custom setters for attributes as well.
235
- *
236
- * <code>
237
- * class User extends ActiveRecord\Model {
238
- * static $setters = array('password','more','even_more');
239
- *
240
- * # now to define the setter methods. Note you must
241
- * # prepend set_ to your method name:
242
- * function set_password($plaintext) {
243
- * $this->encrypted_password = md5($plaintext);
244
- * }
245
- * }
246
- *
247
- * $user = new User();
248
- * $user->password = 'plaintext'; # will call $user->set_password('plaintext')
249
- * </code>
250
- *
251
- * If you define a custom setter with the same name as an attribute then you
252
- * will need to use assign_attribute() to assign the value to the attribute.
253
- * This is necessary due to the way __set() works.
254
- *
255
- * For example, assume 'name' is a field on the table and we're defining a
256
- * custom setter for 'name':
257
- *
258
- * <code>
259
- * class User extends ActiveRecord\Model {
260
- * static $setters = array('name');
261
- *
262
- * # INCORRECT way to do it
263
- * # function set_name($name) {
264
- * # $this->name = strtoupper($name);
265
- * # }
266
- *
267
- * function set_name($name) {
268
- * $this->assign_attribute('name',strtoupper($name));
269
- * }
270
- * }
271
- *
272
- * $user = new User();
273
- * $user->name = 'bob';
274
- * echo $user->name; # => BOB
275
- * </code>
276
- *
277
- * @var array
278
- */
279
- static $setters = array();
280
-
281
- /**
282
- * Define customer getter methods for the model.
283
- *
284
- * <code>
285
- * class User extends ActiveRecord\Model {
286
- * static $getters = array('middle_initial','more','even_more');
287
- *
288
- * # now to define the getter method. Note you must
289
- * # prepend get_ to your method name:
290
- * function get_middle_initial() {
291
- * return $this->middle_name{0};
292
- * }
293
- * }
294
- *
295
- * $user = new User();
296
- * echo $user->middle_name; # will call $user->get_middle_name()
297
- * </code>
298
- *
299
- * If you define a custom getter with the same name as an attribute then you
300
- * will need to use read_attribute() to get the attribute's value.
301
- * This is necessary due to the way __get() works.
302
- *
303
- * For example, assume 'name' is a field on the table and we're defining a
304
- * custom getter for 'name':
305
- *
306
- * <code>
307
- * class User extends ActiveRecord\Model {
308
- * static $getters = array('name');
309
- *
310
- * # INCORRECT way to do it
311
- * # function get_name() {
312
- * # return strtoupper($this->name);
313
- * # }
314
- *
315
- * function get_name() {
316
- * return strtoupper($this->read_attribute('name'));
317
- * }
318
- * }
319
- *
320
- * $user = new User();
321
- * $user->name = 'bob';
322
- * echo $user->name; # => BOB
323
- * </code>
324
- *
325
- * @var array
326
- */
327
- static $getters = array();
328
-
329
- /**
330
- * Constructs a model.
331
- *
332
- * When a user instantiates a new object (e.g.: it was not ActiveRecord that instantiated via a find)
333
- * then @var $attributes will be mapped according to the schema's defaults. Otherwise, the given
334
- * $attributes will be mapped via set_attributes_via_mass_assignment.
335
- *
336
- * <code>
337
- * new Person(array('first_name' => 'Tito', 'last_name' => 'the Grief'));
338
- * </code>
339
- *
340
- * @param array $attributes Hash containing names and values to mass assign to the model
341
- * @param boolean $guard_attributes Set to true to guard attributes
342
- * @param boolean $instantiating_via_find Set to true if this model is being created from a find call
343
- * @param boolean $new_record Set to true if this should be considered a new record
344
- * @return Model
345
- */
346
- public function __construct(array $attributes=array(), $guard_attributes=true, $instantiating_via_find=false, $new_record=true)
347
- {
348
- $this->__new_record = $new_record;
349
-
350
- // initialize attributes applying defaults
351
- if (!$instantiating_via_find)
352
- {
353
- foreach (static::table()->columns as $name => $meta)
354
- $this->attributes[$meta->inflected_name] = $meta->default;
355
- }
356
-
357
- $this->set_attributes_via_mass_assignment($attributes, $guard_attributes);
358
-
359
- // since all attribute assignment now goes thru assign_attributes() we want to reset
360
- // dirty if instantiating via find since nothing is really dirty when doing that
361
- if ($instantiating_via_find)
362
- $this->__dirty = array();
363
-
364
- $this->invoke_callback('after_construct',false);
365
- }
366
-
367
- /**
368
- * Magic method which delegates to read_attribute(). This handles firing off getter methods,
369
- * as they are not checked/invoked inside of read_attribute(). This circumvents the problem with
370
- * a getter being accessed with the same name as an actual attribute.
371
- *
372
- * @see read_attribute()
373
- * @param string $name Name of an attribute
374
- * @return mixed The value of the attribute
375
- */
376
- public function &__get($name)
377
- {
378
- // check for getter
379
- if (in_array("get_$name",static::$getters))
380
- {
381
- $name = "get_$name";
382
- $value = $this->$name();
383
- return $value;
384
- }
385
-
386
- return $this->read_attribute($name);
387
- }
388
-
389
- /**
390
- * Determines if an attribute exists for this {@link Model}.
391
- *
392
- * @param string $attribute_name
393
- * @return boolean
394
- */
395
- public function __isset($attribute_name)
396
- {
397
- return array_key_exists($attribute_name,$this->attributes) || array_key_exists($attribute_name,static::$alias_attribute);
398
- }
399
-
400
- /**
401
- * Magic allows un-defined attributes to set via $attributes
402
- *
403
- * @throws {@link UndefinedPropertyException} if $name does not exist
404
- * @param string $name Name of attribute, relationship or other to set
405
- * @param mixed $value The value
406
- * @return mixed The value
407
- */
408
- public function __set($name, $value)
409
- {
410
- if (array_key_exists($name, static::$alias_attribute))
411
- $name = static::$alias_attribute[$name];
412
-
413
- elseif (in_array("set_$name",static::$setters))
414
- {
415
- $name = "set_$name";
416
- return $this->$name($value);
417
- }
418
-
419
- if (array_key_exists($name,$this->attributes))
420
- return $this->assign_attribute($name,$value);
421
-
422
- foreach (static::$delegate as &$item)
423
- {
424
- if (($delegated_name = $this->is_delegated($name,$item)))
425
- return $this->$item['to']->$delegated_name = $value;
426
- }
427
-
428
- throw new UndefinedPropertyException(get_called_class(),$name);
429
- }
430
-
431
- public function __wakeup()
432
- {
433
- // make sure the models Table instance gets initialized when waking up
434
- static::table();
435
- }
436
-
437
- /**
438
- * Assign a value to an attribute.
439
- *
440
- * @param string $name Name of the attribute
441
- * @param mixed &$value Value of the attribute
442
- * @return mixed the attribute value
443
- */
444
- public function assign_attribute($name, $value)
445
- {
446
- $table = static::table();
447
-
448
- if (array_key_exists($name,$table->columns) && !is_object($value))
449
- $value = $table->columns[$name]->cast($value,static::connection());
450
-
451
- // convert php's \DateTime to ours
452
- if ($value instanceof \DateTime)
453
- $value = new DateTime($value->format('Y-m-d H:i:s T'));
454
-
455
- // make sure DateTime values know what model they belong to so
456
- // dirty stuff works when calling set methods on the DateTime object
457
- if ($value instanceof DateTime)
458
- $value->attribute_of($this,$name);
459
-
460
- $this->attributes[$name] = $value;
461
- $this->flag_dirty($name);
462
- return $value;
463
- }
464
-
465
- /**
466
- * Retrieves an attribute's value or a relationship object based on the name passed. If the attribute
467
- * accessed is 'id' then it will return the model's primary key no matter what the actual attribute name is
468
- * for the primary key.
469
- *
470
- * @param string $name Name of an attribute
471
- * @return mixed The value of the attribute
472
- * @throws {@link UndefinedPropertyException} if name could not be resolved to an attribute, relationship, ...
473
- */
474
- public function &read_attribute($name)
475
- {
476
- // check for aliased attribute
477
- if (array_key_exists($name, static::$alias_attribute))
478
- $name = static::$alias_attribute[$name];
479
-
480
- // check for attribute
481
- if (array_key_exists($name,$this->attributes))
482
- return $this->attributes[$name];
483
-
484
- // check relationships if no attribute
485
- if (array_key_exists($name,$this->__relationships))
486
- return $this->__relationships[$name];
487
-
488
- $table = static::table();
489
-
490
- // this may be first access to the relationship so check Table
491
- if (($relationship = $table->get_relationship($name)))
492
- {
493
- $this->__relationships[$name] = $relationship->load($this);
494
- return $this->__relationships[$name];
495
- }
496
-
497
- if ($name == 'id')
498
- {
499
- if (count($this->get_primary_key()) > 1)
500
- throw new Exception("TODO composite key support");
501
-
502
- if (isset($this->attributes[$table->pk[0]]))
503
- return $this->attributes[$table->pk[0]];
504
- }
505
-
506
- //do not remove - have to return null by reference in strict mode
507
- $null = null;
508
-
509
- foreach (static::$delegate as &$item)
510
- {
511
- if (($delegated_name = $this->is_delegated($name,$item)))
512
- {
513
- $to = $item['to'];
514
- if ($this->$to)
515
- {
516
- $val =& $this->$to->$delegated_name;
517
- return $val;
518
- }
519
- else
520
- return $null;
521
- }
522
- }
523
-
524
- throw new UndefinedPropertyException(get_called_class(),$name);
525
- }
526
-
527
- /**
528
- * Flags an attribute as dirty.
529
- *
530
- * @param string $name Attribute name
531
- */
532
- public function flag_dirty($name)
533
- {
534
- if (!$this->__dirty)
535
- $this->__dirty = array();
536
-
537
- $this->__dirty[$name] = true;
538
- }
539
-
540
- /**
541
- * Returns hash of attributes that have been modified since loading the model.
542
- *
543
- * @return mixed null if no dirty attributes otherwise returns array of dirty attributes.
544
- */
545
- public function dirty_attributes()
546
- {
547
- if (!$this->__dirty)
548
- return null;
549
-
550
- $dirty = array_intersect_key($this->attributes,$this->__dirty);
551
- return !empty($dirty) ? $dirty : null;
552
- }
553
-
554
- /**
555
- * Returns a copy of the model's attributes hash.
556
- *
557
- * @return array A copy of the model's attribute data
558
- */
559
- public function attributes()
560
- {
561
- return $this->attributes;
562
- }
563
-
564
- /**
565
- * Retrieve the primary key name.
566
- *
567
- * @return string The primary key for the model
568
- */
569
- public function get_primary_key()
570
- {
571
- return Table::load(get_class($this))->pk;
572
- }
573
-
574
- /**
575
- * Returns the actual attribute name if $name is aliased.
576
- *
577
- * @param string $name An attribute name
578
- * @return string
579
- */
580
- public function get_real_attribute_name($name)
581
- {
582
- if (array_key_exists($name,$this->attributes))
583
- return $name;
584
-
585
- if (array_key_exists($name,static::$alias_attribute))
586
- return static::$alias_attribute[$name];
587
-
588
- return null;
589
- }
590
-
591
- /**
592
- * Returns array of validator data for this Model.
593
- *
594
- * Will return an array looking like:
595
- *
596
- * <code>
597
- * array(
598
- * 'name' => array(
599
- * array('validator' => 'validates_presence_of'),
600
- * array('validator' => 'validates_inclusion_of', 'in' => array('Bob','Joe','John')),
601
- * 'password' => array(
602
- * array('validator' => 'validates_length_of', 'minimum' => 6))
603
- * )
604
- * );
605
- * </code>
606
- *
607
- * @return array An array containing validator data for this model.
608
- */
609
- public function get_validation_rules()
610
- {
611
- require_once 'Validations.php';
612
-
613
- $validator = new Validations($this);
614
- return $validator->rules();
615
- }
616
-
617
- /**
618
- * Returns an associative array containing values for all the attributes in $attributes
619
- *
620
- * @param array $attributes Array containing attribute names
621
- * @return array A hash containing $name => $value
622
- */
623
- public function get_values_for($attributes)
624
- {
625
- $ret = array();
626
-
627
- foreach ($attributes as $name)
628
- {
629
- if (array_key_exists($name,$this->attributes))
630
- $ret[$name] = $this->attributes[$name];
631
- }
632
- return $ret;
633
- }
634
-
635
- /**
636
- * Retrieves the name of the table for this Model.
637
- *
638
- * @return string
639
- */
640
- public static function table_name()
641
- {
642
- return static::table()->table;
643
- }
644
-
645
- /**
646
- * Returns the attribute name on the delegated relationship if $name is
647
- * delegated or null if not delegated.
648
- *
649
- * @param string $name Name of an attribute
650
- * @param array $delegate An array containing delegate data
651
- * @return delegated attribute name or null
652
- */
653
- private function is_delegated($name, &$delegate)
654
- {
655
- if ($delegate['prefix'] != '')
656
- $name = substr($name,strlen($delegate['prefix'])+1);
657
-
658
- if (is_array($delegate) && in_array($name,$delegate['delegate']))
659
- return $name;
660
-
661
- return null;
662
- }
663
-
664
- /**
665
- * Determine if the model is in read-only mode.
666
- *
667
- * @return boolean
668
- */
669
- public function is_readonly()
670
- {
671
- return $this->__readonly;
672
- }
673
-
674
- /**
675
- * Determine if the model is a new record.
676
- *
677
- * @return boolean
678
- */
679
- public function is_new_record()
680
- {
681
- return $this->__new_record;
682
- }
683
-
684
- /**
685
- * Throws an exception if this model is set to readonly.
686
- *
687
- * @throws ActiveRecord\ReadOnlyException
688
- * @param string $method_name Name of method that was invoked on model for exception message
689
- */
690
- private function verify_not_readonly($method_name)
691
- {
692
- if ($this->is_readonly())
693
- throw new ReadOnlyException(get_class($this), $method_name);
694
- }
695
-
696
- /**
697
- * Flag model as readonly.
698
- *
699
- * @param boolean $readonly Set to true to put the model into readonly mode
700
- */
701
- public function readonly($readonly=true)
702
- {
703
- $this->__readonly = $readonly;
704
- }
705
-
706
- /**
707
- * Retrieve the connection for this model.
708
- *
709
- * @return Connection
710
- */
711
- public static function connection()
712
- {
713
- return static::table()->conn;
714
- }
715
-
716
- /**
717
- * Returns the {@link Table} object for this model.
718
- *
719
- * Be sure to call in static scoping: static::table()
720
- *
721
- * @return Table
722
- */
723
- public static function table()
724
- {
725
- return Table::load(get_called_class());
726
- }
727
-
728
- /**
729
- * Creates a model and saves it to the database.
730
- *
731
- * @param array $attributes Array of the models attributes
732
- * @param boolean $validate True if the validators should be run
733
- * @return Model
734
- */
735
- public static function create($attributes, $validate=true)
736
- {
737
- $class_name = get_called_class();
738
- $model = new $class_name($attributes);
739
- $model->save($validate);
740
- return $model;
741
- }
742
-
743
- /**
744
- * Save the model to the database.
745
- *
746
- * This function will automatically determine if an INSERT or UPDATE needs to occur.
747
- * If a validation or a callback for this model returns false, then the model will
748
- * not be saved and this will return false.
749
- *
750
- * If saving an existing model only data that has changed will be saved.
751
- *
752
- * @param boolean $validate Set to true or false depending on if you want the validators to run or not
753
- * @return boolean True if the model was saved to the database otherwise false
754
- */
755
- public function save($validate=true)
756
- {
757
- $this->verify_not_readonly('save');
758
- return $this->is_new_record() ? $this->insert($validate) : $this->update($validate);
759
- }
760
-
761
- /**
762
- * Issue an INSERT sql statement for this model's attribute.
763
- *
764
- * @see save
765
- * @param boolean $validate Set to true or false depending on if you want the validators to run or not
766
- * @return boolean True if the model was saved to the database otherwise false
767
- */
768
- private function insert($validate=true)
769
- {
770
- $this->verify_not_readonly('insert');
771
-
772
- if (($validate && !$this->_validate() || !$this->invoke_callback('before_create',false)))
773
- return false;
774
-
775
- $table = static::table();
776
-
777
- if (!($attributes = $this->dirty_attributes()))
778
- $attributes = $this->attributes;
779
-
780
- $pk = $this->get_primary_key();
781
- $use_sequence = false;
782
-
783
- if ($table->sequence && !isset($attributes[$pk[0]]))
784
- {
785
- if (($conn = static::connection()) instanceof OciAdapter)
786
- {
787
- // terrible oracle makes us select the nextval first
788
- $attributes[$pk[0]] = $conn->get_next_sequence_value($table->sequence);
789
- $table->insert($attributes);
790
- $this->attributes[$pk[0]] = $attributes[$pk[0]];
791
- }
792
- else
793
- {
794
- // unset pk that was set to null
795
- if (array_key_exists($pk[0],$attributes))
796
- unset($attributes[$pk[0]]);
797
-
798
- $table->insert($attributes,$pk[0],$table->sequence);
799
- $use_sequence = true;
800
- }
801
- }
802
- else
803
- $table->insert($attributes);
804
-
805
- // if we've got an autoincrementing/sequenced pk set it
806
- if (count($pk) == 1)
807
- {
808
- $column = $table->get_column_by_inflected_name($pk[0]);
809
-
810
- if ($column->auto_increment || $use_sequence)
811
- $this->attributes[$pk[0]] = $table->conn->insert_id($table->sequence);
812
- }
813
-
814
- $this->invoke_callback('after_create',false);
815
- $this->__new_record = false;
816
- return true;
817
- }
818
-
819
- /**
820
- * Issue an UPDATE sql statement for this model's dirty attributes.
821
- *
822
- * @see save
823
- * @param boolean $validate Set to true or false depending on if you want the validators to run or not
824
- * @return boolean True if the model was saved to the database otherwise false
825
- */
826
- private function update($validate=true)
827
- {
828
- $this->verify_not_readonly('update');
829
-
830
- if ($validate && !$this->_validate())
831
- return false;
832
-
833
- if ($this->is_dirty())
834
- {
835
- $pk = $this->values_for_pk();
836
-
837
- if (empty($pk))
838
- throw new ActiveRecordException("Cannot update, no primary key defined for: " . get_called_class());
839
-
840
- if (!$this->invoke_callback('before_update',false))
841
- return false;
842
-
843
- $dirty = $this->dirty_attributes();
844
- static::table()->update($dirty,$pk);
845
- $this->invoke_callback('after_update',false);
846
- }
847
-
848
- return true;
849
- }
850
-
851
- /**
852
- * Deletes this model from the database and returns true if successful.
853
- *
854
- * @return boolean
855
- */
856
- public function delete()
857
- {
858
- $this->verify_not_readonly('delete');
859
-
860
- $pk = $this->values_for_pk();
861
-
862
- if (empty($pk))
863
- throw new ActiveRecordException("Cannot delete, no primary key defined for: " . get_called_class());
864
-
865
- if (!$this->invoke_callback('before_destroy',false))
866
- return false;
867
-
868
- static::table()->delete($pk);
869
- $this->invoke_callback('after_destroy',false);
870
-
871
- return true;
872
- }
873
-
874
- /**
875
- * Helper that creates an array of values for the primary key(s).
876
- *
877
- * @return array An array in the form array(key_name => value, ...)
878
- */
879
- public function values_for_pk()
880
- {
881
- return $this->values_for(static::table()->pk);
882
- }
883
-
884
- /**
885
- * Helper to return a hash of values for the specified attributes.
886
- *
887
- * @param array $attribute_names Array of attribute names
888
- * @return array An array in the form array(name => value, ...)
889
- */
890
- public function values_for($attribute_names)
891
- {
892
- $filter = array();
893
-
894
- foreach ($attribute_names as $name)
895
- $filter[$name] = $this->$name;
896
-
897
- return $filter;
898
- }
899
-
900
- /**
901
- * Validates the model.
902
- *
903
- * @return boolean True if passed validators otherwise false
904
- */
905
- private function _validate()
906
- {
907
- require_once 'Validations.php';
908
-
909
- $validator = new Validations($this);
910
- $validation_on = 'validation_on_' . ($this->is_new_record() ? 'create' : 'update');
911
-
912
- foreach (array('before_validation', "before_$validation_on") as $callback)
913
- {
914
- if (!$this->invoke_callback($callback,false))
915
- return false;
916
- }
917
-
918
- $this->errors = $validator->validate();
919
-
920
- foreach (array('after_validation', "after_$validation_on") as $callback)
921
- $this->invoke_callback($callback,false);
922
-
923
- if (!$this->errors->is_empty())
924
- return false;
925
-
926
- return true;
927
- }
928
-
929
- /**
930
- * Returns true if the model has been modified.
931
- *
932
- * @return boolean true if modified
933
- */
934
- public function is_dirty()
935
- {
936
- return empty($this->__dirty) ? false : true;
937
- }
938
-
939
- /**
940
- * Run validations on model and returns whether or not model passed validation.
941
- *
942
- * @see is_invalid
943
- * @return boolean
944
- */
945
- public function is_valid()
946
- {
947
- return $this->_validate();
948
- }
949
-
950
- /**
951
- * Runs validations and returns true if invalid.
952
- *
953
- * @see is_valid
954
- * @return boolean
955
- */
956
- public function is_invalid()
957
- {
958
- return !$this->_validate();
959
- }
960
-
961
- /**
962
- * Updates a model's timestamps.
963
- */
964
- public function set_timestamps()
965
- {
966
- $now = date('Y-m-d H:i:s');
967
-
968
- if (isset($this->updated_at))
969
- $this->updated_at = $now;
970
-
971
- if (isset($this->created_at) && $this->is_new_record())
972
- $this->created_at = $now;
973
- }
974
-
975
- /**
976
- * Mass update the model with an array of attribute data and saves to the database.
977
- *
978
- * @param array $attributes An attribute data array in the form array(name => value, ...)
979
- * @return boolean True if successfully updated and saved otherwise false
980
- */
981
- public function update_attributes($attributes)
982
- {
983
- $this->set_attributes($attributes);
984
- return $this->save();
985
- }
986
-
987
- /**
988
- * Updates a single attribute and saves the record without going through the normal validation procedure.
989
- *
990
- * @param string $name Name of attribute
991
- * @param mixed $value Value of the attribute
992
- * @return boolean True if successful otherwise false
993
- */
994
- public function update_attribute($name, $value)
995
- {
996
- $this->__set($name, $value);
997
- return $this->update(false);
998
- }
999
-
1000
- /**
1001
- * Mass update the model with data from an attributes hash.
1002
- *
1003
- * Unlike update_attributes() this method only updates the model's data
1004
- * but DOES NOT save it to the database.
1005
- *
1006
- * @see update_attributes
1007
- * @param array $attributes An array containing data to update in the form array(name => value, ...)
1008
- */
1009
- public function set_attributes(array $attributes)
1010
- {
1011
- $this->set_attributes_via_mass_assignment($attributes, true);
1012
- }
1013
-
1014
- /**
1015
- * Passing $guard_attributes as true will throw an exception if an attribute does not exist.
1016
- *
1017
- * @throws ActiveRecord\UndefinedPropertyException
1018
- * @param array $attributes An array in the form array(name => value, ...)
1019
- * @param boolean $guard_attributes Flag of whether or not attributes should be guarded
1020
- */
1021
- private function set_attributes_via_mass_assignment(array &$attributes, $guard_attributes)
1022
- {
1023
- //access uninflected columns since that is what we would have in result set
1024
- $table = static::table();
1025
- $exceptions = array();
1026
- $use_attr_accessible = !empty(static::$attr_accessible);
1027
- $use_attr_protected = !empty(static::$attr_protected);
1028
- $connection = static::connection();
1029
-
1030
- foreach ($attributes as $name => $value)
1031
- {
1032
- // is a normal field on the table
1033
- if (array_key_exists($name,$table->columns))
1034
- {
1035
- $value = $table->columns[$name]->cast($value,$connection);
1036
- $name = $table->columns[$name]->inflected_name;
1037
- }
1038
-
1039
- if ($guard_attributes)
1040
- {
1041
- if ($use_attr_accessible && !in_array($name,static::$attr_accessible))
1042
- continue;
1043
-
1044
- if ($use_attr_protected && in_array($name,static::$attr_protected))
1045
- continue;
1046
-
1047
- // set valid table data
1048
- try {
1049
- $this->$name = $value;
1050
- } catch (UndefinedPropertyException $e) {
1051
- $exceptions[] = $e->getMessage();
1052
- }
1053
- }
1054
- else
1055
- {
1056
- // ignore OciAdapter's limit() stuff
1057
- if ($name == 'ar_rnum__')
1058
- continue;
1059
-
1060
- // set arbitrary data
1061
- $this->assign_attribute($name,$value);
1062
- }
1063
- }
1064
-
1065
- if (!empty($exceptions))
1066
- throw new UndefinedPropertyException(get_called_class(),$exceptions);
1067
- }
1068
-
1069
- /**
1070
- * Add a model to the given named ($name) relationship.
1071
- *
1072
- * @internal This should <strong>only</strong> be used by eager load
1073
- * @param Model $model
1074
- * @param $name of relationship for this table
1075
- * @return void
1076
- */
1077
- public function set_relationship_from_eager_load(Model $model=null, $name)
1078
- {
1079
- $table = static::table();
1080
-
1081
- if (($rel = $table->get_relationship($name)))
1082
- {
1083
- if ($rel->is_poly())
1084
- {
1085
- // if the related model is null and it is a poly then we should have an empty array
1086
- if (is_null($model))
1087
- return $this->__relationships[$name] = array();
1088
- else
1089
- return $this->__relationships[$name][] = $model;
1090
- }
1091
- else
1092
- return $this->__relationships[$name] = $model;
1093
- }
1094
-
1095
- throw new RelationshipException("Relationship named $name has not been declared for class: {$table->class->getName()}");
1096
- }
1097
-
1098
- /**
1099
- * Reloads the attributes and relationships of this object from the database.
1100
- *
1101
- * @return Model
1102
- */
1103
- public function reload()
1104
- {
1105
- $this->__relationships = array();
1106
- $pk = array_values($this->get_values_for($this->get_primary_key()));
1107
-
1108
- $this->set_attributes($this->find($pk)->attributes);
1109
- $this->reset_dirty();
1110
-
1111
- return $this;
1112
- }
1113
-
1114
- public function __clone()
1115
- {
1116
- $this->__relationships = array();
1117
- $this->reset_dirty();
1118
- return $this;
1119
- }
1120
-
1121
- /**
1122
- * Resets the dirty array.
1123
- *
1124
- * @see dirty_attributes
1125
- */
1126
- public function reset_dirty()
1127
- {
1128
- $this->__dirty = null;
1129
- }
1130
-
1131
- /**
1132
- * A list of valid finder options.
1133
- *
1134
- * @var array
1135
- */
1136
- static $VALID_OPTIONS = array('conditions', 'limit', 'offset', 'order', 'select', 'joins', 'include', 'readonly', 'group', 'from', 'having');
1137
-
1138
- /**
1139
- * Enables the use of dynamic finders.
1140
- *
1141
- * Dynamic finders are just an easy way to do queries quickly without having to
1142
- * specify an options array with conditions in it.
1143
- *
1144
- * <code>
1145
- * SomeModel::find_by_first_name('Tito');
1146
- * SomeModel::find_by_first_name_and_last_name('Tito','the Grief');
1147
- * SomeModel::find_by_first_name_or_last_name('Tito','the Grief');
1148
- * SomeModel::find_all_by_last_name('Smith');
1149
- * SomeModel::count_by_name('Bob')
1150
- * SomeModel::count_by_name_or_state('Bob','VA')
1151
- * SomeModel::count_by_name_and_state('Bob','VA')
1152
- * </code>
1153
- *
1154
- * You can also create the model if the find call returned no results:
1155
- *
1156
- * <code>
1157
- * Person::find_or_create_by_name('Tito');
1158
- *
1159
- * # would be the equivalent of
1160
- * if (!Person::find_by_name('Tito'))
1161
- * Person::create(array('Tito'));
1162
- * </code>
1163
- *
1164
- * Some other examples of find_or_create_by:
1165
- *
1166
- * <code>
1167
- * Person::find_or_create_by_name_and_id('Tito',1);
1168
- * Person::find_or_create_by_name_and_id(array('name' => 'Tito', 'id' => 1));
1169
- * </code>
1170
- *
1171
- * @param string $method Name of method
1172
- * @param mixed $args Method args
1173
- * @return Model
1174
- * @throws {@link ActiveRecordException} if invalid query
1175
- * @see find
1176
- */
1177
- public static function __callStatic($method, $args)
1178
- {
1179
- $options = static::extract_and_validate_options($args);
1180
- $create = false;
1181
-
1182
- if (substr($method,0,17) == 'find_or_create_by')
1183
- {
1184
- $attributes = substr($method,17);
1185
-
1186
- // can't take any finders with OR in it when doing a find_or_create_by
1187
- if (strpos($attributes,'_or_') !== false)
1188
- throw new ActiveRecordException("Cannot use OR'd attributes in find_or_create_by");
1189
-
1190
- $create = true;
1191
- $method = 'find_by' . substr($method,17);
1192
- }
1193
-
1194
- if (substr($method,0,7) === 'find_by')
1195
- {
1196
- $attributes = substr($method,8);
1197
- $options['conditions'] = SQLBuilder::create_conditions_from_underscored_string(static::table()->conn,$attributes,$args,static::$alias_attribute);
1198
-
1199
- if (!($ret = static::find('first',$options)) && $create)
1200
- return static::create(SQLBuilder::create_hash_from_underscored_string($attributes,$args,static::$alias_attribute));
1201
-
1202
- return $ret;
1203
- }
1204
- elseif (substr($method,0,11) === 'find_all_by')
1205
- {
1206
- $options['conditions'] = SQLBuilder::create_conditions_from_underscored_string(static::table()->conn,substr($method,12),$args,static::$alias_attribute);
1207
- return static::find('all',$options);
1208
- }
1209
- elseif (substr($method,0,8) === 'count_by')
1210
- {
1211
- $options['conditions'] = SQLBuilder::create_conditions_from_underscored_string(static::table()->conn,substr($method,9),$args,static::$alias_attribute);
1212
- return static::count($options);
1213
- }
1214
-
1215
- throw new ActiveRecordException("Call to undefined method: $method");
1216
- }
1217
-
1218
- /**
1219
- * Enables the use of build|create for associations.
1220
- *
1221
- * @param string $method Name of method
1222
- * @param mixed $args Method args
1223
- * @return mixed An instance of a given {@link AbstractRelationship}
1224
- */
1225
- public function __call($method, $args)
1226
- {
1227
- //check for build|create_association methods
1228
- if (preg_match('/(build|create)_/', $method))
1229
- {
1230
- if (!empty($args))
1231
- $args = $args[0];
1232
-
1233
- $association_name = str_replace(array('build_', 'create_'), '', $method);
1234
-
1235
- if (($association = static::table()->get_relationship($association_name)))
1236
- {
1237
- //access association to ensure that the relationship has been loaded
1238
- //so that we do not double-up on records if we append a newly created
1239
- $this->$association_name;
1240
- $method = str_replace($association_name,'association', $method);
1241
- return $association->$method($this, $args);
1242
- }
1243
- }
1244
-
1245
- throw new ActiveRecordException("Call to undefined method: $method");
1246
- }
1247
-
1248
- /**
1249
- * Alias for self::find('all').
1250
- *
1251
- * @see find
1252
- * @return array array of records found
1253
- */
1254
- public static function all(/* ... */)
1255
- {
1256
- return call_user_func_array('static::find',array_merge(array('all'),func_get_args()));
1257
- }
1258
-
1259
- /**
1260
- * Get a count of qualifying records.
1261
- *
1262
- * <code>
1263
- * YourModel::count(array('conditions' => 'amount > 3.14159265'));
1264
- * </code>
1265
- *
1266
- * @see find
1267
- * @return int Number of records that matched the query
1268
- */
1269
- public static function count(/* ... */)
1270
- {
1271
- $args = func_get_args();
1272
- $options = static::extract_and_validate_options($args);
1273
- $options['select'] = 'COUNT(*)';
1274
-
1275
- if (!empty($args))
1276
- {
1277
- if (is_hash($args[0]))
1278
- $options['conditions'] = $args[0];
1279
- else
1280
- $options['conditions'] = call_user_func_array('static::pk_conditions',$args);
1281
- }
1282
-
1283
- $table = static::table();
1284
- $sql = $table->options_to_sql($options);
1285
- $values = $sql->get_where_values();
1286
- return $table->conn->query_and_fetch_one($sql->to_s(),$values);
1287
- }
1288
-
1289
- /**
1290
- * Determine if a record exists.
1291
- *
1292
- * <code>
1293
- * SomeModel::exists(123);
1294
- * SomeModel::exists(array('conditions' => array('id=? and name=?', 123, 'Tito')));
1295
- * SomeModel::exists(array('id' => 123, 'name' => 'Tito'));
1296
- * </code>
1297
- *
1298
- * @see find
1299
- * @return boolean
1300
- */
1301
- public static function exists(/* ... */)
1302
- {
1303
- return call_user_func_array('static::count',func_get_args()) > 0 ? true : false;
1304
- }
1305
-
1306
- /**
1307
- * Alias for self::find('first').
1308
- *
1309
- * @see find
1310
- * @return Model The first matched record or null if not found
1311
- */
1312
- public static function first(/* ... */)
1313
- {
1314
- return call_user_func_array('static::find',array_merge(array('first'),func_get_args()));
1315
- }
1316
-
1317
- /**
1318
- * Alias for self::find('last')
1319
- *
1320
- * @see find
1321
- * @return Model The last matched record or null if not found
1322
- */
1323
- public static function last(/* ... */)
1324
- {
1325
- return call_user_func_array('static::find',array_merge(array('last'),func_get_args()));
1326
- }
1327
-
1328
- /**
1329
- * Find records in the database.
1330
- *
1331
- * Finding by the primary key:
1332
- *
1333
- * <code>
1334
- * # queries for the model with id=123
1335
- * YourModel::find(123);
1336
- *
1337
- * # queries for model with id in(1,2,3)
1338
- * YourModel::find(1,2,3);
1339
- *
1340
- * # finding by pk accepts an options array
1341
- * YourModel::find(123,array('order' => 'name desc'));
1342
- * </code>
1343
- *
1344
- * Finding by using a conditions array:
1345
- *
1346
- * <code>
1347
- * YourModel::find('first', array('conditions' => array('name=?','Tito'),
1348
- * 'order' => 'name asc'))
1349
- * YourModel::find('all', array('conditions' => 'amount > 3.14159265'));
1350
- * YourModel::find('all', array('conditions' => array('id in(?)', array(1,2,3))));
1351
- * </code>
1352
- *
1353
- * Finding by using a hash:
1354
- *
1355
- * <code>
1356
- * YourModel::find(array('name' => 'Tito', 'id' => 1));
1357
- * YourModel::find('first',array('name' => 'Tito', 'id' => 1));
1358
- * YourModel::find('all',array('name' => 'Tito', 'id' => 1));
1359
- * </code>
1360
- *
1361
- * An options array can take the following parameters:
1362
- *
1363
- * <ul>
1364
- * <li><b>select:</b> A SQL fragment for what fields to return such as: '*', 'people.*', 'first_name, last_name, id'</li>
1365
- * <li><b>joins:</b> A SQL join fragment such as: 'JOIN roles ON(roles.user_id=user.id)' or a named association on the model</li>
1366
- * <li><b>include:</b> TODO not implemented yet</li>
1367
- * <li><b>conditions:</b> A SQL fragment such as: 'id=1', array('id=1'), array('name=? and id=?','Tito',1), array('name IN(?)', array('Tito','Bob')),
1368
- * array('name' => 'Tito', 'id' => 1)</li>
1369
- * <li><b>limit:</b> Number of records to limit the query to</li>
1370
- * <li><b>offset:</b> The row offset to return results from for the query</li>
1371
- * <li><b>order:</b> A SQL fragment for order such as: 'name asc', 'name asc, id desc'</li>
1372
- * <li><b>readonly:</b> Return all the models in readonly mode</li>
1373
- * <li><b>group:</b> A SQL group by fragment</li>
1374
- * </ul>
1375
- *
1376
- * @throws {@link RecordNotFound} if no options are passed or finding by pk and no records matched
1377
- * @return mixed An array of records found if doing a find_all otherwise a
1378
- * single Model object or null if it wasn't found. NULL is only return when
1379
- * doing a first/last find. If doing an all find and no records matched this
1380
- * will return an empty array.
1381
- */
1382
- public static function find(/* $type, $options */)
1383
- {
1384
- $class = get_called_class();
1385
-
1386
- if (func_num_args() <= 0)
1387
- throw new RecordNotFound("Couldn't find $class without an ID");
1388
-
1389
- $args = func_get_args();
1390
- $options = static::extract_and_validate_options($args);
1391
- $num_args = count($args);
1392
- $single = true;
1393
-
1394
- if ($num_args > 0 && ($args[0] === 'all' || $args[0] === 'first' || $args[0] === 'last'))
1395
- {
1396
- switch ($args[0])
1397
- {
1398
- case 'all':
1399
- $single = false;
1400
- break;
1401
-
1402
- case 'last':
1403
- if (!array_key_exists('order',$options))
1404
- $options['order'] = join(' DESC, ',static::table()->pk) . ' DESC';
1405
- else
1406
- $options['order'] = SQLBuilder::reverse_order($options['order']);
1407
-
1408
- // fall thru
1409
-
1410
- case 'first':
1411
- $options['limit'] = 1;
1412
- $options['offset'] = 0;
1413
- break;
1414
- }
1415
-
1416
- $args = array_slice($args,1);
1417
- $num_args--;
1418
- }
1419
- //find by pk
1420
- elseif (1 === count($args) && 1 == $num_args)
1421
- $args = $args[0];
1422
-
1423
- // anything left in $args is a find by pk
1424
- if ($num_args > 0 && !isset($options['conditions']))
1425
- return static::find_by_pk($args, $options);
1426
-
1427
- $options['mapped_names'] = static::$alias_attribute;
1428
- $list = static::table()->find($options);
1429
-
1430
- return $single ? (!empty($list) ? $list[0] : null) : $list;
1431
- }
1432
-
1433
- /**
1434
- * Finder method which will find by a single or array of primary keys for this model.
1435
- *
1436
- * @see find
1437
- * @param array $values An array containing values for the pk
1438
- * @param array $options An options array
1439
- * @return Model
1440
- * @throws {@link RecordNotFound} if a record could not be found
1441
- */
1442
- public static function find_by_pk($values, $options)
1443
- {
1444
- $options['conditions'] = static::pk_conditions($values);
1445
- $list = static::table()->find($options);
1446
- $results = count($list);
1447
-
1448
- if ($results != ($expected = count($values)))
1449
- {
1450
- $class = get_called_class();
1451
-
1452
- if ($expected == 1)
1453
- {
1454
- if (!is_array($values))
1455
- $values = array($values);
1456
-
1457
- throw new RecordNotFound("Couldn't find $class with ID=" . join(',',$values));
1458
- }
1459
-
1460
- $values = join(',',$values);
1461
- throw new RecordNotFound("Couldn't find all $class with IDs ($values) (found $results, but was looking for $expected)");
1462
- }
1463
- return $expected == 1 ? $list[0] : $list;
1464
- }
1465
-
1466
- /**
1467
- * Find using a raw SELECT query.
1468
- *
1469
- * <code>
1470
- * YourModel::find_by_sql("SELECT * FROM people WHERE name=?",array('Tito'));
1471
- * YourModel::find_by_sql("SELECT * FROM people WHERE name='Tito'");
1472
- * </code>
1473
- *
1474
- * @param string $sql The raw SELECT query
1475
- * @param array $values An array of values for any parameters that needs to be bound
1476
- * @return array An array of models
1477
- */
1478
- public static function find_by_sql($sql, $values=null)
1479
- {
1480
- return static::table()->find_by_sql($sql, $values, true);
1481
- }
1482
-
1483
- /**
1484
- * Determines if the specified array is a valid ActiveRecord options array.
1485
- *
1486
- * @param array $array An options array
1487
- * @param bool $throw True to throw an exception if not valid
1488
- * @return boolean True if valid otherwise valse
1489
- * @throws {@link ActiveRecordException} if the array contained any invalid options
1490
- */
1491
- public static function is_options_hash($array, $throw=true)
1492
- {
1493
- if (is_hash($array))
1494
- {
1495
- $keys = array_keys($array);
1496
- $diff = array_diff($keys,self::$VALID_OPTIONS);
1497
-
1498
- if (!empty($diff) && $throw)
1499
- throw new ActiveRecordException("Unknown key(s): " . join(', ',$diff));
1500
-
1501
- $intersect = array_intersect($keys,self::$VALID_OPTIONS);
1502
-
1503
- if (!empty($intersect))
1504
- return true;
1505
- }
1506
- return false;
1507
- }
1508
-
1509
- /**
1510
- * Returns a hash containing the names => values of the primary key.
1511
- *
1512
- * @internal This needs to eventually support composite keys.
1513
- * @param mixed $args Primary key value(s)
1514
- * @return array An array in the form array(name => value, ...)
1515
- */
1516
- public static function pk_conditions($args)
1517
- {
1518
- $table = static::table();
1519
- $ret = array($table->pk[0] => $args);
1520
- return $ret;
1521
- }
1522
-
1523
- /**
1524
- * Pulls out the options hash from $array if any.
1525
- *
1526
- * @internal DO NOT remove the reference on $array.
1527
- * @param array &$array An array
1528
- * @return array A valid options array
1529
- */
1530
- public static function extract_and_validate_options(array &$array)
1531
- {
1532
- $options = array();
1533
-
1534
- if ($array)
1535
- {
1536
- $last = &$array[count($array)-1];
1537
-
1538
- try
1539
- {
1540
- if (self::is_options_hash($last))
1541
- {
1542
- array_pop($array);
1543
- $options = $last;
1544
- }
1545
- }
1546
- catch (ActiveRecordException $e)
1547
- {
1548
- if (!is_hash($last))
1549
- throw $e;
1550
-
1551
- $options = array('conditions' => $last);
1552
- }
1553
- }
1554
- return $options;
1555
- }
1556
-
1557
- /**
1558
- * Returns a JSON representation of this model.
1559
- *
1560
- * @see Serialization
1561
- * @param array $options An array containing options for json serialization (see {@link Serialization} for valid options)
1562
- * @return string JSON representation of the model
1563
- */
1564
- public function to_json(array $options=array())
1565
- {
1566
- return $this->serialize('Json', $options);
1567
- }
1568
-
1569
- /**
1570
- * Returns an XML representation of this model.
1571
- *
1572
- * @see Serialization
1573
- * @param array $options An array containing options for xml serialization (see {@link Serialization} for valid options)
1574
- * @return string XML representation of the model
1575
- */
1576
- public function to_xml(array $options=array())
1577
- {
1578
- return $this->serialize('Xml', $options);
1579
- }
1580
-
1581
- /**
1582
- * Creates a serializer based on pre-defined to_serializer()
1583
- *
1584
- * An options array can take the following parameters:
1585
- *
1586
- * <ul>
1587
- * <li><b>only:</b> a string or array of attributes to be included.</li>
1588
- * <li><b>excluded:</b> a string or array of attributes to be excluded.</li>
1589
- * <li><b>methods:</b> a string or array of methods to invoke. The method's name will be used as a key for the final attributes array
1590
- * along with the method's returned value</li>
1591
- * <li><b>include:</b> a string or array of associated models to include in the final serialized product.</li>
1592
- * </ul>
1593
- *
1594
- * @param string $type Either Xml or Json
1595
- * @param array $options Options array for the serializer
1596
- * @return string Serialized representation of the model
1597
- */
1598
- private function serialize($type, $options)
1599
- {
1600
- require_once 'Serialization.php';
1601
- $class = "ActiveRecord\\{$type}Serializer";
1602
- $serializer = new $class($this, $options);
1603
- return $serializer->to_s();
1604
- }
1605
-
1606
- /**
1607
- * Invokes the specified callback on this model.
1608
- *
1609
- * @param string $method_name Name of the call back to run.
1610
- * @param boolean $must_exist Set to true to raise an exception if the callback does not exist.
1611
- * @return boolean True if invoked or null if not
1612
- */
1613
- private function invoke_callback($method_name, $must_exist=true)
1614
- {
1615
- return static::table()->callback->invoke($this,$method_name,$must_exist);
1616
- }
1617
-
1618
- /**
1619
- * Executes a block of code inside a database transaction.
1620
- *
1621
- * <code>
1622
- * YourModel::transaction(function()
1623
- * {
1624
- * YourModel::create(array("name" => "blah"));
1625
- * });
1626
- * </code>
1627
- *
1628
- * If an exception is thrown inside the closure the transaction will
1629
- * automatically be rolled back. You can also return false from your
1630
- * closure to cause a rollback:
1631
- *
1632
- * <code>
1633
- * YourModel::transaction(function()
1634
- * {
1635
- * YourModel::create(array("name" => "blah"));
1636
- * throw new Exception("rollback!");
1637
- * });
1638
- *
1639
- * YourModel::transaction(function()
1640
- * {
1641
- * YourModel::create(array("name" => "blah"));
1642
- * return false; # rollback!
1643
- * });
1644
- * </code>
1645
- *
1646
- * @param Closure $closure The closure to execute. To cause a rollback have your closure return false or throw an exception.
1647
- * @return boolean True if the transaction was committed, False if rolled back.
1648
- */
1649
- public static function transaction($closure)
1650
- {
1651
- $connection = static::connection();
1652
-
1653
- try
1654
- {
1655
- $connection->transaction();
1656
-
1657
- if ($closure() === false)
1658
- {
1659
- $connection->rollback();
1660
- return false;
1661
- }
1662
- else
1663
- $connection->commit();
1664
- }
1665
- catch (\Exception $e)
1666
- {
1667
- $connection->rollback();
1668
- throw $e;
1669
- }
1670
- return true;
1671
- }
1672
- };
1673
- ?>