dataobjects

Gesponsorde koppelingen

PHP script bestanden

  1. dataobjects

« Lees de omschrijving en reacties

De toegangspoort: een echte klassieke Database-klasse

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
class DatabaseException extends Exception {
   public function __construct($link, $message, $sql = '') {
      $this->sql = $sql;
      $this->errmsg = mysql_error($link);
      parent::__construct($message, mysql_errno($link));
   }


   public function getErrorMessage() {
      return $this->errmsg;
   }


   public function getSQL() {
      return $this->sql;
   }
}


class Database {
   const FETCH_ALL = 2;

   private $handle;
   static private $queries = array();

   /* wat debug-functies, altijd handig */
   static public function getQueryCount() {
      return count(self::$queries);
   }


   static public function getQueries() {
      return self::$queries;
   }


   public function __construct($host, $username, $password, $database) {
      if(!($this->handle = mysql_connect($host, $username, $password))) {
         throw new DatabaseException($this->handle, 'Ik heb een kuthost die even niet zo vriendelijk is om een databaseverbinding voor mijn site beschikbaar te houden! :@');
      }

      if(!mysql_select_db($database, $this->handle)) {
         throw new DatabaseException($this->handle, 'Could not select Database');
      }
   }


   public function query($sql) {
      if(!($result = mysql_query($sql, $this->handle))) {
         throw new DatabaseException($this->handle, 'Error while executing query', $sql);
      }
else {
         self::$queries[] = $sql . '<br>hits: ' . @mysql_num_rows($result) . '/' . @mysql_affected_rows($result);
         return $result;
      }
   }

  
   /* vooral gebruikt in self::prepareSQL */
   public function quote($value) {
      $specialValues = array(
      'NOW()', 'TRUE', 'FALSE'
      );
      if (get_magic_quotes_gpc()) {
         $value = stripslashes($value);
      }

      if(!in_array($value, $specialValues) && !is_int($value)) {
         $value = "'" . mysql_real_escape_string($value) . "'";
      }


      return $value;
   }


   /*
    * Verantwoordelijk voor de DatabaseObjecten.
    * (str) $decorator: naam van de decorator-klasse
    *  -- (moet afstammen van AbstractDataObject)
    * (str) $sql: het gedeelte dat na "WHERE" komt in een query
    * (arr) $args: Gaat samen met $sql naar self::prepareSQL()
    */

   public function fetch($decorator, $sql = null, $args = array()) {
      if($sql == null || $sql == Database::FETCH_ALL) {
         $sql = '1';
      }


      $dummyInstance = new $decorator;

      $refl_primaryKey = new ReflectionProperty($decorator, 'primaryKey');
      $primaryKey = $refl_primaryKey->getValue($dummyInstance);
      $refl_primaryKey = null;

      $refl_tableName = new ReflectionProperty($decorator, 'tableName');
      $tableName = $refl_tableName->getValue($dummyInstance);
      $refl_tableName = null;

      $sql = $this->prepareSQL('SELECT ' . $primaryKey . ' FROM ' . $tableName . ' WHERE ' . $sql, $args);
      $resultData = array_map('intval',$this->fetchCol($primaryKey, $sql));

      $dataset = new DataSet($resultData);
      $dataset->setPrimaryKey($primaryKey);
      $dataset->setTableName($tableName);
      $dataset->setDatabaseInstance($this);
      $dataset->setDecorator($decorator);

      return $dataset;
   }


   public function fetchAll($sql, $args = null) {
      $sql = $this->prepareSQL($sql, $args);
      $result = $this->query($sql);

      $buffer = array();

      while($row = mysql_fetch_assoc($result)) {
         $buffer[] = $row;
      }


      return $buffer;
   }


   public function fetchRow($sql, $args = null) {
      $sql = $this->prepareSQL($sql, $args);
      $result = $this->query($sql);

      return mysql_fetch_assoc($result);
   }


   public function fetchCol($field, $sql, $args = null) {
      $sql = $this->prepareSQL($sql, $args);
      $result = $this->query($sql);

      $rows = mysql_num_rows($result);

      $buffer = array();
      for($i = 0; $i < $rows; $i++) {
         $buffer[] = mysql_result($result, $i, $field);
      }

      return $buffer;
   }


