Subversion Repositories PHPX

Rev

Rev 65 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 65 Rev 67
1
<?php
1
<?php
2
2
3
namespace PointedEars\PHPX;
3
namespace PointedEars\PHPX;
4
4
5
/**
5
/**
6
* Abstract model class for Object-Relational Mapping
6
* Abstract model class for Object-Relational Mapping
7
*
7
*
8
* Provides simple mapping of a model object to records of
8
* Provides simple mapping of a model object to records of
9
* a table of a relational database.
9
* a table of a relational database.
10
*
10
*
11
* @property Db\Table $persistentTable
11
* @property Db\Table $persistentTable
12
* @author Thomas Lahn
12
* @author Thomas Lahn
13
*/
13
*/
14
abstract class Model extends \PointedEars\PHPX\AbstractModel
14
abstract class Model extends \PointedEars\PHPX\AbstractModel
15
{
15
{
16
  /**
16
  /**
17
   * The <code>Table</code> for instances of this model
17
   * The <code>Table</code> for instances of this model
18
   *
18
   *
19
   * @type Table|string
19
   * @type Table|string
20
   */
20
   */
21
        protected static $_persistentTable;
21
        protected static $_persistentTable;
22
22
23
  /**
23
  /**
24
   * The name(s) of the property or properties whose value(s)
24
   * The name(s) of the property or properties whose value(s)
25
   * identify this object in the <code>Table</code>.  They are
25
   * identify this object in the <code>Table</code>.  They are
26
   * used for comparing against the primary key column(s) of
26
   * used for comparing against the primary key column(s) of
27
   * the <code>Table</code>.
27
   * the <code>Table</code>.
28
   *
28
   *
29
   * @type string|array[string]
29
   * @type string|array[string]
30
   */
30
   */
31
        protected static $_persistentId = 'id';
31
        protected static $_persistentId = 'id';
32
32
33
  /**
33
  /**
34
   * The names of the properties that should be used in database
34
   * The names of the properties that should be used in database
35
   * queries, and their mapping to the columns of
35
   * queries, and their mapping to the columns of
36
   * the <code>Table</code>, if specified (keys are property names,
36
   * the <code>Table</code>, if specified (keys are property names,
37
   * values are column names, or both if the key is numeric).
37
   * values are column names, or both if the key is numeric).
38
   *
38
   *
39
   * NOTE: It should not be necessary to include the
39
   * NOTE: It should not be necessary to include the
40
   * <code>persistentId</code> property value here.  If an object
40
   * <code>persistentId</code> property value here.  If an object
41
   * is not in the database, it should be assigned an ID
41
   * is not in the database, it should be assigned an ID
42
   * automatically when saved; if it is in the database,
42
   * automatically when saved; if it is in the database,
43
   * you already have its ID as you searched by it.
43
   * you already have its ID as you searched by it.
44
   *
44
   *
45
   * @type array
45
   * @type array
46
   */
46
   */
47
  protected static $_persistentProperties = array();
47
  protected static $_persistentProperties = array();
48
48
49
        /**
49
        /**
50
   * Creates a new model object
50
   * Creates a new model object
51
   *
51
   *
52
   * @see AbstractModel::__construct()
52
   * @see AbstractModel::__construct()
53
   */
53
   */
54
  public function __construct (
54
  public function __construct (
55
    array $data = null, array $mapping = null, $exclusiveMapping = false)
55
    array $data = null, array $mapping = null, $exclusiveMapping = false)
56
  {
56
  {
57
    parent::__construct($data, $mapping, $exclusiveMapping);
57
    parent::__construct($data, $mapping, $exclusiveMapping);
58
  }
58
  }
59
59
60
  public function getPersistentTable ()
60
  public function getPersistentTable ()
61
  {
61
  {
62
        $class = \get_class($this);
62
        $class = \get_class($this);
63
        if (\is_string($class::$_persistentTable))
63
        if (\is_string($class::$_persistentTable))
64
        {
64
        {
65
                /* Call setter to convert to Table */
65
                /* Call setter to convert to Table */
66
                $this->setPersistentTable($class::$_persistentTable);
66
                $this->setPersistentTable($class::$_persistentTable);
67
        }
67
        }
68
68
69
        return $class::$_persistentTable;
69
        return $class::$_persistentTable;
70
  }
70
  }
71
71
72
  public function setPersistentTable ($value)
72
  public function setPersistentTable ($value)
73
  {
73
  {
74
        $class = \get_class($this);
74
        $class = \get_class($this);
75
        if ($value instanceof Table)
75
        if ($value instanceof Table)
76
        {
76
        {
77
                $class::$_persistentTable = $value;
77
                $class::$_persistentTable = $value;
78
        }
78
        }
79
        else
79
        else
80
        {
80
        {
81
                $table = new $value();
81
                $table = new $value();
82
                if (!($table instanceof Db\Table))
82
                if (!($table instanceof Db\Table))
83
                {
83
                {
84
                        throw new \InvalidArgumentException(
84
                        throw new \InvalidArgumentException(
85
                                'Parameter does not specify a subclass of \\PointedEars\\PHPX\\Table: '
85
                                'Parameter does not specify a subclass of \\PointedEars\\PHPX\\Table: '
86
                                . $value
86
                                . $value
87
                        );
87
                        );
88
                }
88
                }
89
89
90
                $class::$_persistentTable = $table;
90
                $class::$_persistentTable = $table;
91
        }
91
        }
92
  }
92
  }
93
93
94
  /**
94
  /**
-
 
95
   * Returns an array containing the property-column mapping.
-
 
96
   *
-
 
97
   * @param array $propertyNames = null
-
 
98
   *   Names of the properties that should be included.
-
 
99
   *   The default is to include all persistent properties.
-
 
100
   * @return array
-
 
101
   */
-
 
102
  public static function getPersistentMapping (array $propertyNames = null)
-
 
103
  {
-
 
104
    $a = array();
-
 
105
-
 
106
        $persistent_properties = static::$_persistentProperties;
-
 
107
-
 
108
        if ($propertyNames === null)
-
 
109
        {
-
 
110
                $propertyNames = $persistent_properties;
-
 
111
        }
-
 
112
-
 
113
        foreach ($propertyNames as $property_name)
-
 
114
        {
-
 
115
          if (!array_key_exists($property_name, $persistent_properties))
-
 
116
          {
-
 
117
                        $column_name = $property_name;
-
 
118
          }
-
 
119
          else
-
 
120
          {
-
 
121
            $column_name = $persistent_properties[$property_name];
-
 
122
          }
-
 
123
-
 
124
                $a[$property_name] = $column_name;
-
 
125
        }
-
 
126
-
 
127
        return $a;
-
 
128
  }
-
 
129
-
 
130
  /**
95
   * Returns an array for database queries containing the
131
   * Returns an array for database queries containing the
96
   * property values of this object, using the specified
132
   * property values of this object, using the specified
97
   * property-to-column mapping.
133
   * property-to-column mapping.
98
   *
134
   *
99
   * @param array $propertyNames = null
135
   * @param array $propertyNames = null
100
   *   Names of the properties that should be included.
136
   *   Names of the properties that should be included.
101
   *   The default is to include all persistent properties.
137
   *   The default is to include all persistent properties.
102
   * @return array
138
   * @return array
103
   */
139
   */
104
  public function getPropertyArray (array $propertyNames = null)
140
  public function getPropertyArray (array $propertyNames = null)
105
  {
141
  {
106
        $a = array();
142
        $a = array();
107
143
108
        if ($propertyNames === null)
144
        if ($propertyNames === null)
109
        {
145
        {
110
                $class = \get_class($this);
146
                $class = \get_class($this);
111
                $propertyNames = $class::$_persistentProperties;
147
                $propertyNames = $class::$_persistentProperties;
112
        }
148
        }
113
149
114
        foreach ($propertyNames as $propertyName => $columnName)
150
        foreach ($propertyNames as $propertyName => $columnName)
115
        {
151
        {
116
                if (is_numeric($propertyName))
152
                if (is_numeric($propertyName))
117
                {
153
                {
118
                        $propertyName = $columnName;
154
                        $propertyName = $columnName;
119
                }
155
                }
120
156
121
                $a[$columnName] = $this->$propertyName;
157
                $a[$columnName] = $this->$propertyName;
122
        }
158
        }
123
159
124
        return $a;
160
        return $a;
125
  }
161
  }
126
162
127
  /**
163
  /**
128
   * Finds the record for the model object in the table, fills
164
   * Finds the record for the model object in the table, fills
129
   * the object with missing data, and returns the result.
165
   * the object with missing data, and returns the result.
130
   *
166
   *
131
   * @param mixed $id = null
167
   * @param mixed $id = null
132
   *   The ID of the object to find.  If <code>null</code> (default),
168
   *   The ID of the object to find.  If <code>null</code> (default),
133
   *   the object is search for by its current ID.
169
   *   the object is searched for by its current ID.
134
   * @see Table::find(Model)
-
 
135
   * @return Model|null
170
   * @return Model|null
136
   *   This object filled with missing data, or <code>null</code>
171
   *   This object filled with missing data, or <code>null</code>
137
   *   if there is no data for this object
172
   *   if there is no data for this object
138
   * @see Table::find(Model)
173
   * @see Table::find(int)
139
   */
174
   */
140
  public function find ($id = null)
175
  public function find ($id = null)
141
  {
176
  {
142
        $class = \get_class($this);
177
        $class = \get_class($this);
143
        if ($id === null)
178
        if ($id === null)
144
        {
179
        {
145
          $id = $this->{$class::$_persistentId};
180
          $id = $this->{$class::$_persistentId};
146
        }
181
        }
147
182
148
    $result = $this->persistentTable->find($id);
183
    $result = $this->persistentTable->find($id);
149
    if ($id !== null)
184
    if ($id !== null)
150
    {
185
    {
151
      $this->{$class::$_persistentId} = $id;
186
      $this->{$class::$_persistentId} = $id;
152
    }
187
    }
153
188
154
    $result = $this->persistentTable->find($this->{$class::$_persistentId});
189
    $result = $this->persistentTable->find($this->{$class::$_persistentId});
155
    if ($result)
190
    if ($result)
156
    {
191
    {
157
        return $this->map($result);
192
        return $this->map($result);
158
    }
193
    }
-
 
194
-
 
195
    return null;
-
 
196
  }
-
 
197
-
 
198
  /**
-
 
199
   * Finds the records for model objects in the table by value,
-
 
200
   * and returns the result.
-
 
201
   *
-
 
202
   * @param string $name
-
 
203
   *   Name of the property to search for.
-
 
204
   * @param mixed $value = null
-
 
205
   *   The property value to find.  If <code>null</code>,
-
 
206
   *   the current value of the specified property is used.
-
 
207
   *   (To search for null, you need to make sure that the
-
 
208
   *   current property value is <code>null</code>, which is
-
 
209
   *   the PHP default.)
-
 
210
   * @return array[Model]|null
-
 
211
   *   Model objects, or <code>null</code> if there is no data
-
 
212
   *   for this property and value
-
 
213
   * @see Table::select(Model)
-
 
214
   */
-
 
215
  public function findByProperty ($name, $value = null)
-
 
216
  {
-
 
217
    $class = \get_class($this);
-
 
218
        $mapping = $class::getPersistentMapping(array($name));
-
 
219
-
 
220
        if ($value === null)
-
 
221
        {
-
 
222
          $value = $this->$name;
-
 
223
        }
-
 
224
-
 
225
    $results = $this->persistentTable->select(null,
-
 
226
      array($mapping[$name] => $value));
-
 
227
-
 
228
    if ($results)
-
 
229
    {
-
 
230
        return array_map(array($this, 'map'), $results);
-
 
231
    }
159
232
160
    return null;
233
    return null;
161
  }
234
  }
162
235
163
  /**
236
  /**
164
   * Saves the model object in the table
237
   * Saves the model object in the table
165
   *
238
   *
166
   * @param array $propertyNames = null
239
   * @param array $propertyNames = null
167
   *   Names of the properties whose values should be saved
240
   *   Names of the properties whose values should be saved
168
   *   in the database.  The default is to save the values
241
   *   in the database.  The default is to save the values
169
   *   of all persistent properties.
242
   *   of all persistent properties.
170
   * @return boolean
243
   * @return boolean
171
   *   The return value of
244
   *   The return value of
172
   *   <code>$this->persistentTable->updateOrInsert()</code>.
245
   *   <code>$this->persistentTable->updateOrInsert()</code>.
173
   * @see Model::getPropertyArray()
246
   * @see Model::getPropertyArray()
174
   * @see Table::updateOrInsert()
247
   * @see Table::updateOrInsert()
175
   */
248
   */
176
  public function save (array $propertyNames = null)
249
  public function save (array $propertyNames = null)
177
  {
250
  {
178
        $table = $this->persistentTable;
251
        $table = $this->persistentTable;
179
        $class = \get_class($this);
252
        $class = \get_class($this);
180
        $idPropertyName = $class::$_persistentId;
253
        $idPropertyName = $class::$_persistentId;
181
254
182
        $result = $table->updateOrInsert(
255
        $result = $table->updateOrInsert(
183
                $this->getPropertyArray($propertyNames),
256
                $this->getPropertyArray($propertyNames),
184
                array(
257
                array(
185
                        $table->id => $this->$idPropertyName
258
                        $table->id => $this->$idPropertyName
186
                )
259
                )
187
        );
260
        );
188
261
189
        if ($result && ($lastInsertId = $table->lastInsertId))
262
        if ($result && ($lastInsertId = $table->lastInsertId))
190
        {
263
        {
191
                $this->$idPropertyName = $lastInsertId;
264
                $this->$idPropertyName = $lastInsertId;
192
        }
265
        }
193
266
194
        return $result;
267
        return $result;
195
  }
268
  }
196
269
197
  /**
270
  /**
198
   * Inserts the model object into the table
271
   * Inserts the model object into the table
199
   *
272
   *
200
   * @param array $propertyNames = null
273
   * @param array $propertyNames = null
201
   *   Names of the properties whose values should be insert
274
   *   Names of the properties whose values should be insert
202
   *   in the database.  The default is to insert the values
275
   *   in the database.  The default is to insert the values
203
   *   of all persistent properties.
276
   *   of all persistent properties.
204
   * @return boolean
277
   * @return boolean
205
   * @see Model::getPropertyArray()
278
   * @see Model::getPropertyArray()
206
   * @see Table::insert()
279
   * @see Table::insert()
207
   */
280
   */
208
  public function insert (array $propertyNames = null)
281
  public function insert (array $propertyNames = null)
209
  {
282
  {
210
        $table = $this->persistentTable;
283
        $table = $this->persistentTable;
211
        $class = \get_class($this);
284
        $class = \get_class($this);
212
        $idPropertyName = $class::$_persistentId;
285
        $idPropertyName = $class::$_persistentId;
213
286
214
        $result = $table->insert($this->getPropertyArray($propertyNames));
287
        $result = $table->insert($this->getPropertyArray($propertyNames));
215
288
216
        if ($result && ($lastInsertId = $table->lastInsertId))
289
        if ($result && ($lastInsertId = $table->lastInsertId))
217
        {
290
        {
218
                $this->$idPropertyName = $lastInsertId;
291
                $this->$idPropertyName = $lastInsertId;
219
        }
292
        }
220
293
221
        return $result;
294
        return $result;
222
  }
295
  }
223
296
224
  /**
297
  /**
225
   * Deletes a model object from the <code>Table</code>
298
   * Deletes a model object from the <code>Table</code>
226
   *
299
   *
227
   * @return bool
300
   * @return bool
228
   * @see Table::delete()
301
   * @see Table::delete()
229
   */
302
   */
230
  public function delete ()
303
  public function delete ()
231
  {
304
  {
232
        $class = \get_class($this);
305
        $class = \get_class($this);
233
        return $this->persistentTable->delete($this->{$class::$_persistentId});
306
        return $this->persistentTable->delete($this->{$class::$_persistentId});
234
  }
307
  }
235
}
308
}
236
 
309