Subversion Repositories web.active

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download

<?php namespace ProcessWire;

/**
 * ProcessWire Page Sort Process
 *
 * Saves moved or sorted pages for the PageList process. 
 * Intended to be executed via an ajax call. 
 * 
 * For more details about how Process modules work, please see: 
 * /wire/core/Process.php 
 * 
 * ProcessWire 3.x, Copyright 2016 by Ryan Cramer
 * https://processwire.com
 *
 *
 */

class ProcessPageSort extends Process {

  protected $ids = array(); 
  protected $parent_id = 0; 
  protected $move_id = 0; 
  protected $user; 
  protected $isMoved = false;

  public static function getModuleInfo() {
    return array(
      'title' => __('Page Sort and Move', __FILE__), // getModuleInfo title
      'summary' => __('Handles page sorting and moving for PageList', __FILE__), // getModuleInfo summary
      'version' => 100, 
      'permanent' => true, 
      'permission' => 'page-edit',
      ); 
  }

  /**
   * Install a new permission in addition to the regular ProcessPageSort permission
   *
   * The "ProcessPageSortMove" permission refers to changing the page's parent,
   * whereas the "ProcessPageSort" permission refers to changing the sort within the same parent. 
   *
   */
  public function ___install() {
    parent::___install();
  }

  /**
   * Save a move/sort request
   *
   */
  public function ___execute() {

    if($this->config->demo) throw new WireException($this->_("Your change was not saved because this site is in demo mode")); 
    if(!isset($_POST['sort'])) throw new WireException($this->_("This Process is only accessible via POST")); 
    $this->session->CSRF->validate(); // throws exception if invalid
    $input = $this->wire('input');
    $this->user = $this->wire('user'); 
    $this->ids = array();
    $ids = explode(',', $input->post->sort); 
    foreach($ids as $sort => $id) $this->ids[(int) $sort] = (int) $id; 
    if(!count($this->ids)) return; 
    unset($ids);

    $this->parent_id = (int) $input->post->parent_id; 
    $this->move_id = (int) $input->post->id;
      
    $parentPage = $this->wire('pages')->get($this->parent_id);
    $movePage = $this->wire('pages')->get($this->move_id); 
    if($movePage->id < 2 || !$parentPage->id) return;

    $this->movePage($movePage, $parentPage); 
    $this->sortPages($movePage, $parentPage); 
  } 

  /**
   * Saves a page that has had it's parent_id changed
   * 
   * @param Page $page
   * @param Page $parent
   * @throws WirePermissionException
   *
   */
  protected function movePage(Page $page, Page $parent) {

    if($page->parent_id == $parent->id) return;

    if(!$page->moveable($parent)) {
      throw new WirePermissionException(
        $this->_("You do not have permission to move pages using this parent") . " - " . 
        $parent->path()
      );
    }

    $page->setOutputFormatting(false); 
    $page->resetTrackChanges(true); 
    $page->parent = $parent; 
    $page->save();
    $this->message("Moved page $page to parent $parent"); 
    $this->isMoved = true;
  }

  /**
   * Updates the sortfield for all pages having the same parent
   * 
   * @param Page $page
   * @param Page $parent
   * @throws WirePermissionException|WireException
   *
   */
  protected function sortPages(Page $page, Page $parent) {

    if(!$page->sortable()) { 
      if(!$this->isMoved) {
        throw new WirePermissionException(
          $this->_("You do not have permission to sort pages using this parent") . " - " .
          $parent->path()
        );
      }
      return;
    }

    $sortfield = $parent->sortfield();
    if($sortfield && $sortfield != 'sort') {
      $msg = sprintf($this->_("Your sort was not saved because these pages are automatically sorted by %s."), $sortfield);
      if(!$this->isMoved) {
        throw new WireException($msg);
      } else {
        $this->message($msg);
      }
      return;
    }
    
    $changes = 0; 
    $database = $this->wire('database');

    // locate the 'sort' value of the current first sorted item, to use as our starting point
    // (in case sorting in a pagination other than 1)
    $sql = "SELECT sort FROM pages WHERE parent_id=:parent_id AND id IN("; 
    foreach($this->ids as $id) $sql .= ((int) $id) . ",";
    $sql = rtrim($sql, ",") . ") ";
    if($this->isMoved) $sql .= "AND id!=:move_id ";
    $sql .= "ORDER BY sort LIMIT 1";
    $query = $database->prepare($sql);
    $query->bindValue(":parent_id", $parent->id, \PDO::PARAM_INT);
    if($this->isMoved) $query->bindValue(":move_id", $this->move_id, \PDO::PARAM_INT);
    $query->execute();
    $sortStart = (int) $query->fetchColumn();
    
    $query = $database->prepare("UPDATE pages SET sort=:sort1 WHERE id=:id AND parent_id=:parent_id AND sort!=:sort2");
    $query->bindValue(":parent_id", $parent->id, \PDO::PARAM_INT);
    $pageSort = 0;
    
    foreach($this->ids as $sort => $id) {
      $sort += $sortStart;
      $query->bindValue(":sort1", $sort, \PDO::PARAM_INT);
      $query->bindValue(":sort2", $sort, \PDO::PARAM_INT);
      $query->bindValue(":id", $id, \PDO::PARAM_INT); 
      $query->execute();
      if($query->rowCount() > 0) $changes++;
      if($page->id == $id) $pageSort = $sort; 
    }
  
    // trigger hooks
    $page->set('sort', $pageSort);
    $page->trackChange('sort');
    $page->save();
    $parent->trackChange('children');
    $parent->save();
    $this->wire('pages')->sorted($page, false, $changes);

    if($changes) $this->message("Updated sort for $changes pages", Notice::log); 
    
  }
  
}