   public function insert($table, $fields) {
      $buffer = array();
      foreach($fields as $key => $value) {
         $buffer[] = $key . '=' . $this->quote($value);
      }


      return $this->query('INSERT INTO ' . $table .' SET ' . implode(', ', $buffer));
   }


   public function update($table, $fields, $where = null) {
      $buffer = array();
      foreach($fields as $key => $value) {
         $buffer[] = $key . '=' . $this->quote($value);
      }


      $sql = 'UPDATE ' . $table . ' SET ' . implode(', ', $buffer);
      if(!is_null($where)) {
         $sql .= ' WHERE ' . $where;
      }


      $this->query($sql);
      return mysql_affected_rows($this->handle) > 0;
   }


   public function insertId() {
      return mysql_insert_id($this->handle);
   }


   /*
    * Verantwoordelijk voor het veilig maken van database-voer.
    * Gebruik in $sql :varname (let op dubbele punt!) en in $args
    * als key weer 'varname' en als waarde dat waar het door moet
    * worden vervangen.
    */

   public function prepareSQL($sql, $args = null) {
      if(!is_null($args)) {
         foreach($args as $key => $value) {
            $sql = str_replace(':'.$key . '', $this->quote($value), $sql);
         }
      }

      return $sql;
   }
}

?>


Deze is nodig voor DataSet, en maakt het onder andere mogelijk om foreach te gebruiken. Implementeert de interface Iterator, die teruggevonden kan worden in SPL.
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
abstract class AbstractIterator implements SeekableIterator, Countable
{
   protected $position;

   public function current()
   {

      if($this->hasIndexAt) {
         return $this->__getAtIndex($this->position);
      }
else {
         return $this->stack[$this->position];
      }
   }


   public function key()
   {

      return $this->position + 1;
   }


   public function next()
   {

      $this->position++;
   }


   /* niet onderdeel van de officiele implementatie */
   public function previous()
   {

      $this->position--;
   }


   public function rewind()
   {

      $this->position = 0;
   }


   /* niet onderdeel van de officiele implementatie */
   public function end()
   {

      $this->position = count($this->stack) - 1;
   }


   public function reset()
   {

      $this->rewind();
      $this->hasIndexAt = is_callable(array($this, '__getAtIndex'));
   }


   /* implementeert SeekableIterator */
   public function seek($position)
   {

      if($position > $this->count()) {
         throw new Exception('This DataSet has only ' . $this->count() . ' elements in stack. It is not posible to go to index ' . $position);
      }

      $this->position = $position;
   }


   /*
    * implementeert Countable.
    * nu kan je count($dirObject) gebruiken!
    */

   public function valid()
   {

      return isset($this->stack[$this->position]);
   }


   public function count()
   {

      return count($this->stack);
   }
}

?>


DataSet: de 'array' met alle DataObjecten, maar niet met de daadwerkelijke data. Hier worden tevens de DataObjecten gebakken en eventueel van inhoud voorzien. Vergeet niet buffer() op de juiste momenten aan te roepen! Dat komt de snelheid zeker ten goede!
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
class DataSet extends AbstractIterator
{
   const ALL = -1;

   private $databaseInstance;
   private $decorator;

   protected $tableName;
   protected $primaryKey;

   public function __construct($data = false)
   {

      $this->stack = is_array($data) ? $data : array();
      $this->reset();
   }


   protected function __getAtIndex($index)
   {

      $data = $this->stack[$index];
      if(!$data) {
         return false;
      }

      if(!is_object($data)) {
         return new $this->decorator($data, $this->databaseInstance);
      }
else {
         return $data;
      }
   }


   public function setDecorator($decorator)
   {

      $this->decorator = $decorator;
   }


   public function setDatabaseInstance(Database $instance)
   {

      $this->databaseInstance = $instance;
   }


   public function setPrimaryKey($key)
   {

      $this->primaryKey = $key;
   }


   public function setTableName($tableName)
   {

      $this->tableName = $tableName;
   }


