Example #1
0
 /**
  * Save individual Page fields and supporting actions
  * 
  * triggers hooks: saved, added, moved, renamed, templateChanged
  * 
  * @param Page $page
  * @param bool $isNew
  * @param array $options
  * @return bool
  * 
  */
 protected function savePageFinish(Page $page, $isNew, array $options)
 {
     $changes = $page->getChanges();
     $changesValues = $page->getChanges(true);
     // update children counts for current/previous parent
     if ($isNew) {
         $page->parent->numChildren++;
     } else {
         if ($page->parentPrevious && $page->parentPrevious->id != $page->parent->id) {
             $page->parentPrevious->numChildren--;
             $page->parent->numChildren++;
         }
     }
     // if page hasn't changed, don't continue further
     if (!$page->isChanged() && !$isNew) {
         $this->debugLog('save', '[not-changed]', true);
         $this->saved($page, array());
         return true;
     }
     // if page has a files path (or might have previously), trigger filesManager's save
     if (PagefilesManager::hasPath($page)) {
         $page->filesManager->save();
     }
     // disable outputFormatting and save state
     $of = $page->of();
     $page->of(false);
     // when a page is statusCorrupted, it records what fields are corrupted in _statusCorruptedFields array
     $corruptedFields = $page->hasStatus(Page::statusCorrupted) ? $page->_statusCorruptedFields : array();
     // save each individual Fieldtype data in the fields_* tables
     foreach ($page->fieldgroup as $field) {
         if (isset($corruptedFields[$field->name])) {
             continue;
         }
         // don't even attempt save of corrupted field
         if (!$field->type) {
             continue;
         }
         try {
             $field->type->savePageField($page, $field);
         } catch (Exception $e) {
             $error = sprintf($this->_('Error saving field "%s"'), $field->name) . ' - ' . $e->getMessage();
             $this->trackException($e, true, $error);
         }
     }
     // return outputFormatting state
     $page->of($of);
     if (empty($page->template->sortfield)) {
         $this->sortfields->save($page);
     }
     if ($options['resetTrackChanges']) {
         $page->resetTrackChanges();
     }
     // determine whether we'll trigger the added() hook
     if ($isNew) {
         $page->setIsNew(false);
         $triggerAddedPage = $page;
     } else {
         $triggerAddedPage = null;
     }
     // check for template changes
     if ($page->templatePrevious && $page->templatePrevious->id != $page->template->id) {
         // the template was changed, so we may have data in the DB that is no longer applicable
         // find unused data and delete it
         foreach ($page->templatePrevious->fieldgroup as $field) {
             if ($page->template->fieldgroup->has($field)) {
                 continue;
             }
             $field->type->deletePageField($page, $field);
             $this->message("Deleted field '{$field}' on page {$page->url}", Notice::debug);
         }
     }
     if ($options['uncacheAll']) {
         $this->uncacheAll($page);
     }
     // determine whether the pages_access table needs to be updated so that pages->find()
     // operations can be access controlled.
     if ($isNew || $page->parentPrevious || $page->templatePrevious) {
         new PagesAccess($page);
     }
     // lastly determine whether the pages_parents table needs to be updated for the find() cache
     // and call upon $this->saveParents where appropriate.
     if ($page->parentPrevious && $page->numChildren > 0) {
         // page is moved and it has children
         $this->saveParents($page->id, $page->numChildren);
         if ($page->parent->numChildren == 1) {
             $this->saveParents($page->parent_id, $page->parent->numChildren);
         }
     } else {
         if ($page->parentPrevious && $page->parent->numChildren == 1 || $isNew && $page->parent->numChildren == 1 || $page->forceSaveParents) {
             // page is moved and is the first child of it's new parent
             // OR page is NEW and is the first child of it's parent
             // OR $page->forceSaveParents is set (debug/debug, can be removed later)
             $this->saveParents($page->parent_id, $page->parent->numChildren);
         }
     }
     if ($page->parentPrevious && $page->parentPrevious->numChildren == 0) {
         // $page was moved and it's previous parent is now left with no children, this ensures the old entries get deleted
         $this->saveParents($page->parentPrevious->id, 0);
     }
     // trigger hooks
     $this->saved($page, $changes, $changesValues);
     if ($triggerAddedPage) {
         $this->added($triggerAddedPage);
     }
     if ($page->namePrevious && $page->namePrevious != $page->name) {
         $this->renamed($page);
     }
     if ($page->parentPrevious) {
         $this->moved($page);
     }
     if ($page->templatePrevious) {
         $this->templateChanged($page);
     }
     if (in_array('status', $changes)) {
         $this->statusChanged($page);
     }
     $this->debugLog('save', $page, true);
     return true;
 }
