[ Index ]

PHP Cross Reference of GlotPress

title

Body

[close]

/gp-includes/ -> thing.php (source)

   1  <?php
   2  /**
   3   * Things: GP_Thing class
   4   *
   5   * @package GlotPress
   6   * @subpackage Things
   7   * @since 1.0.0
   8   */
   9  
  10  /**
  11   * Core base class extended to register things.
  12   *
  13   * @since 1.0.0
  14   */
  15  class GP_Thing {
  16  
  17      var $field_names = array();
  18      var $non_db_field_names = array();
  19      var $int_fields = array();
  20      var $validation_rules = null;
  21      var $per_page = 30;
  22      var $map_results = true;
  23      var $static = array();
  24  
  25      public $class;
  26      public $table_basename;
  27      public $id;
  28      public $non_updatable_attributes;
  29      public $default_conditions;
  30      public $table = null;
  31      public $errors = array();
  32  
  33      static $static_by_class = array();
  34      static $validation_rules_by_class = array();
  35  
  36  	public function __construct( $fields = array() ) {
  37          global $wpdb;
  38          $this->class = get_class( $this );
  39          $this->table = $wpdb->{$this->table_basename};
  40          foreach( $this->field_names as $field_name ) {
  41              $this->$field_name = null;
  42          }
  43          $this->set_fields( $fields );
  44  
  45          if ( isset( self::$validation_rules_by_class[$this->class] ) ) {
  46              $this->validation_rules = &self::$validation_rules_by_class[$this->class];
  47          } else {
  48              $this->validation_rules = new GP_Validation_Rules( array_merge( $this->field_names, $this->non_db_field_names ) );
  49              // we give the rules as a parameter here solely as a syntax sugar
  50              $this->restrict_fields( $this->validation_rules );
  51              self::$validation_rules_by_class[$this->class] = &$this->validation_rules;
  52          }
  53          if ( !$this->get_static( 'static-vars-are-set' ) ) {
  54              foreach( get_class_vars( $this->class ) as $name => $value ) {
  55                  $this->set_static( $name, $value );
  56              }
  57              $this->set_static( 'static-vars-are-set', true );
  58          }
  59      }
  60  
  61  	public function get_static( $name, $default = null ) {
  62          return isset( self::$static_by_class[$this->class][$name] )? self::$static_by_class[$this->class][$name] : $default;
  63      }
  64  
  65  	public function has_static( $name ) {
  66          return isset( self::$static_by_class[$this->class][$name] );
  67      }
  68  
  69  	public function set_static( $name, $value ) {
  70          self::$static_by_class[$this->class][$name] = $value;
  71      }
  72  
  73      // CRUD
  74  
  75      /**
  76       * Retrieves all rows from this table
  77       */
  78  	public function all( $order = null ) {
  79          return $this->many( $this->select_all_from_conditions_and_order( array(), $order ) );
  80      }
  81  
  82      /**
  83       * Reloads the object data from the database, based on its id
  84       */
  85  	public function reload() {
  86          $this->set_fields( $this->get( $this->id ) );
  87          return $this;
  88      }
  89  
  90      /**
  91       * Retrieves a single row from this table
  92       *
  93       * For parameters description see BPDB::prepare()
  94       * @return mixed an object, containing the selected row or false on error
  95       */
  96  	public function one() {
  97          global $wpdb;
  98          $args = func_get_args();
  99          return $this->coerce( $wpdb->get_row( $this->prepare( $args ) ) );
 100      }
 101  
 102      /**
 103       * Retrieves a single value from this table
 104       *
 105       * For parameters description see BPDB::prepare()
 106       * @return scalar the result of the query or false on error
 107       */
 108  	public function value() {
 109          global $wpdb;
 110          $args = func_get_args();
 111          $res = $wpdb->get_var( $this->prepare( $args ) );
 112          return is_null( $res )? false : $res;
 113      }
 114  
 115  	public function prepare( $args ) {
 116          global $wpdb;
 117          if ( 1 == count( $args ) ) {
 118              return $args[0];
 119          } else {
 120              $query = array_shift( $args );
 121              return $wpdb->prepare( $query, $args );
 122          }
 123      }
 124  
 125  
 126      /**
 127       * Retrieves multiple rows from this table
 128       *
 129       * For parameters description see `$wpdb->prepare()`.
 130       *
 131       * @since 1.0.0
 132       *
 133       * @return mixed An object, containing the selected row or false on error.
 134       */
 135  	public function many() {
 136          global $wpdb;
 137          $args = func_get_args();
 138          return $this->map( $wpdb->get_results( $this->prepare( $args ) ) );
 139      }
 140  
 141      /**
 142       * [many_no_map description]
 143       *
 144       * @since 1.0.0
 145       *
 146       * @return mixed
 147       */
 148  	public function many_no_map() {
 149          $args = func_get_args();
 150          return $this->_no_map( 'many', $args );
 151      }
 152  
 153      /**
 154       * [find_many description]
 155       *
 156       * @since 1.0.0
 157       *
 158       * @param string|array $conditions
 159       * @param string|array $order Optional.
 160       * @return mixed
 161       */
 162  	public function find_many( $conditions, $order = null ) {
 163          return $this->many( $this->select_all_from_conditions_and_order( $conditions, $order ) );
 164      }
 165  
 166      /**
 167       * [find_many_no_map description]
 168       *
 169       * @since 1.0.0
 170       *
 171       * @param string|array $conditions
 172       * @param string|array $order Optional.
 173       * @return mixed
 174       */
 175  	public function find_many_no_map( $conditions, $order = null ) {
 176          return $this->_no_map( 'find_many', array( $conditions, $order ) );
 177      }
 178  
 179      /**
 180       * [find_one description]
 181       *
 182       * @since 1.0.0
 183       *
 184       * @param string|array $conditions
 185       * @param string|array $order Optional.
 186       * @return mixed
 187       */
 188  	public function find_one( $conditions, $order = null ) {
 189          return $this->one( $this->select_all_from_conditions_and_order( $conditions, $order ) );
 190      }
 191  
 192      /**
 193       * [find description]
 194       *
 195       * @since 1.0.0
 196       *
 197       * @param string|array $conditions
 198       * @param string|array $order Optional.
 199       * @return mixed
 200       */
 201  	public function find( $conditions, $order = null ) {
 202          return $this->find_many( $conditions, $order );
 203      }
 204  
 205      /**
 206       * [find_no_map description]
 207       *
 208       * @since 1.0.0
 209       *
 210       * @param string|array $conditions
 211       * @param string|array $order Optional.
 212       * @return mixed
 213       */
 214  	public function find_no_map( $conditions, $order = null ) {
 215          return $this->_no_map( 'find', array( $conditions, $order ) );
 216      }
 217  
 218      /**
 219       * [_no_map description]
 220       *
 221       * @since 1.0.0
 222       *
 223       * @param string $name Method name.
 224       * @param mixed  $args Method-dependent arguments.
 225       * @return mixed
 226       */
 227  	private function _no_map( $name, $args ) {
 228          $this->map_results = false;
 229          $result = call_user_func_array( array( $this, $name ), $args );
 230          $this->map_results = true;
 231  
 232          return $result;
 233      }
 234  
 235      /**
 236       * [map_no_map description]
 237       *
 238       * @since 1.0.0
 239       *
 240       * @param mixed $results The results, unmapped.
 241       * @return mixed
 242       */
 243  	public function map_no_map( $results ) {
 244          return $this->_no_map( 'map', $results );
 245      }
 246  
 247      /**
 248       * [map description]
 249       *
 250       * @since 1.0.0
 251       *
 252       * @param mixed $results The results, mapped.
 253       * @return mixed
 254       */
 255  	public function map( $results ) {
 256          if ( isset( $this->map_results ) && ! $this->map_results ) {
 257              return $results;
 258          }
 259  
 260          if ( ! $results || ! is_array( $results ) ) {
 261              $results = array();
 262          }
 263  
 264          $mapped = array();
 265          foreach ( $results as $result ) {
 266              $mapped[] = $this->coerce( $result );
 267          }
 268  
 269          return $mapped;
 270      }
 271  
 272      /**
 273       * Performs a database query.
 274       *
 275       * @since 1.0.0
 276       *
 277       * @return mixed
 278       */
 279  	public function query() {
 280          global $wpdb;
 281          $args = func_get_args();
 282          return $wpdb->query( $this->prepare( $args ) );
 283      }
 284  
 285      /**
 286       * Inserts a new row
 287       *
 288       * @param $args array associative array with fields as keys and values as values
 289       * @return mixed the object corresponding to the inserted row or false on error
 290       */
 291  	public function create( $args ) {
 292          global $wpdb;
 293          $args = $this->prepare_fields_for_save( $args );
 294          $args = $this->prepare_fields_for_create( $args );
 295          $field_formats = $this->get_db_field_formats( $args );
 296          $res = $wpdb->insert( $this->table, $args, $field_formats );
 297          if ( $res === false ) return false;
 298          $class = $this->class;
 299          $inserted = new $class( $args );
 300          $inserted->id = $wpdb->insert_id;
 301          $inserted->after_create();
 302          return $inserted;
 303      }
 304  
 305      /**
 306       * Inserts a record and then selects it back based on the id
 307       *
 308       * @param $args array see create()
 309       * @return mixed the selected object or false on error
 310       */
 311  	public function create_and_select( $args ) {
 312          $created = $this->create( $args );
 313          if ( !$created ) return false;
 314          $created->reload();
 315          return $created;
 316      }
 317  
 318      /**
 319       * Updates a single row
 320       *
 321       * @param $data array associative array with fields as keys and updated values as values
 322       */
 323  	public function update( $data, $where = null ) {
 324          global $wpdb;
 325          if ( !$data ) return false;
 326          $where = is_null( $where )? array( 'id' => $this->id ) : $where;
 327          $fields_for_save = $this->prepare_fields_for_save( $data );
 328          if ( is_array( $fields_for_save ) && empty( $fields_for_save ) ) return true;
 329  
 330          $field_formats = $this->get_db_field_formats( $fields_for_save );
 331          $where_formats = $this->get_db_field_formats( $where );
 332  
 333          return !is_null( $wpdb->update( $this->table, $fields_for_save, $where, $field_formats, $where_formats ) );
 334      }
 335  
 336  	public function get( $thing_or_id ) {
 337          global $wpdb;
 338          if ( !$thing_or_id ) return false;
 339          $id = is_object( $thing_or_id )? $thing_or_id->id : $thing_or_id;
 340          return $this->find_one( array( 'id' => $id ) );
 341      }
 342  
 343      /**
 344       * Saves an existing thing.
 345       *
 346       * @since 1.0.0
 347       *
 348       * @param mixed $args Values to update.
 349       * @return bool|null Null and false on failure, true on success.
 350       */
 351  	public function save( $args = null ) {
 352          $thing_before = clone $this;
 353  
 354          if ( is_null( $args ) ) {
 355              $args = get_object_vars( $this );
 356          }
 357  
 358          if ( ! is_array( $args ) ) {
 359              $args = (array) $args;
 360          }
 361  
 362          $args = $this->prepare_fields_for_save( $args );
 363  
 364          $update_res = $this->update( $args );
 365  
 366          $this->set_fields( $args );
 367  
 368          if ( ! $update_res ) {
 369              return null;
 370          }
 371  
 372          $update_res = $this->after_save( $thing_before );
 373  
 374          return $update_res;
 375      }
 376  
 377      /**
 378       * Deletes a single row
 379       *
 380       * @since 1.0.0
 381       */
 382  	public function delete() {
 383          return $this->delete_all( array( 'id' => $this->id ) );
 384      }
 385  
 386      /**
 387       * Deletes all or multiple rows
 388       *
 389       * @since 1.0.0
 390       *
 391       * @param array $where An array of conditions to use to for a SQL "where" clause, if null, not used and all matching rows will be deleted.
 392       */
 393  	public function delete_all( $where = null ) {
 394          $query = "DELETE FROM $this->table";
 395          $conditions_sql = $this->sql_from_conditions( $where );
 396          if ( $conditions_sql ) $query .= " WHERE $conditions_sql";
 397          $result = $this->query( $query );
 398          $this->after_delete();
 399          return $result;
 400      }
 401  
 402      /**
 403       * Deletes multiple rows
 404       *
 405       * @since 2.0.0
 406       *
 407       * @param array $where An array of conditions to use to for a SQL "where" clause, if not passed, no rows will be deleted.
 408       */
 409  	public function delete_many( $where = null ) {
 410          if ( null !== $where ) {
 411              return $this->delete_all( $where );
 412          }
 413  
 414          return false;
 415      }
 416  
 417  	public function set_fields( $db_object ) {
 418          $db_object = $this->normalize_fields( $db_object );
 419          foreach( $db_object as $key => $value ) {
 420              $this->$key = $value;
 421          }
 422      }
 423  
 424      /**
 425       * Normalizes an array with key-value pairs representing
 426       * a GP_Thing object.
 427       *
 428       * @todo Include default type handling. For example dates 0000-00-00 should be set to null
 429       *
 430       * @since 1.0.0
 431       *
 432       * @param array $args Arguments for a GP_Thing object.
 433       * @return array Normalized arguments for a GP_Thing object.
 434       */
 435  	public function normalize_fields( $args ) {
 436          return $args;
 437      }
 438  
 439      /**
 440       * Prepares for enetering the database an array with
 441       * key-value pairs, preresenting a GP_Thing object.
 442       *
 443       */
 444  	public function prepare_fields_for_save( $args ) {
 445          $args = (array)$args;
 446          $args = $this->normalize_fields( $args );
 447          unset( $args['id'] );
 448          foreach( $this->non_updatable_attributes as $attribute ) {
 449              unset( $args[$attribute] );
 450          }
 451          foreach( $args as $key => $value ) {
 452              if ( !in_array( $key, $this->field_names ) ) {
 453                  unset( $args[$key] );
 454              }
 455          }
 456  
 457          if ( in_array( 'date_modified', $this->field_names ) ) {
 458              $args['date_modified'] = $this->now_in_mysql_format();
 459          }
 460  
 461          return $args;
 462      }
 463  
 464  	public function now_in_mysql_format() {
 465          $now = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
 466          return $now->format( DATE_MYSQL );
 467      }
 468  
 469  	public function prepare_fields_for_create( $args ) {
 470          if ( in_array( 'date_added', $this->field_names ) ) {
 471              $args['date_added'] = $this->now_in_mysql_format();
 472          }
 473          return $args;
 474      }
 475  
 476  	public function get_db_field_formats( $args ) {
 477          $formats = array_fill_keys( array_keys( $args ), '%s' );
 478          return array_merge( $formats, array_fill_keys( $this->int_fields, '%d' ) );
 479      }
 480  
 481  	public function coerce( $thing ) {
 482          if ( !$thing || is_wp_error( $thing ) ) {
 483              return false;
 484          } else {
 485              $class = $this->class;
 486              return new $class( $thing );
 487          }
 488      }
 489  
 490      // Triggers
 491  
 492      /**
 493       * Is called after an object is created in the database.
 494       *
 495       * This is a placeholder function which should be implemented in the child classes.
 496       *
 497       * @return bool
 498       */
 499  	public function after_create() {
 500          return true;
 501      }
 502  
 503      /**
 504       * Is called after an object is saved to the database.
 505       *
 506       * This is a placeholder function which should be implemented in the child classes.
 507       *
 508       * @param GP_Thing $thing_before Object before the update.
 509       * @return bool
 510       */
 511  	public function after_save( $thing_before ) {
 512          return true;
 513      }
 514  
 515      /**
 516       * Is called after an object is deleted from the database.
 517       *
 518       * This is a placeholder function which should be implemented in the child classes.
 519       *
 520       * @return bool
 521       */
 522  	public function after_delete() {
 523          return true;
 524      }
 525  
 526  	public function sql_condition_from_php_value( $php_value ) {
 527          global $wpdb;
 528          if ( is_array( $php_value ) ) {
 529              return array_map( array( &$this, 'sql_condition_from_php_value' ), $php_value );
 530          }
 531          $operator = '=';
 532          if ( is_integer( $php_value ) || ctype_digit( $php_value) )
 533               $sql_value = $php_value;
 534          else
 535              $sql_value = "'" . esc_sql( $php_value )  ."'";
 536          if ( is_null( $php_value ) ) {
 537              $operator = 'IS';
 538              $sql_value = 'NULL';
 539          }
 540          return "$operator $sql_value";
 541      }
 542  
 543  	public function sql_from_conditions( $conditions ) {
 544          if ( is_string( $conditions ) ) {
 545              $conditions;
 546          } elseif ( is_array( $conditions ) ) {
 547              $conditions = array_map( array( &$this, 'sql_condition_from_php_value' ), $conditions );
 548              $string_conditions = array();
 549  
 550              foreach ( $conditions as $field => $sql_condition ) {
 551                  if ( is_array( $sql_condition ) ) {
 552                      $string_conditions[] = '(' . implode( ' OR ', array_map( function( $cond ) use ( $field ) {
 553                              return "$field $cond";
 554                          }, $sql_condition ) ) . ')';
 555                  } else {
 556                      $string_conditions[] = "$field $sql_condition";
 557                  }
 558              }
 559  
 560              $conditions = implode( ' AND ', $string_conditions );
 561          }
 562          return $this->apply_default_conditions( $conditions );
 563      }
 564  
 565  	public function sql_from_order( $order_by, $order_how = '' ) {
 566          if ( is_array( $order_by ) ) {
 567              $order_by = implode( ' ', $order_by );
 568              $order_how = '';
 569          }
 570          $order_by = trim( $order_by );
 571          if ( !$order_by ) return gp_member_get( $this, 'default_order' );
 572          return 'ORDER BY ' . $order_by . ( $order_how? " $order_how" : '' );
 573      }
 574  
 575  	public function select_all_from_conditions_and_order( $conditions, $order = null ) {
 576          $query = "SELECT * FROM $this->table";
 577          $conditions_sql = $this->sql_from_conditions( $conditions );
 578          if ( $conditions_sql ) $query .= " WHERE $conditions_sql";
 579          $order_sql = $this->sql_from_order( $order );
 580          if ( $order_sql ) $query .= " $order_sql";
 581          return $query;
 582      }
 583  
 584      /**
 585       * Sets restriction rules for fields.
 586       *
 587       * @since 1.0.0
 588       *
 589       * @param GP_Validation_Rules $rules The validation rules instance.
 590       */
 591  	public function restrict_fields( $rules ) {
 592          // Don't restrict any fields by default.
 593      }
 594  
 595  	public function validate() {
 596          $verdict = $this->validation_rules->run( $this );
 597          $this->errors = $this->validation_rules->errors;
 598          return $verdict;
 599      }
 600  
 601  	public function force_false_to_null( $value ) {
 602          return $value? $value : null;
 603      }
 604  
 605  	public function fields() {
 606          $result = array();
 607          foreach( array_merge( $this->field_names, $this->non_db_field_names ) as $field_name ) {
 608              if ( isset( $this->$field_name ) ) {
 609                  $result[$field_name] = $this->$field_name;
 610              }
 611          }
 612          return $result;
 613      }
 614  
 615  	public function sql_limit_for_paging( $page, $per_page = null ) {
 616          $per_page = is_null( $per_page )? $this->per_page : $per_page;
 617          if ( 'no-limit' == $per_page || 'no-limit' == $page ) return '';
 618          $page = intval( $page )? intval( $page ) : 1;
 619          return sprintf( "LIMIT %d OFFSET %d", $per_page, ($page-1)*$per_page );
 620      }
 621  
 622  	public function found_rows() {
 623          global $wpdb;
 624          return $wpdb->get_var("SELECT FOUND_ROWS();");
 625      }
 626  
 627  	public function like_escape_printf( $s ) {
 628          global $wpdb;
 629          return str_replace( '%', '%%', $wpdb->esc_like( $s ) );
 630      }
 631  
 632  	public function apply_default_conditions( $conditions_str ) {
 633          $conditions = array();
 634          if ( isset( $this->default_conditions ) )  $conditions[] = $this->default_conditions;
 635          if ( $conditions_str ) $conditions[] = $conditions_str;
 636          return implode( ' AND ', $conditions );
 637      }
 638  
 639  
 640      // set memory limits.
 641  	public function set_memory_limit( $new_limit ) {
 642          $current_limit     = ini_get( 'memory_limit' );
 643  
 644          if ( '-1' == $current_limit ) {
 645              return false;
 646          }
 647  
 648          $current_limit_int = intval( $current_limit );
 649          if ( false !== strpos( $current_limit, 'G' ) ) {
 650              $current_limit_int *= 1024;
 651          }
 652  
 653          $new_limit_int = intval( $new_limit );
 654          if ( false !== strpos( $new_limit, 'G' ) ) {
 655              $new_limit_int *= 1024;
 656          }
 657  
 658          if ( -1 != $current_limit && ( -1 == $new_limit || $current_limit_int < $new_limit_int ) ) {
 659              ini_set( 'memory_limit', $new_limit );
 660              return true;
 661          }
 662  
 663          return false;
 664      }
 665  
 666  }


Generated: Tue Mar 19 01:01:50 2019 Cross-referenced by PHPXref 0.7.1