1 <?php 2 /* Copyright (c) 2013, Geert Bergman (geert@scrivo.nl) 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. Neither the name of "Scrivo" nor the names of its contributors may be 14 * used to endorse or promote products derived from this software without 15 * specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 * 29 * $Id: User.php 866 2013-08-25 16:22:35Z geert $ 30 */ 31 32 /** 33 * Implementation of the \Scrivo\User class. 34 */ 35 36 namespace Scrivo; 37 38 /** 39 * The Scrivo User class represents the user entity in Scrivo. Access rights 40 * to objects like pages and assets are determined using these user principals. 41 * 42 * An user is identified by it's object id, but also by it's user code. 43 * Convention (but not mandatory) is to use email addresses for user codes. 44 * Both the user id and user code can be used to retrieve a user. 45 * 46 * The User class defines some descriptive members for the user's name and 47 * and email address. For additional user data to store along with a user 48 * you can use the multipurose 'customData' field. 49 * 50 * Peudo users 51 * 52 * The situation that you'll need to autenticate to different user database 53 * arises frequently. Since the existence of Scrivo users is a requirement 54 * for dertermining access to pages and assest it is suggested to use psuedo 55 * users. After autenticating to an other database the user should adopt a 56 * predefined (or progamatically defined) Scrivo user to access Scrivo 57 * resources. This is already the case for annymous access to Scrivo resources, 58 * in that case the user will adopt the Scrivo anymous user identity. 59 * 60 * TODO currently object ids 1 and 2 are used for reserved user ids, this is 61 * not in line with the policy for object ids. In the code the are patched to 62 * the values 3 and 4. 63 * 64 * @property-read object $customData A facility for 'free' storage. 65 * @property-read int $id The user's user id (DB key) 66 * @property-read array[] $roles An array of role-ids representing the roles 67 * for the user. 68 * @property \Scrivo\String $emailAddress The user's email address. 69 * @property \Scrivo\String $familyName The user's family name. 70 * @property \Scrivo\String $familyNamePrefix A prefix for the user's family 71 * name. 72 * @property \Scrivo\String $givenName The user's given name. 73 * @property \Scrivo\String $password The user's password (encrypted). 74 * @property int $status The user's status, one out of the constants 75 * self::STATUS_* 76 * @property \Scrivo\String $userCode A more descriptive identification 77 * for the user than the user id.* 78 */ 79 class User { 80 81 /** 82 * Status value indicating an admin user. 83 */ 84 const STATUS_ADMIN = 1; 85 86 /** 87 * Status value indicating an editor. 88 */ 89 const STATUS_EDITOR = 2; 90 91 /** 92 * Status value indicating a member. 93 */ 94 const STATUS_MEMBER = 3; 95 96 /** 97 * Reserved user id for primary admin user. 98 */ 99 const PRIMARY_ADMIN_ID = 4; 100 101 /** 102 * Reserved user id for the anonymous user. 103 */ 104 const ANONYMOUS_USER_ID = 3; 105 106 /** 107 * The user's user id (DB key) 108 * @var int 109 */ 110 private $id = 0; 111 112 /** 113 * The user status, one out of the constants self::STATUS_* 114 * @var int 115 */ 116 private $status = self::STATUS_MEMBER; 117 118 /** 119 * A more descriptive identification for the user than the user id. 120 * @var \Scrivo\String 121 */ 122 private $userCode = null; 123 124 /** 125 * The user's password (encrypted). 126 * @var \Scrivo\String 127 */ 128 private $password = null; 129 130 /** 131 * The user's given name. 132 * @var \Scrivo\String 133 */ 134 private $givenName = null; 135 136 /** 137 * A prefix for the user's family name. 138 * @var \Scrivo\String 139 */ 140 private $familyNamePrefix = null; 141 142 /** 143 * The user's family name. 144 * @var \Scrivo\String 145 */ 146 private $familyName = null; 147 148 /** 149 * The user's email address. 150 * @var \Scrivo\String 151 */ 152 private $emailAddress = null; 153 154 /** 155 * An array of role-ids representing the roles for the user. 156 * @var array[] 157 */ 158 private $roles = null; 159 160 /** 161 * A facility for 'free' storage. 162 * @var object 163 */ 164 private $customData = null; 165 166 /** 167 * A Scrivo context. 168 * @var Context 169 */ 170 private $context = null; 171 172 /** 173 * Create an empty user object. 174 * 175 * @param \Scrivo\Context $context A Scrivo context. 176 */ 177 public function __construct(\Scrivo\Context $context=null) { 178 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array(null), 0); 179 180 if ($context) { 181 $this->userCode = new \Scrivo\String(); 182 $this->password = new \Scrivo\String(); 183 $this->givenName = new \Scrivo\String(); 184 $this->familyNamePrefix = new \Scrivo\String(); 185 $this->familyName = new \Scrivo\String(); 186 $this->emailAddress = new \Scrivo\String(); 187 $this->customData = new \stdClass; 188 189 $this->context = $context; 190 } 191 } 192 193 /** 194 * Implementation of the readable properties using the PHP magic 195 * method __get(). 196 * 197 * @param string $name The name of the property to get. 198 * 199 * @return mixed The value of the requested property. 200 */ 201 public function __get($name) { 202 switch($name) { 203 case "id": return $this->id; 204 case "status": return $this->status; 205 case "userCode": return $this->userCode; 206 case "password": return $this->password; 207 case "givenName": return $this->givenName; 208 case "familyNamePrefix": return $this->familyNamePrefix; 209 case "familyName": return $this->familyName; 210 case "emailAddress": return $this->emailAddress; 211 case "roles": return $this->getRoles(); 212 case "customData": return $this->customData; 213 } 214 throw new \Scrivo\SystemException("No such get-property '$name'."); 215 } 216 217 /** 218 * Implementation of the writable properties using the PHP magic 219 * method __set(). 220 * 221 * @param string $name The name of the property to set. 222 * @param mixed $value The value of the property to set. 223 */ 224 public function __set($name, $value) { 225 switch($name) { 226 case "status": $this->setStatus($value); return; 227 case "userCode": $this->setUserCode($value); return; 228 case "password": $this->setPassword($value); return; 229 case "givenName": $this->setGivenName($value); return; 230 case "familyNamePrefix": $this->setFamilyNamePrefix($value); return; 231 case "familyName": $this->setFamilyName($value); return; 232 case "emailAddress": $this->setEmailAddress($value); return; 233 case "context": $this->setContext($value); return; 234 } 235 throw new \Scrivo\SystemException("No such set-property '$name'."); 236 } 237 238 /** 239 * Convenience method to set the fields of a user object from 240 * an array (result set row). 241 * 242 * @param \Scrivo\Context $context A Scrivo context. 243 * @param array $rd An array containing the field data using the database 244 * field names as keys. 245 */ 246 private function setFields(\Scrivo\Context $context, array $rd) { 247 248 $id = intval($rd["user_id"]); 249 if ($id === 1) { 250 $id = self::ANONYMOUS_USER_ID; 251 } 252 if ($id === 2) { 253 $id = self::PRIMARY_ADMIN_ID; 254 } 255 256 $this->id = $id; 257 $this->status = intval($rd["status"]); 258 $this->userCode = new \Scrivo\String($rd["user_code"]); 259 $this->password = new \Scrivo\String("- hidden -"); 260 $this->givenName = new \Scrivo\String($rd["given_name"]); 261 $this->familyNamePrefix = new \Scrivo\String($rd["family_name_prefix"]); 262 $this->familyName = new \Scrivo\String($rd["family_name"]); 263 $this->emailAddress = new \Scrivo\String($rd["email_address"]); 264 $this->customData = unserialize($rd["custom_data"]); 265 if (is_array($this->customData)) { 266 $this->customData = (object)$this->customData; 267 } 268 269 $this->context = $context; 270 } 271 272 /** 273 * Utility to patch legacy ids 1 and 2. 274 * @param int $id The id to patch. 275 * @return int The patched id. 276 */ 277 public static function patchId($id) { 278 if ($id === self::ANONYMOUS_USER_ID) { 279 return 1; 280 } 281 if ($id === self::PRIMARY_ADMIN_ID) { 282 return 2; 283 } 284 return $id; 285 } 286 287 /** 288 * Get the user-roles for this user. 289 * 290 * @return UserRole[roleId] The set of user-roles for this user. 291 */ 292 private function getRoles() { 293 if (!is_array($this->roles)) { 294 $this->roles = UserRole::select($this->context, $this); 295 $this->context->cache["U".$this->id] = $this; 296 } 297 return $this->roles; 298 } 299 300 /** 301 * Set the user status, one out of the constants User::STATUS_* 302 * 303 * @param int The user status, one out of the constants User::STATUS_* 304 */ 305 private function setStatus($status) { 306 if ($status != self::STATUS_ADMIN && $status != self::STATUS_EDITOR 307 && $status != self::STATUS_MEMBER) { 308 throw new \Scrivo\SystemException("Not a valid status"); 309 } 310 $this->status = $status; 311 } 312 313 /** 314 * Set the user code. 315 * 316 * @param \Scrivo\String A more descriptive identification for the 317 * user than the user id. 318 */ 319 private function setUserCode(\Scrivo\String $userCode) { 320 $this->userCode = $userCode; 321 } 322 323 /** 324 * Set the user's password (not encrypted). 325 * 326 * @param \Scrivo\String The user's password (not encrypted). 327 */ 328 private function setPassword(\Scrivo\String $password) { 329 $this->password = new \Scrivo\String($this->encrypt($password)); 330 } 331 332 /** 333 * Set the user's given name. 334 * 335 * @param \Scrivo\String The user's given name. 336 */ 337 private function setGivenName(\Scrivo\String $givenName) { 338 $this->givenName = $givenName; 339 } 340 341 /** 342 * Set a prefix for the user's family name. 343 * 344 * @param \Scrivo\String A prefix for the user's family name. 345 */ 346 private function setFamilyNamePrefix(\Scrivo\String $familyNamePrefix) { 347 $this->familyNamePrefix = $familyNamePrefix; 348 } 349 350 /** 351 * Set the user's family name. 352 * 353 * @param \Scrivo\String The user's family name. 354 */ 355 private function setFamilyName(\Scrivo\String $familyName) { 356 $this->familyName = $familyName; 357 } 358 359 /** 360 * Set the user's email address 361 * 362 * @param \Scrivo\String The user's email address 363 */ 364 private function setEmailAddress(\Scrivo\String $emailAddress) { 365 $this->emailAddress = $emailAddress; 366 } 367 368 /** 369 * Set the user's context. 370 * 371 * @param \Scrivo\Context $context A Scrivo context. 372 */ 373 private function setContext(\Scrivo\Context $context) { 374 $this->context = $context; 375 } 376 377 /** 378 * Check if the current user code is valid. 379 * 380 * The user code must be unique in the current database instance and at 381 * least three characters in length. 382 * 383 * @throws ApplicationException If the user code does not comply. 384 */ 385 private function checkUserCode() { 386 387 if ($this->userCode->length < 3) { 388 throw new ApplicationException("User code too short", 389 StatusCodes::USER_CODE_TOO_SHORT); 390 } 391 392 $sth = $this->context->connection->prepare( 393 "SELECT COUNT(*) FROM user 394 WHERE instance_id = :instId AND user_code = :userCode 395 AND user_id <> :id"); 396 397 $this->context->connection->bindInstance($sth); 398 $sth->bindValue(":id", self::patchId($this->id), \PDO::PARAM_INT); 399 $sth->bindValue(":userCode", $this->userCode, \PDO::PARAM_STR); 400 $sth->execute(); 401 402 $count = $sth->fetchColumn(); 403 404 if ($count != 0) { 405 throw new \Scrivo\ApplicationException("User code already in use", 406 StatusCodes::USER_CODE_IN_USE); 407 } 408 409 } 410 411 /** 412 * Encrypt a password. 413 * 414 * @param \Scrivo\String $password 415 * 416 * @return string 417 */ 418 private function encrypt(\Scrivo\String $password) { 419 $salt = base_convert(md5(mt_rand(0, 1000000)), 16, 36); 420 $c = crypt($password, "\$2a\$07\$".$salt."\$"); 421 return $c; 422 } 423 424 /** 425 * Check if this user object can be inserted into the database. 426 * 427 * @throws \Scrivo\ApplicationException If the data is not accessible or 428 * one or more of the fields contain invalid data. 429 */ 430 private function validateInsert() { 431 $this->context->checkPermission(\Scrivo\AccessController::WRITE_ACCESS); 432 $this->checkUserCode(); 433 } 434 435 /** 436 * Insert new user object data into the database. 437 * 438 * First it is checked if the data of this user object can be inserted 439 * into the database, then the data is inserted into the database. If no id 440 * was set a new object id is generated. 441 * 442 * @throws \Scrivo\ApplicationException If the data is not accessible or 443 * one or more of the fields contain invalid data. 444 */ 445 public function insert() { 446 try { 447 $this->validateInsert(); 448 449 if (!$this->id) { 450 $this->id = $this->context->connection->generateId(); 451 } 452 453 $sth = $this->context->connection->prepare( 454 "INSERT INTO user ( 455 instance_id, user_id, status, user_code, password, 456 given_name, family_name_prefix, family_name, email_address, 457 custom_data 458 ) VALUES ( 459 :instId, :id, :status, :userCode, :password, 460 :givenName, :familyNamePrefix, :familyName, :emailAddress, 461 :customData 462 )"); 463 464 $this->context->connection->bindInstance($sth); 465 $sth->bindValue(":id", $this->id, \PDO::PARAM_INT); 466 $sth->bindValue(":status", $this->status, \PDO::PARAM_INT); 467 $sth->bindValue(":userCode", $this->userCode, \PDO::PARAM_STR); 468 $sth->bindValue(":password", $this->password, \PDO::PARAM_STR); 469 $sth->bindValue(":givenName", $this->givenName, \PDO::PARAM_STR); 470 $sth->bindValue( 471 ":familyNamePrefix", $this->familyNamePrefix, \PDO::PARAM_STR); 472 $sth->bindValue(":familyName", $this->familyName, \PDO::PARAM_STR); 473 $sth->bindValue( 474 ":emailAddress", $this->emailAddress, \PDO::PARAM_STR); 475 $sth->bindValue( 476 ":customData", serialize($this->customData), \PDO::PARAM_STR); 477 478 $sth->execute(); 479 480 } catch(\PDOException $e) { 481 throw new \Scrivo\ResourceException($e); 482 } 483 } 484 485 /** 486 * Check if this user object can be updated in the database. 487 * 488 * @throws \Scrivo\ApplicationException If the data is not accessible or 489 * one or more of the fields contain invalid data. 490 */ 491 private function validateUpdate() { 492 $this->context->checkPermission(\Scrivo\AccessController::WRITE_ACCESS); 493 $this->checkUserCode(); 494 } 495 496 /** 497 * Update existing user object data in the database. 498 * 499 * First it is checked if the data of this user object can be updated 500 * in the database, then the data is updated in the database. 501 * 502 * The user's password cannot be updated with this method. Use 503 * User::updatePassword() in order to do that. 504 * 505 * @throws \Scrivo\ApplicationException If the data is not accessible or 506 * one or more of the fields contain invalid data. 507 */ 508 public function update() { 509 try { 510 $this->validateUpdate(); 511 512 $sth = $this->context->connection->prepare( 513 "UPDATE user SET 514 status = :status, user_code = :userCode, 515 given_name = :givenName, 516 family_name_prefix = :familyNamePrefix, 517 family_name = :familyName, email_address = :emailAddress, 518 custom_data = :customData 519 WHERE instance_id = :instId AND user_id = :id"); 520 521 $this->context->connection->bindInstance($sth); 522 $sth->bindValue(":id", self::patchId($this->id), \PDO::PARAM_INT); 523 524 $sth->bindValue(":status", $this->status, \PDO::PARAM_INT); 525 $sth->bindValue(":userCode", $this->userCode, \PDO::PARAM_STR); 526 $sth->bindValue(":givenName", $this->givenName, \PDO::PARAM_STR); 527 $sth->bindValue( 528 ":familyNamePrefix", $this->familyNamePrefix, \PDO::PARAM_STR); 529 $sth->bindValue(":familyName", $this->familyName, \PDO::PARAM_STR); 530 $sth->bindValue( 531 ":emailAddress", $this->emailAddress, \PDO::PARAM_STR); 532 $sth->bindValue( 533 ":customData", serialize($this->customData), \PDO::PARAM_STR); 534 535 $sth->execute(); 536 537 unset($this->context->cache["U".$this->id]); 538 539 } catch(\PDOException $e) { 540 throw new \Scrivo\ResourceException($e); 541 } 542 } 543 544 /** 545 * Update the password of this user. 546 * 547 * The password property should be set to its new value. When saving 548 * a encrypted value will be stored into the database. When this user 549 * object is loaded again its password property will contain the encrypted 550 * value for the new password. 551 * 552 * @throws ApplicationException If one or more of the fields contain 553 * invalid data. 554 */ 555 public function updatePassword() { 556 try { 557 $this->context->checkPermission(\Scrivo\AccessController::WRITE_ACCESS); 558 559 $sth = $this->context->connection->prepare( 560 "UPDATE user SET password = :password 561 WHERE instance_id = :instId AND user_id = :id"); 562 563 $this->context->connection->bindInstance($sth); 564 $sth->bindValue(":id", self::patchId($this->id), \PDO::PARAM_INT); 565 566 $sth->bindValue( 567 ":password", $this->password, \PDO::PARAM_STR); 568 569 $sth->execute(); 570 571 } catch(\PDOException $e) { 572 throw new \Scrivo\ResourceException($e); 573 } 574 } 575 576 /** 577 * Check if a given password matches with the one of this user. 578 * 579 * @param \Scrivo\String $toTest Password to test. 580 * 581 * @return boolean True if given password matches the user's, false if not. 582 */ 583 public function checkPassword(\Scrivo\String $toTest) { 584 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array(null)); 585 try { 586 587 $sth = $this->context->connection->prepare( 588 "SELECT password FROM user 589 WHERE instance_id = :instId AND user_id = :id"); 590 591 $this->context->connection->bindInstance($sth); 592 $sth->bindValue(":id", self::patchId($this->id), \PDO::PARAM_INT); 593 594 $sth->execute(); 595 596 if ($sth->rowCount() != 1) { 597 throw new \Scrivo\SystemException("Failed to load User"); 598 } 599 600 $pw = $sth->fetchColumn(); 601 602 return $pw == crypt($toTest, $pw); 603 604 } catch(\PDOException $e) { 605 throw new \Scrivo\ResourceException($e); 606 } 607 } 608 609 /** 610 * Check if deletion of user object data does not violate any 611 * business rules. 612 * 613 * @param \Scrivo\Context $context A Scrivo context. 614 * @param int $id a valid object id. 615 * 616 * @throws \Scrivo\ApplicationException If the data is not accessible or 617 * if it is not possible to delete the user data. 618 */ 619 private function validateDelete(\Scrivo\Context $context, $id) { 620 $context->checkPermission(\Scrivo\AccessController::WRITE_ACCESS); 621 if ($id == self::PRIMARY_ADMIN_ID || $id == self::ANONYMOUS_USER_ID) { 622 throw new \Scrivo\ApplicationException("Can't delete system users", 623 StatusCodes::CANNOT_DELETE_SYSTEM_USERS); 624 } 625 } 626 627 /** 628 * Delete existing user data from the database. 629 * 630 * First it is is checked if it's possible to delete user data, 631 * then the user data including its dependecies is deleted from 632 * the database. 633 * 634 * @param \Scrivo\Context $context A Scrivo context. 635 * @param int $id a valid object id. 636 * 637 * @throws \Scrivo\ApplicationException If the data is not accessible or 638 * if it is not possible to delete the user data. 639 */ 640 public static function delete(\Scrivo\Context $context, $id) { 641 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 642 null, 643 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 644 )); 645 try { 646 self::validateDelete($context, $id); 647 648 foreach (array("user", "user_role") as $table) { 649 650 $sth = $context->connection->prepare( 651 "DELETE FROM $table 652 WHERE instance_id = :instId AND user_id = :id"); 653 654 $context->connection->bindInstance($sth); 655 $sth->bindValue(":id", $id, \PDO::PARAM_INT); 656 657 $sth->execute(); 658 } 659 660 unset($context->cache["U".$id]); 661 662 } catch(\PDOException $e) { 663 throw new \Scrivo\ResourceException($e); 664 } 665 } 666 667 /** 668 * Assign user roles to this user. 669 * 670 * The user roles to set is either an array of UserRole or stdObject 671 * objects. stdObject need to contain the members roleId and isPublisher. 672 * 673 * Note: this sets all the roles for the user at once. So not giving the 674 * the roles effectivily clears the roles for the given user. 675 * 676 * @param UserRole[]|object[] $roles A new set of user-roles for the given 677 * user. 678 */ 679 public function assignRoles($roles) { 680 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array(null)); 681 682 UserRole::set($this->context, $this, $roles); 683 } 684 685 /** 686 * Fetch a user object from the database using the object id or 687 * user code. 688 * 689 * @param \Scrivo\Context $context A Scrivo context. 690 * @param int|\Scrivo\String $id a valid object id or user code. 691 * 692 * @return \Scrivo\User The requested user object. 693 * 694 * @throws \Scrivo\ApplicationException If the given user code was 695 * not found (when selecting by user code). 696 */ 697 public static function fetch(\Scrivo\Context $context, $id) { 698 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 699 null, 700 array(array(\Scrivo\ArgumentCheck::TYPE_INTEGER, "Scrivo\String")) 701 )); 702 try { 703 704 if ($id instanceof \Scrivo\String) { 705 $byUserCode = true; 706 } else if (is_int($id)) { 707 $byUserCode = false; 708 } else { 709 throw new \Scrivo\SystemException("Invalid argument type"); 710 } 711 712 // Try to retieve the user from the cache ... 713 if (!$byUserCode && isset($context->cache["U".$id])) { 714 // ... get it from the cache and set the context. 715 $user = $context->cache["U".$id]; 716 $user->context = $context; 717 } else { 718 // ... else retrieve it and set it in the cache. 719 $sth = $context->connection->prepare( 720 "SELECT user_id, status, user_code, 721 given_name, family_name_prefix, family_name, email_address, custom_data 722 FROM user 723 WHERE instance_id = :instId AND 724 ".($byUserCode ? "user_code" : "user_id")." = :id"); 725 726 $user = new \Scrivo\User($context); 727 728 $context->connection->bindInstance($sth); 729 if ($byUserCode) { 730 $sth->bindValue(":id", $id, \PDO::PARAM_STR); 731 } else { 732 $sth->bindValue( 733 ":id", $user->patchId($id), \PDO::PARAM_INT); 734 } 735 736 $sth->execute(); 737 738 if ($sth->rowCount() != 1) { 739 if ($byUserCode) { 740 throw new \Scrivo\ApplicationException( 741 "Failed to load User $byUserCode"); 742 } 743 throw new \Scrivo\SystemException("Failed to load User"); 744 } 745 746 $rd = $sth->fetch(\PDO::FETCH_ASSOC); 747 748 $user->setFields($context, $rd); 749 750 $context->cache["U".$user->id] = $user; 751 } 752 753 return $user; 754 755 } catch(\PDOException $e) { 756 throw new \Scrivo\ResourceException($e); 757 } 758 } 759 760 /** 761 * Select users from the database. 762 * 763 * Depending on the given arguments all users or all users for a given 764 * role can be retrieved. 765 * 766 * @param \Scrivo\Context $context A Scrivo context. 767 * @param int $roleId Optional role id for which to retrieve the users. 768 * 769 * @return User[id] An array containing the selected users. 770 */ 771 public static function select(\Scrivo\Context $context, $roleId = null) { 772 \Scrivo\ArgumentCheck::assertArgs(func_get_args(), array( 773 null, 774 array(\Scrivo\ArgumentCheck::TYPE_INTEGER) 775 ), 1); 776 try { 777 $sth = $context->connection->prepare( 778 "SELECT U.user_id, U.status, U.user_code, U.given_name, U.family_name_prefix, 779 U.family_name, U.email_address, U.custom_data 780 FROM user U" .($roleId? ", user_role": "")." 781 WHERE U.instance_id = :instId" .($roleId 782 ? " AND user_role.instance_id = :instId AND 783 user_role.user_id = U.user_id AND role_id = :roleId" 784 : "")); 785 786 $context->connection->bindInstance($sth); 787 if ($roleId) { 788 $sth->bindValue(":roleId", $roleId, \PDO::PARAM_INT); 789 } 790 791 $sth->execute(); 792 793 $res = array(); 794 795 while ($rd = $sth->fetch(\PDO::FETCH_ASSOC)) { 796 797 $li = new User(); 798 $li->setFields($context, $rd); 799 800 $res[$li->id] = $li; 801 } 802 803 return $res; 804 805 } catch(\PDOException $e) { 806 throw new \Scrivo\ResourceException($e); 807 } 808 } 809 810 } 811 812 ?>
Documentation generated by phpDocumentor 2.0.0a12 and ScrivoDocumentor on August 29, 2013