fwk /
Db
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Fwk |
||
| 4 | * |
||
| 5 | * Copyright (c) 2011-2012, Julien Ballestracci <[email protected]>. |
||
| 6 | * All rights reserved. |
||
| 7 | * |
||
| 8 | * For the full copyright and license information, please view the LICENSE |
||
| 9 | * file that was distributed with this source code. |
||
| 10 | * |
||
| 11 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||
| 12 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||
| 13 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
||
| 14 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
||
| 15 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
||
| 16 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
||
| 17 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||
| 18 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||
| 19 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
| 20 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
||
| 21 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
||
| 22 | * POSSIBILITY OF SUCH DAMAGE. |
||
| 23 | * |
||
| 24 | * PHP Version 5.3 |
||
| 25 | * |
||
| 26 | * @category Database |
||
| 27 | * @package Fwk\Db |
||
| 28 | * @author Julien Ballestracci <[email protected]> |
||
| 29 | * @copyright 2011-2012 Julien Ballestracci <[email protected]> |
||
| 30 | * @license http://www.opensource.org/licenses/bsd-license.php BSD License |
||
| 31 | * @link http://www.phpfwk.com |
||
| 32 | */ |
||
| 33 | namespace Fwk\Db; |
||
| 34 | |||
| 35 | use Fwk\Db\Registry\RegistryState; |
||
| 36 | use Fwk\Db\Relations\AbstractManyRelation; |
||
| 37 | use Fwk\Db\Relations\One2Many; |
||
| 38 | use Fwk\Db\Relations\One2One; |
||
| 39 | |||
| 40 | /** |
||
| 41 | * This class transforms a resultset from a query into a set of corresponding |
||
| 42 | * entities. |
||
| 43 | * |
||
| 44 | * @category Utilities |
||
| 45 | * @package Fwk\Db |
||
| 46 | * @author Julien Ballestracci <[email protected]> |
||
| 47 | * @license http://www.opensource.org/licenses/bsd-license.php BSD License |
||
| 48 | * @link http://www.phpfwk.com |
||
| 49 | */ |
||
| 50 | class Hydrator |
||
| 51 | { |
||
| 52 | /** |
||
| 53 | * The query |
||
| 54 | * |
||
| 55 | * @var Query |
||
| 56 | */ |
||
| 57 | protected $query; |
||
| 58 | |||
| 59 | /** |
||
| 60 | * The Connection |
||
| 61 | * |
||
| 62 | * @var Connection |
||
| 63 | */ |
||
| 64 | protected $connection; |
||
| 65 | |||
| 66 | /** |
||
| 67 | * Columns description |
||
| 68 | * |
||
| 69 | * @var array |
||
| 70 | */ |
||
| 71 | protected $columns; |
||
| 72 | |||
| 73 | /** |
||
| 74 | * Parsing stack informations |
||
| 75 | * |
||
| 76 | * @var array |
||
| 77 | */ |
||
| 78 | protected $stack; |
||
| 79 | |||
| 80 | /** |
||
| 81 | * Entities that need to be marked as fresh in registry |
||
| 82 | * |
||
| 83 | * @var array |
||
| 84 | */ |
||
| 85 | protected $markAsFresh; |
||
| 86 | |||
| 87 | /** |
||
| 88 | * Constructor |
||
| 89 | * |
||
| 90 | * @param Query $query Executed query |
||
| 91 | * @param Connection $connection Database Connection |
||
| 92 | * @param array $columns Columns description |
||
| 93 | * |
||
| 94 | * @return void |
||
|
0 ignored issues
–
show
|
|||
| 95 | */ |
||
| 96 | public function __construct(Query $query, Connection $connection, array $columns) |
||
| 97 | { |
||
| 98 | $this->query = $query; |
||
| 99 | $this->columns = $columns; |
||
| 100 | $this->connection = $connection; |
||
| 101 | |||
| 102 | $joins = (array) $query['joins']; |
||
| 103 | $tables = array(); |
||
| 104 | $itx = 0; |
||
| 105 | |||
| 106 | foreach ($columns as $column => $infos) { |
||
| 107 | $itx++; |
||
| 108 | $table = $infos['table']; |
||
| 109 | |||
| 110 | if (isset($tables[$table])) { |
||
| 111 | $tables[$table]['columns'][$column] = $infos['column']; |
||
| 112 | continue; |
||
| 113 | } |
||
| 114 | |||
| 115 | $skipped = false; |
||
| 116 | $jointure = false; |
||
| 117 | $joinOpt = false; |
||
| 118 | |||
| 119 | foreach ($joins as $join) { |
||
| 120 | $jointure = false; |
||
| 121 | $skipped = false; |
||
| 122 | |||
| 123 | if (\strpos($join['table'], ' ') !== false) { |
||
| 124 | list($joinTable, $alias) = explode(' ', $join['table']); |
||
|
0 ignored issues
–
show
The assignment to
$alias is unused. Consider omitting it like so list($first,,$third).
This checks looks for assignemnts to variables using the Consider the following code example. <?php
function returnThreeValues() {
return array('a', 'b', 'c');
}
list($a, $b, $c) = returnThreeValues();
print $a . " - " . $c;
Only the variables Instead, the list call could have been. list($a,, $c) = returnThreeValues();
Loading history...
|
|||
| 125 | } else { |
||
| 126 | $joinTable = $join['table']; |
||
| 127 | $alias = null; |
||
|
0 ignored issues
–
show
$alias is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the Loading history...
|
|||
| 128 | } |
||
| 129 | |||
| 130 | if ($joinTable == $table) { |
||
| 131 | if ($join['options']['skipped'] == true) { |
||
| 132 | $skipped = true; |
||
| 133 | } |
||
| 134 | |||
| 135 | $jointure = true; |
||
| 136 | $joinOpt = $join; |
||
| 137 | break; |
||
| 138 | } |
||
| 139 | } |
||
| 140 | |||
| 141 | if ($skipped && $jointure) { |
||
| 142 | continue; |
||
| 143 | } |
||
| 144 | |||
| 145 | $tables[$table]['columns'] = array(); |
||
| 146 | if ($jointure) { |
||
| 147 | $tables[$table]['join'] = $joinOpt; |
||
| 148 | $tables[$table]['entity'] = $joinOpt['options']['entity']; |
||
| 149 | $tables[$table]['entityListeners'] |
||
| 150 | = $joinOpt['options']['entityListeners']; |
||
| 151 | } else { |
||
| 152 | $tables[$table]['entity'] |
||
| 153 | = ($itx == 1 ? $query['entity'] : $this->connection->table($table)->getDefaultEntity()); |
||
| 154 | $tables[$table]['entityListeners'] |
||
| 155 | = (count($query['entityListeners']) ? |
||
| 156 | $query['entityListeners'] : |
||
| 157 | $this->connection->table($table)->getDefaultEntityListeners() |
||
| 158 | ); |
||
| 159 | } |
||
| 160 | $tables[$table]['columns'][$column] = $infos['column']; |
||
| 161 | } |
||
| 162 | |||
| 163 | $this->stack = $tables; |
||
| 164 | } |
||
| 165 | |||
| 166 | /** |
||
| 167 | * Transform raw results from database into ORM-style entities |
||
| 168 | * |
||
| 169 | * @param array $results Raw PDO results |
||
| 170 | * |
||
| 171 | * @return array |
||
| 172 | */ |
||
| 173 | public function hydrate(array $results) |
||
| 174 | { |
||
| 175 | $final = array(); |
||
| 176 | $joinData = array(); |
||
| 177 | |||
| 178 | foreach ($results as $result) { |
||
| 179 | $mainObj = null; |
||
| 180 | $mainObjRefs = null; |
||
| 181 | $mainObjTable = null; |
||
| 182 | |||
| 183 | foreach ($this->stack as $tableName => $infos) { |
||
| 184 | $columns = $infos['columns']; |
||
| 185 | $isJoin = (isset($infos['join']) ? true : false); |
||
| 186 | $entityClass= $infos['entity']; |
||
| 187 | $ids = $this->getIdentifiers($tableName, $result); |
||
| 188 | $obj = $this->loadEntityClass( |
||
| 189 | $tableName, |
||
| 190 | $ids, |
||
| 191 | $entityClass, |
||
| 192 | $infos['entityListeners'] |
||
| 193 | ); |
||
| 194 | $access = new Accessor($obj); |
||
| 195 | $values = $this->getValuesFromSet($columns, $result); |
||
| 196 | $access->setValues($values); |
||
| 197 | $mainObjRefs = $ids; |
||
| 198 | |||
| 199 | foreach ($access->getRelations() as $relation) { |
||
| 200 | $relation->setConnection($this->connection); |
||
| 201 | $relation->setParentRefs($access->get($relation->getLocal())); |
||
|
0 ignored issues
–
show
The method
setParentRefs() does not exist on Fwk\Db\RelationInterface. Did you maybe mean setParent()?
This check marks calls to methods that do not seem to exist on an object. This is most likely the result of a method being renamed without all references to it being renamed likewise. Loading history...
|
|||
| 202 | } |
||
| 203 | |||
| 204 | if (!$isJoin) { |
||
| 205 | $mainObj = $obj; |
||
| 206 | $mainObjTable = $tableName; |
||
| 207 | unset($access, $values, $isJoin, $columns); |
||
| 208 | if (!in_array($mainObj, $final, true)) { |
||
| 209 | array_push($final, $mainObj); |
||
| 210 | } |
||
| 211 | continue; |
||
| 212 | } |
||
| 213 | |||
| 214 | $idsHash = $tableName . implode(':', $ids); |
||
| 215 | $access = new Accessor($mainObj); |
||
| 216 | $columnName = $infos['join']['options']['column']; |
||
| 217 | |||
| 218 | $current = (isset($joinData[$idsHash . $columnName]) ? |
||
| 219 | $joinData[$idsHash . $columnName] : |
||
| 220 | $this->getRelationObject( |
||
| 221 | $mainObj, |
||
| 222 | $columnName, |
||
| 223 | $infos['join'], |
||
| 224 | $entityClass |
||
| 225 | ) |
||
| 226 | ); |
||
| 227 | |||
| 228 | $joinData[$idsHash . $columnName] = $current; |
||
| 229 | $current->add($obj, $ids); |
||
| 230 | $current->setFetched(true); |
||
| 231 | $current->setParentRefs($mainObjRefs); |
||
| 232 | |||
| 233 | $tableObj = $this->connection->table($mainObjTable); |
||
| 234 | $current->setParent( |
||
| 235 | $mainObj, |
||
| 236 | $tableObj->getRegistry()->getEventDispatcher($mainObj) |
||
| 237 | ); |
||
| 238 | |||
| 239 | $access->set($columnName, $current); |
||
| 240 | |||
| 241 | unset($access, $values, $isJoin, $columns, $current); |
||
| 242 | } |
||
| 243 | |||
| 244 | $access = new Accessor($mainObj); |
||
| 245 | $relations = $access->getRelations(); |
||
| 246 | foreach ($relations as $relation) { |
||
| 247 | $tableObj = $this->connection->table($mainObjTable); |
||
| 248 | $relation->setParent( |
||
| 249 | $mainObj, |
||
| 250 | $tableObj->getRegistry()->getEventDispatcher($mainObj) |
||
| 251 | ); |
||
| 252 | } |
||
| 253 | |||
| 254 | unset($mainObj, $mainObjRefs); |
||
| 255 | } |
||
| 256 | |||
| 257 | $this->markAsFresh(); |
||
| 258 | |||
| 259 | return $final; |
||
| 260 | } |
||
| 261 | |||
| 262 | /** |
||
| 263 | * Return RelationInterface object of an entity |
||
| 264 | * |
||
| 265 | * @param mixed $object The entity |
||
| 266 | * @param string $columnName RelationInterface's column name |
||
| 267 | * @param array $join Join descriptor (array) |
||
| 268 | * @param string $entityClass RelationInterface's entity class name |
||
|
0 ignored issues
–
show
Should the type for parameter
$entityClass not be string|null?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. Loading history...
|
|||
| 269 | * |
||
| 270 | * @return RelationInterface |
||
| 271 | */ |
||
| 272 | public function getRelationObject($object, $columnName, array $join, |
||
| 273 | $entityClass = null |
||
| 274 | ) { |
||
| 275 | $access = new Accessor($object); |
||
| 276 | $test = $access->get($columnName); |
||
| 277 | |||
| 278 | if (strpos($join['table'], ' ') !== false) { |
||
| 279 | list($table, ) = explode(' ', $join['table']); |
||
| 280 | } else { |
||
| 281 | $table = $join['table']; |
||
| 282 | } |
||
| 283 | |||
| 284 | if ($test instanceof \Fwk\Db\RelationInterface && $entityClass == $test->getEntity()) { |
||
| 285 | if ($test instanceof One2One) { |
||
| 286 | return $test; |
||
| 287 | } elseif ($test instanceof AbstractManyRelation && $join['options']['reference'] == $test->getReference()) { |
||
| 288 | return $test; |
||
| 289 | } |
||
| 290 | } |
||
| 291 | |||
| 292 | if (strpos($join['table'], ' ') !== false) { |
||
| 293 | list($table, ) = explode(' ', $join['table']); |
||
| 294 | } else { |
||
| 295 | $table = $join['table']; |
||
| 296 | } |
||
| 297 | |||
| 298 | $ref = new One2Many( |
||
| 299 | $join['local'], |
||
| 300 | $join['foreign'], |
||
| 301 | $table, |
||
| 302 | $entityClass, |
||
| 303 | $join['options']['entityListeners'] |
||
| 304 | ); |
||
| 305 | |||
| 306 | if (!empty($join['options']['reference'])) { |
||
| 307 | $ref->setReference($join['options']['reference']); |
||
| 308 | } |
||
| 309 | |||
| 310 | // $ref->setRegistry($this->connection->table($table)->getRegistry()); |
||
| 311 | $ref->setConnection($this->connection); |
||
| 312 | |||
| 313 | return $ref; |
||
| 314 | } |
||
| 315 | |||
| 316 | /** |
||
| 317 | * Transforms aliased results into results with real columns names |
||
| 318 | * |
||
| 319 | * @param array $columns Columns description |
||
| 320 | * @param array $resultSet Result set |
||
| 321 | * |
||
| 322 | * @return array |
||
| 323 | */ |
||
| 324 | public function getValuesFromSet(array $columns, array $resultSet) |
||
| 325 | { |
||
| 326 | $final = array(); |
||
| 327 | foreach ($columns as $alias => $realName) { |
||
| 328 | $final[$realName] = $resultSet[$alias]; |
||
| 329 | } |
||
| 330 | |||
| 331 | return $final; |
||
| 332 | } |
||
| 333 | |||
| 334 | /** |
||
| 335 | * Loads an entity |
||
| 336 | * |
||
| 337 | * @param string $tableName Table's name |
||
| 338 | * @param array $identifiers Entity identifiers |
||
| 339 | * @param string $entityClass Entity class name |
||
|
0 ignored issues
–
show
Should the type for parameter
$entityClass not be string|null?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. Loading history...
|
|||
| 340 | * @param array $listeners Entity's listeners |
||
| 341 | * |
||
| 342 | * @return mixed |
||
|
0 ignored issues
–
show
|
|||
| 343 | */ |
||
| 344 | protected function loadEntityClass($tableName, array $identifiers, |
||
| 345 | $entityClass = null, array $listeners = array() |
||
| 346 | ) { |
||
| 347 | $tableObj = $this->connection->table($tableName); |
||
| 348 | $registry = $tableObj->getRegistry(); |
||
| 349 | |||
| 350 | if ($entityClass === null) { |
||
| 351 | $entityClass = $tableObj->getDefaultEntity(); |
||
| 352 | } |
||
| 353 | |||
| 354 | $obj = $registry->get($identifiers, $entityClass); |
||
| 355 | |||
| 356 | if (null === $obj) { |
||
| 357 | $obj = new $entityClass; |
||
| 358 | $registry->store( |
||
| 359 | $obj, $identifiers, RegistryState::FRESH, array( |
||
| 360 | 'listeners' => $listeners |
||
| 361 | ) |
||
| 362 | ); |
||
| 363 | $this->markAsFresh[] = array( |
||
| 364 | 'registry' => $registry, |
||
| 365 | 'entity' => $obj, |
||
| 366 | 'table' => $tableObj |
||
| 367 | ); |
||
| 368 | } |
||
| 369 | |||
| 370 | return $obj; |
||
| 371 | } |
||
| 372 | |||
| 373 | /** |
||
| 374 | * Mark freshly built entities as fresh (aka "just fetched") |
||
| 375 | * |
||
| 376 | * @return void |
||
| 377 | */ |
||
| 378 | protected function markAsFresh() |
||
| 379 | { |
||
| 380 | if (!is_array($this->markAsFresh) || !count($this->markAsFresh)) { |
||
| 381 | return; |
||
| 382 | } |
||
| 383 | |||
| 384 | foreach ($this->markAsFresh as $infos) { |
||
| 385 | $infos['registry']->defineInitialValues( |
||
| 386 | $infos['entity'], |
||
| 387 | $this->connection, |
||
| 388 | $infos['table'] |
||
| 389 | ); |
||
| 390 | } |
||
| 391 | |||
| 392 | unset($this->markAsFresh); |
||
| 393 | } |
||
| 394 | |||
| 395 | /** |
||
| 396 | * Returns an array of identifiers for the given table |
||
| 397 | * |
||
| 398 | * @param string $tableName Table's name |
||
| 399 | * @param array $results Raw PDO results |
||
| 400 | * |
||
| 401 | * @return array |
||
| 402 | */ |
||
| 403 | protected function getIdentifiers($tableName, array $results) |
||
| 404 | { |
||
| 405 | $tableObj = $this->connection->table($tableName); |
||
| 406 | $tableIds = $tableObj->getIdentifiersKeys(); |
||
| 407 | |||
| 408 | if (!count($tableIds)) { |
||
| 409 | return array(); |
||
| 410 | } |
||
| 411 | |||
| 412 | $final = array(); |
||
| 413 | foreach ((array) $this->columns as $colName => $infos) { |
||
| 414 | if ($infos['table'] == $tableName |
||
| 415 | && in_array($infos['column'], $tableIds) |
||
| 416 | ) { |
||
| 417 | $final[$infos['column']] = $results[$colName]; |
||
| 418 | } |
||
| 419 | } |
||
| 420 | |||
| 421 | return $final; |
||
| 422 | } |
||
| 423 | } |
Adding a
@returnannotation to a constructor is not recommended, since a constructor does not have a meaningful return value.Please refer to the PHP core documentation on constructors.