   /* some filling-functions */

   public function buffer($length = false, $from = false)
   {

      if($this->count() < 1) {
         return;
      }


      if(!$from) {
         $from = $this->position + 1;
      }


      if(!$length) {
         $length = $this->count() - $from;
      }


      $ids = array();
      $items = array();
      $break = $from + $length;
      for($i = $from; $i < $break; $i++) {
         if(!isset($this->stack[$i])) break;       /* end of stack */
         if(is_object($this->stack[$i])) continue; /* already in cache */
         array_push($items, $i);
         array_push($ids, $this->stack[$i]);
      }


      if(count($ids) <= 1) {
         return;
      }


      $dummyInstance = new $this->decorator;

      if(!$this->primaryKey) {
         $refl_primaryKey = new ReflectionProperty($this->decorator, 'primaryKey');
         $this->primaryKey = $refl_primaryKey->getValue($dummyInstance);
         $refl_primaryKey = null;
      }


      if(!$this->tableName) {
         $refl_tableName = new ReflectionProperty($this->decorator, 'tableName');
         $this->tableName = $refl_tableName->getValue($dummyInstance);
         $refl_tableName = null;
      }


      $results = $this->databaseInstance->fetchAll('SELECT * FROM ' . $this->tableName . ' WHERE ' . $this->primaryKey . ' IN(' . join(', ', $ids) . ')');
      foreach($results as $result) {
         $index = array_search(intval($result[$this->primaryKey]), $ids);
         $entryObject = new $this->decorator();
         $entryObject->setRawData($result);
         $entryObject->setDatabaseInstance($this->databaseInstance);
         $this->stack[$items[$index]] = $entryObject;
      }
   }


   public function push($item)
   {

      return array_push($this->stack, $item);
   }


   public function pop()
   {

      $data = array_pop($this->stack);
      if(!$data) {
         return false;
      }

      if(is_object($data)) {
         return $data;
      }
else {
         return new $this->decorator($data, $this->databaseInstance);
      }
   }
}

?>


Het abstracte DataObject. Werkt natuurlijk niet stand-alone, simpelweg omdat hij niet weet hoe zijn MySQL-tabel eruit ziet. Deze moet je dus extenden. En als bonus: ook hier een iterator! Ook hier kan je foreach op los laten! Nooit meer je aliassen onthouden! Wat is programmeren toch een heerlijk lui en simpel gebeuren ;)
Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
abstract class AbstractDataObject implements Iterator {
   const READ_ONLY = 2;

   const STRING = 3;
   const INT = 4;
   const FLOAT = 5;

   private $data = array();
   private $databaseInstance;
   private $_isNew = true;
   private $iteratorPosition = -1;
   private $iteratorKeys = array();


   /*
    * Te gebruiken in de kinderen van deze klasse.
    * Haalt gegevens uit de db en vult zichzelf ermee.
    */

   protected function populate($conditions, $parameters = array())
   {

      if(!$this->databaseInstance) {
         /*
          * Deze mag je lekker zelf implementeren.
          * Een hint: Registery Pattern
          *
          * $this->databaseInstance = Base::acquire('database');
          */

          throw new Exception('No databaseInstance available');
      }


      $selectedFields = array();
      $temporaryAliasses = array();
      $i = 0;

      foreach($this->tableStructure as $alias => $column) {
         $tempAlias = 'alias'.$i++;
         $temporaryAliasses[$tempAlias] = $column[0];
         $selectedFields[] = $column[0] . ' as ' . $tempAlias;
      }


      $data = $this->databaseInstance->fetchRow('SELECT ' . implode(', ', $selectedFields) . ' FROM ' . $this->tableName . ' WHERE '.$conditions.' LIMIT 1', $parameters);

      if(!$data) {
         return false;
      }


      foreach($data as $tempAlias => $value) {
         $this->data[$temporaryAliasses[$tempAlias]] = $value;
      }


      $this->_isNew = false;

      return true;
   }


   public function setDatabaseInstance($databaseInstance)
   {

      $this->databaseInstance = $databaseInstance;
   }

  
   /*
    * Voor de db masterclass, om direct alle gegevens erin te pushen.
    * Dit is in sommige gevallen efficienter
    */

