[ Index ]

PHP Cross Reference of GlotPress

title

Body

[close]

/gp-includes/things/ -> project.php (source)

   1  <?php
   2  /**
   3   * Things: GP_Project class
   4   *
   5   * @package GlotPress
   6   * @subpackage Things
   7   * @since 1.0.0
   8   */
   9  
  10  /**
  11   * Core class used to implement the projects.
  12   *
  13   * @since 1.0.0
  14   */
  15  class GP_Project extends GP_Thing {
  16  
  17      var $table_basename = 'gp_projects';
  18      var $field_names = array( 'id', 'name', 'slug', 'path', 'description', 'parent_project_id', 'source_url_template', 'active' );
  19      var $int_fields = array( 'id', 'parent_project_id', 'active' );
  20      var $non_updatable_attributes = array( 'id' );
  21  
  22      public $id;
  23      public $name;
  24      public $slug;
  25      public $path;
  26      public $description;
  27      public $parent_project_id;
  28      public $source_url_template;
  29      public $active;
  30      public $user_source_url_template;
  31  
  32      /**
  33       * Sets restriction rules for fields.
  34       *
  35       * @since 1.0.0
  36       *
  37       * @param GP_Validation_Rules $rules The validation rules instance.
  38       */
  39  	public function restrict_fields( $rules ) {
  40          $rules->name_should_not_be( 'empty' );
  41          $rules->slug_should_not_be( 'empty' );
  42      }
  43  
  44      // Additional queries
  45  
  46  	public function by_path( $path ) {
  47          /**
  48           * Filters the prefix for the locale glossary path.
  49           *
  50           * @since 2.3.1
  51           *
  52           * @param string $$locale_glossary_path_prefix Prefix for the locale glossary path.
  53           */
  54          $locale_glossary_path_prefix = apply_filters( 'gp_locale_glossary_path_prefix', '/languages' );
  55  
  56          if ( $locale_glossary_path_prefix === $path ) {
  57              return GP::$glossary->get_locale_glossary_project();
  58          }
  59          return $this->one( "SELECT * FROM $this->table WHERE path = %s", trim( $path, '/' ) );
  60      }
  61  
  62      /**
  63       * Fetches the project by id or object.
  64       *
  65       * @since 2.3.0
  66       *
  67       * @param int|object $thing_or_id A project or the id.
  68       * @return GP_Project The project
  69       */
  70  	public function get( $thing_or_id ) {
  71          if ( is_numeric( $thing_or_id ) && 0 === (int) $thing_or_id ) {
  72              return GP::$glossary->get_locale_glossary_project();
  73          }
  74  
  75          return parent::get( $thing_or_id );
  76      }
  77  
  78      /**
  79       * Retrieves the sub projects
  80       *
  81       * @return array Array of GP_Project
  82       */
  83  	public function sub_projects() {
  84          $sub_projects = $this->many( "SELECT * FROM $this->table WHERE parent_project_id = %d ORDER BY active DESC, id ASC", $this->id );
  85  
  86          /**
  87           * Filter the list of sub-projects of a project.
  88           *
  89           * @since 1.0.0
  90           *
  91           * @param array  $sub_projects An array of sub projects as GP_Project.
  92           * @param string $project_id   ID of the current project. Can be zero at the top level.
  93           */
  94          $sub_projects = apply_filters( 'gp_projects', $sub_projects, $this->id );
  95  
  96          return $sub_projects;
  97      }
  98  
  99  	public function top_level() {
 100          $projects = $this->many( "SELECT * FROM $this->table WHERE parent_project_id IS NULL OR parent_project_id < 1 ORDER BY name ASC" );
 101  
 102          /** This filter is documented in gp-includes/things/project.php */
 103          $projects = apply_filters( 'gp_projects', $projects, 0 );
 104  
 105          return $projects;
 106      }
 107  
 108      // Triggers
 109  
 110      /**
 111       * Executes after creating a project.
 112       *
 113       * @since 1.0.0
 114       *
 115       * @return bool
 116       */
 117  	public function after_create() {
 118          /**
 119           * Fires after creating a project.
 120           *
 121           * @since 1.0.0
 122           *
 123           * @param GP_Project $project The project that was created.
 124           */
 125          do_action( 'gp_project_created', $this );
 126  
 127          // TODO: pass some args to pre/after_create?
 128          if ( is_null( $this->update_path() ) ) {
 129              return false;
 130          }
 131  
 132          return true;
 133      }
 134  
 135      /**
 136       * Executes after saving a project.
 137       *
 138       * @since 1.0.0
 139       * @since 2.4.0 Added the `$project_before` parameter.
 140       *
 141       * @param GP_Project $project_before Project before the update.
 142       * @return bool
 143       */
 144  	public function after_save( $project_before ) {
 145          /**
 146           * Fires after saving a project.
 147           *
 148           * @since 1.0.0
 149           * @since 2.4.0 Added the `$project_before` parameter.
 150           *
 151           * @param GP_Project $project        Project following the update.
 152           * @param GP_Project $project_before Project before the update.
 153           */
 154          do_action( 'gp_project_saved', $this, $project_before );
 155  
 156          // TODO: pass the update args to after/pre_save?
 157          // TODO: only call it if the slug or parent project were changed
 158          return ! is_null( $this->update_path() );
 159      }
 160  
 161      /**
 162       * Executes after deleting a project.
 163       *
 164       * @since 2.0.0
 165       *
 166       * @return bool
 167       */
 168  	public function after_delete() {
 169          /**
 170           * Fires after deleting a project.
 171           *
 172           * @since 2.0.0
 173           *
 174           * @param GP_Project $project The project that was deleted.
 175           */
 176          do_action( 'gp_project_deleted', $this );
 177  
 178          return true;
 179      }
 180  
 181      /**
 182       * Normalizes an array with key-value pairs representing
 183       * a GP_Project object.
 184       *
 185       * @since 1.0.0
 186       *
 187       * @param array $args Arguments for a GP_Project object.
 188       * @return array Normalized arguments for a GP_Project object.
 189       */
 190  	public function normalize_fields( $args ) {
 191          $args = (array) $args;
 192  
 193          if ( isset( $args['parent_project_id'] ) ) {
 194              $args['parent_project_id'] = $this->force_false_to_null( $args['parent_project_id'] );
 195          }
 196  
 197          if ( isset( $args['slug'] ) && !$args['slug'] ) {
 198              $args['slug'] = $args['name'];
 199          }
 200  
 201          if ( ! empty( $args['slug'] ) ) {
 202              $args['slug'] = gp_sanitize_slug( $args['slug'] );
 203          }
 204  
 205          if ( ( isset( $args['path']) && !$args['path'] ) || !isset( $args['path'] ) || is_null( $args['path'] )) {
 206              unset( $args['path'] );
 207          }
 208  
 209          if ( isset( $args['active'] ) ) {
 210              if ( 'on' === $args['active'] ) {
 211                  $args['active'] = 1;
 212              }
 213  
 214              if ( !$args['active'] ) {
 215                  $args['active'] = 0;
 216              }
 217          }
 218  
 219          return $args;
 220      }
 221  
 222      // Helpers
 223  
 224      /**
 225       * Updates this project's and its chidlren's paths, according to its current slug.
 226       */
 227  	public function update_path() {
 228          global $wpdb;
 229          $old_path = isset( $this->path )? $this->path : '';
 230          $parent_project = $this->get( $this->parent_project_id );
 231          if ( $parent_project )
 232              $path = gp_url_join( $parent_project->path, $this->slug );
 233          elseif ( !$wpdb->last_error )
 234              $path = $this->slug;
 235          else
 236              return null;
 237  
 238          $path = trim( $path, '/' );
 239  
 240          $this->path = $path;
 241          $res_self = $this->update( array( 'path' => $path ) );
 242          if ( is_null( $res_self ) ) return $res_self;
 243          // update children's paths, too
 244          if ( $old_path ) {
 245              $query = "UPDATE $this->table SET path = CONCAT(%s, SUBSTRING(path, %d)) WHERE path LIKE %s";
 246              return $this->query( $query, $path, strlen($old_path) + 1, $wpdb->esc_like( $old_path).'%' );
 247          } else {
 248              return $res_self;
 249          }
 250      }
 251  
 252      /**
 253       * Regenrate the paths of all projects from its parents slugs
 254       */
 255  	public function regenerate_paths( $parent_project_id = null ) {
 256          // TODO: do it with one query. Use the tree generation code from GP_Route_Main::_options_from_projects()
 257          if ( $parent_project_id ) {
 258              $parent_project = $this->get( $parent_project_id );
 259              $path = $parent_project->path;
 260          } else {
 261              $path = '';
 262              $parent_project_id = null;
 263          }
 264  
 265          $projects = $this->find( array( 'parent_project_id' => $parent_project_id ) );
 266          foreach( (array)$projects as $project ) {
 267              $project->update( array( 'path' => trim( gp_url_join( $path, $project->slug ), '/' ) ) );
 268              $this->regenerate_paths( $project->id );
 269          }
 270      }
 271  
 272  	public function source_url( $file, $line ) {
 273          $source_url = false;
 274          if ( $source_url_template = $this->source_url_template() ) {
 275              $source_url = str_replace( array( '%file%', '%line%' ), array( $file, $line ), $source_url_template );
 276          }
 277  
 278          /**
 279           * Allows per-reference overriding of the source URL defined as project setting.
 280           *
 281           * @since 2.2.0
 282           *
 283           * @param string|false $source_url The originally generated source URL, or false if no URL is available.
 284           * @param GP_Project $project The current project.
 285           * @param string $file The referenced file name.
 286           * @param string $line The line number in the referenced file.
 287           */
 288          return apply_filters( 'gp_reference_source_url', $source_url, $this, $file, $line );
 289      }
 290  
 291  	public function source_url_template() {
 292          if ( isset( $this->user_source_url_template ) )
 293              return $this->user_source_url_template;
 294          else {
 295              if ( $this->id && is_user_logged_in() && ( $templates = get_user_meta( get_current_user_id(), 'gp_source_url_templates', true ) )
 296                       && isset( $templates[$this->id] ) ) {
 297                  $this->user_source_url_template = $templates[$this->id];
 298                  return $this->user_source_url_template;
 299              } else {
 300                  return $this->source_url_template;
 301              }
 302          }
 303      }
 304  
 305      /**
 306       * Gives an array of project objects starting from the current project
 307       * then its parent, its parent and up to the root
 308       *
 309       * @todo Cache the results. Invalidation is tricky, because on each project update we need to invalidate the cache
 310       * for all of its children.
 311       *
 312       * @return array
 313       */
 314  	public function path_to_root() {
 315          $path = array();
 316          if ( $this->parent_project_id ) {
 317              $parent_project = $this->get( $this->parent_project_id );
 318  
 319              if ( $parent_project ) {
 320                  $path = $parent_project->path_to_root();
 321              }
 322          }
 323          return array_merge( array( &$this ), $path );
 324      }
 325  
 326  	public function set_difference_from( $other_project ) {
 327          $this_sets  = (array) GP::$translation_set->by_project_id( $this->id );
 328          $other_sets = (array) GP::$translation_set->by_project_id( $other_project->id );
 329          $added      = array();
 330          $removed    = array();
 331  
 332          foreach ( $other_sets as $other_set ) {
 333              if ( ! gp_array_any( array( $this, '_compare_set_item' ), $this_sets, $other_set ) ) {
 334                  $added[] = $other_set;
 335              }
 336          }
 337  
 338          foreach ( $this_sets as $this_set ) {
 339              if ( ! gp_array_any( array( $this, '_compare_set_item' ), $other_sets, $this_set ) ) {
 340                  $removed[] = $this_set;
 341              }
 342          }
 343  
 344          return array(
 345              'added' => $added,
 346              'removed' => $removed
 347          );
 348      }
 349  
 350  	public function _compare_set_item( $set, $this_set ) {
 351          return ( $set->locale == $this_set->locale && $set->slug = $this_set->slug );
 352      }
 353  
 354  	public function copy_sets_and_translations_from( $source_project_id ) {
 355          $sets = GP::$translation_set->by_project_id( $source_project_id );
 356  
 357          foreach( $sets as $to_add ) {
 358              $new_set = GP::$translation_set->create( array( 'project_id' => $this->id, 'name' => $to_add->name, 'locale' => $to_add->locale, 'slug' => $to_add->slug ) );
 359              if ( ! $new_set  ) {
 360                  $this->errors[] = sprintf( __( 'Couldn&#8217;t add translation set named %s', 'glotpress' ), esc_html( $to_add->name ) );
 361              } else {
 362                  //Duplicate translations
 363                  $new_set->copy_translations_from( $to_add->id );
 364              }
 365          }
 366      }
 367  
 368  	public function copy_originals_from( $source_project_id ) {
 369          global $wpdb;
 370          return $this->query("
 371              INSERT INTO $wpdb->gp_originals (
 372                  `project_id`, `context`, `singular`, `plural`, `references`, `comment`, `status`, `priority`, `date_added`
 373              )
 374              SELECT
 375                  %s AS `project_id`, `context`, `singular`, `plural`, `references`, `comment`, `status`, `priority`, `date_added`
 376              FROM $wpdb->gp_originals WHERE project_id = %s", $this->id, $source_project_id
 377          );
 378      }
 379  
 380      /**
 381       * Gives an array of project objects starting from the current project children
 382       * then its grand children etc
 383       *
 384       * @return array
 385       */
 386  	public function inclusive_sub_projects() {
 387          $sub_projects = $this->sub_projects();
 388          foreach ( $sub_projects as $sub ) {
 389              $sub_projects = array_merge( $sub_projects, $sub->inclusive_sub_projects() );
 390          }
 391  
 392          return $sub_projects;
 393      }
 394  
 395  	public function duplicate_project_contents_from( $source_project ){
 396          $source_sub_projects = $source_project->inclusive_sub_projects();
 397  
 398          //Duplicate originals, translations sets and translations for the root project
 399          $this->copy_originals_from( $source_project->id ) ;
 400          $this->copy_sets_and_translations_from( $source_project->id );
 401  
 402          //Keep a list of parents to preserve hierarchy
 403          $parents = array();
 404          $parents[$source_project->id] = $this->id;
 405  
 406          //Duplicate originals, translations sets and translations for the child projects
 407          foreach ( $source_sub_projects as $sub ) {
 408              $copy_project = new GP_Project( $sub->fields() );
 409              $copy_project->parent_project_id = $parents[$sub->parent_project_id];
 410              $parent_project = $copy_project->get( $copy_project->parent_project_id );
 411  
 412              $copy_project->path = gp_url_join( $parent_project->path, $copy_project->slug );
 413              $copy = GP::$project->create( $copy_project );
 414              $parents[$sub->id] = $copy->id;
 415  
 416              $copy->copy_originals_from( $sub->id );
 417              $copy->copy_sets_and_translations_from( $sub->id );
 418          }
 419      }
 420  
 421      /**
 422       * Deletes a project and all of sub projects, translations, translation sets, originals and glossaries.
 423       *
 424       * @since 2.0.0
 425       *
 426       * @return bool
 427       */
 428  	public function delete() {
 429          GP::$project->delete_many( array( 'parent_project_id' => $this->id ) );
 430  
 431          GP::$translation_set->delete_many( array( 'project_id' => $this->id ) );
 432  
 433          GP::$original->delete_many( array( 'project_id' => $this->id ) );
 434  
 435          return parent::delete();
 436      }
 437  }
 438  GP::$project = new GP_Project();


Generated: Mon Nov 18 01:01:56 2019 Cross-referenced by PHPXref 0.7.1