Example #2
0
 /**
  * Is the given page in a state where it can be saved?
  *
  * @param Page $page
  * @param string $reason Text containing the reason why it can't be saved (assuming it's not saveable)
  * @return bool True if saveable, False if not
  *
  */
 public function isSaveable(Page $page, &$reason)
 {
     $saveable = false;
     $outputFormattingReason = "Call \$page->setOutputFormatting(false) before getting/setting values that will be modified and saved. ";
     if ($page instanceof NullPage) {
         $reason = "Pages of type NullPage are not saveable";
     } else {
         if ((!$page->parent || $page->parent instanceof NullPage) && $page->id !== 1) {
             $reason = "It has no parent assigned";
         } else {
             if (!$page->template) {
                 $reason = "It has no template assigned";
             } else {
                 if (!strlen(trim($page->name))) {
                     $reason = "It has an empty 'name' field";
                 } else {
                     if ($page->is(Page::statusCorrupted)) {
                         $reason = $outputFormattingReason . " [Page::statusCorrupted]";
                     } else {
                         if ($page->id == 1 && !$page->template->useRoles) {
                             $reason = "Selected homepage template cannot be used because it does not define access.";
                         } else {
                             if ($page->id == 1 && !$page->template->hasRole('guest')) {
                                 $reason = "Selected homepage template cannot be used because it does not have the required 'guest' role in it's access settings.";
                             } else {
                                 $saveable = true;
                             }
                         }
                     }
                 }
             }
         }
     }
     // check if they could corrupt a field by saving
     if ($saveable && $page->outputFormatting) {
         // iternate through recorded changes to see if any custom fields involved
         foreach ($page->getChanges() as $change) {
             if ($page->template->fieldgroup->getField($change) !== null) {
                 $reason = $outputFormattingReason . " [{$change}]";
                 $saveable = false;
                 break;
             }
         }
         // iterate through already-loaded data to see if any are objects that have changed
         if ($saveable) {
             foreach ($page->getArray() as $key => $value) {
                 if (!$page->template->fieldgroup->getField($key)) {
                     continue;
                 }
                 if (is_object($value) && $value instanceof Wire && $value->isChanged()) {
                     $reason = $outputFormattingReason . " [{$key}]";
                     $saveable = false;
                     break;
                 }
             }
         }
     }
     // check for a parent change
     if ($saveable && $page->parentPrevious && $page->parentPrevious->id != $page->parent->id) {
         // page was moved
         if ($page->template->noMove && ($page->is(Page::statusSystem) || $page->is(Page::statusSystemID) || !$page->isTrash())) {
             // make sure the page's template allows moves. only move laways allowed is to the trash, unless page has system status
             $saveable = false;
             $reason = "Pages using template '{$page->template}' are not moveable (template::noMove)";
         } else {
             if ($page->parent->template->noChildren) {
                 $saveable = false;
                 $reason = "Chosen parent '{$page->parent->path}' uses template that does not allow children.";
             } else {
                 if ($page->parent->id && $page->parent->id != $this->config->trashPageID && count($page->parent->template->childTemplates) && !in_array($page->template->id, $page->parent->template->childTemplates)) {
                     // make sure the new parent's template allows pages with this template
                     $saveable = false;
                     $reason = "Can't move '{$page->name}' because Template '{$page->parent->template}' used by '{$page->parent->path}' doesn't allow children with this template.";
                 } else {
                     if (count($page->template->parentTemplates) && $page->parent->id != $this->config->trashPageID && !in_array($page->parent->template->id, $page->template->parentTemplates)) {
                         $saveable = false;
                         $reason = "Can't move '{$page->name}' because Template '{$page->parent->template}' used by '{$page->parent->path}' is not allowed by template '{$page->template->name}'.";
                     } else {
                         if (count($page->parent->children("name={$page->name},status<" . Page::statusMax))) {
                             $saveable = false;
                             $reason = "Chosen parent '{$page->parent->path}' already has a page named '{$page->name}'";
                         }
                     }
                 }
             }
         }
     }
     return $saveable;
 }