   public function setRawData($data)
   {

      foreach($data as $key => $value) {
         $this->data[$key] = $value;
      }


      $this->_isNew = false;
   }

  
   /*
    * magic: indien functie $this->set{$Alias} beschikbaar is,
    * laat die het opslaan afhandele, anders kijken of we de waarde toevallig
    * in de tablestructure moet komen, en of dat wel mag (READ_ONLY)
    */

   public function __set($alias, $value) {
      $functionName = 'set'.ucfirst($alias);

      if(is_callable(array($this, $functionName))) {
         $value = call_user_func_array(array($this, $functionName), array($this->data, $value));
         if(!$value) {
            return false;
         }
      }
else {
         $key = $this->translate($alias);

         if(in_array(self::READ_ONLY, $this->tableStructure[$alias])) {
            throw new Exception("Field $alias (better known as $key) is marked as read only.");
         }


         $this->data[$key] = strval($this->convert($alias, $value));
         return true;
      }
   }


   /*
    * magic: indien functie $this->get{$Alias} beschikbaar is,
    * raadpleeg die, anders kijken of we de waarde toevallig
    * in de tablestructure hebben zitten.
    */

   public function __get($alias) {
      $functionName = 'get'.ucfirst($alias);

      if(is_callable(array($this, $functionName))) {
         return call_user_func_array(array($this, $functionName), array($this->data));
      }
else {
         return $this->convert($alias, $this->data[$this->translate($alias)]);
      }
   }



   /* Wijziginen opslaan */
   public function commit() {
      if(!$this->databaseInstance) {
         /*
          * Voor deze geldt hetzelfde
          * $this->databaseInstance = Base::acquire('database');
          */

          throw new Exception('No databaseInstance available');
      }


      if(empty($this->primaryKey)) {
         throw new Exception("No primary key found in table $this->tableName. A primary key is required to use this method.");
      }


      if(!empty($this->data[$this->primaryKey])) {
         return $this->databaseInstance->update($this->tableName, $this->data, $this->databaseInstance->prepareSQL($this->primaryKey . ' = :value', array('value' => intval($this->data[$this->primaryKey]))));
      }
else {
         if($this->databaseInstance->insert($this->tableName, $this->data)) {
            $this->data[$this->primaryKey] = $this->databaseInstance->insertId();
            return true;
         }
else {
            return false;
         }
      }
   }


   /*
    * Van alias (key in tablestructure) naar
    * veldnaam van db-tabel.
    */

   private function translate($key)
   {

      if(isset($this->tableStructure[$key])) {
         return $this->tableStructure[$key][0];
      }


      throw new Exception("Alias $key not found in \$tableStructure");
   }


  
   /*
    * Alles is een String waneer het uit de DB komt,
    * dus wij maken er een echte waarde van!
    */

   private function convert($key, $value)
   {

      if(isset($this->tableStructure[$key])) {
         $fieldSettings = $this->tableStructure[$key];
         switch(true) {
            case
in_array(self::INT, $fieldSettings):
               return intval($value);
            case
in_array(self::FLOAT, $fieldSettings):
               return floatval($value);
            case
in_array(self::STRING, $fieldSettings):
               if(is_callable(array($value, '__toString'))) {
                  return strval($value->__toString());
               }
else {
                  return strval($value);
               }
            default:

               return $value;
         }
      }
else {
         return $value;
      }
   }


   /*
    * callback functie, $object->isNew
    * reden: read-only
    */

  
   public function getIsNew() {
      return $this->_isNew;
   }


   /* Iterator implementatie */
  
   public function current()
   {

      return $this->__get($this->key());
   }


   public function key()
   {

      $keys = array_keys($this->tableStructure);
      return $keys[$this->iteratorPosition];
   }


   public function next()
   {

      $this->iteratorPosition++;
   }


   public function rewind()
   {

      $this->iteratorPosition = 0;
   }


   public function valid()
   {

      return $this->iteratorPosition < count($this->tableStructure);
   }
}

?>

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.