public static function update(array $item)
{
$db = BackendModel::getContainer()->get('database');
// check if new version is active
if ($item['status'] == 'active') {
// archive all older active versions
$db->update('blog_posts', array('status' => 'archived'), 'id = ? AND status = ?', array($item['id'], $item['status']));
// get the record of the exact item we're editing
$revision = self::getRevision($item['id'], $item['revision_id']);
// assign values
$item['created_on'] = BackendModel::getUTCDate('Y-m-d H:i:s', $revision['created_on']);
$item['num_comments'] = $revision['num_comments'];
// if it used to be a draft that we're now publishing, remove drafts
if ($revision['status'] == 'draft') {
$db->delete('blog_posts', 'id = ? AND status = ?', array($item['id'], $revision['status']));
}
}
// don't want revision id
unset($item['revision_id']);
// how many revisions should we keep
$rowsToKeep = (int) BackendModel::get('fork.settings')->get('Blog', 'max_num_revisions', 20);
// set type of archive
$archiveType = $item['status'] == 'active' ? 'archived' : $item['status'];
// get revision-ids for items to keep
$revisionIdsToKeep = (array) $db->getColumn('SELECT i.revision_id
FROM blog_posts AS i
WHERE i.id = ? AND i.status = ? AND i.language = ?
ORDER BY i.edited_on DESC
LIMIT ?', array($item['id'], $archiveType, BL::getWorkingLanguage(), $rowsToKeep));
// delete other revisions
if (!empty($revisionIdsToKeep)) {
// get meta-ids that will be deleted
$metasIdsToRemove = (array) $db->getColumn('SELECT i.meta_id
FROM blog_posts AS i
WHERE i.id = ? AND revision_id NOT IN (' . implode(', ', $revisionIdsToKeep) . ')', array($item['id']));
// get all the images of the revisions that will NOT be deleted
$imagesToKeep = $db->getColumn('SELECT image FROM blog_posts
WHERE id = ? AND revision_id IN (' . implode(', ', $revisionIdsToKeep) . ')', array($item['id']));
// get the images of the revisions that will be deleted
$imagesOfDeletedRevisions = $db->getColumn('SELECT image FROM blog_posts
WHERE id = ? AND status = ? AND revision_id NOT IN (' . implode(', ', $revisionIdsToKeep) . ')', array($item['id'], $archiveType));
// make sure that an image that will be deleted, is not used by a revision that is not to be deleted
foreach ($imagesOfDeletedRevisions as $imageOfDeletedRevision) {
if (!in_array($imageOfDeletedRevision, $imagesToKeep)) {
BackendModel::deleteThumbnails(FRONTEND_FILES_PATH . '/blog/images', $imageOfDeletedRevision);
}
}
$db->delete('blog_posts', 'id = ? AND status = ? AND revision_id NOT IN (' . implode(', ', $revisionIdsToKeep) . ')', array($item['id'], $archiveType));
if (!empty($metasIdsToRemove)) {
$db->delete('meta', 'id IN (' . implode(', ', $metasIdsToRemove) . ')');
}
}
// insert new version
$item['revision_id'] = BackendModel::getContainer()->get('database')->insert('blog_posts', $item);
// return the new revision id
return $item['revision_id'];
}
/** * Validate the form */ private function validateForm() { // is the form submitted? if ($this->frm->isSubmitted()) { // get the status $status = \SpoonFilter::getPostValue('status', array('active', 'draft'), 'active'); // cleanup the submitted fields, ignore fields that were added by hackers $this->frm->cleanupFields(); // validate fields $this->frm->getField('title')->isFilled(BL::err('TitleIsRequired')); $this->frm->getField('text')->isFilled(BL::err('FieldIsRequired')); $this->frm->getField('publish_on_date')->isValid(BL::err('DateIsInvalid')); $this->frm->getField('publish_on_time')->isValid(BL::err('TimeIsInvalid')); $this->frm->getField('category_id')->isFilled(BL::err('FieldIsRequired')); // validate meta $this->meta->validate(); // no errors? if ($this->frm->isCorrect()) { // build item $item['id'] = $this->id; $item['meta_id'] = $this->meta->save(); // this is used to let our model know the status (active, archive, draft) of the edited item $item['revision_id'] = $this->record['revision_id']; $item['category_id'] = (int) $this->frm->getField('category_id')->getValue(); $item['user_id'] = $this->frm->getField('user_id')->getValue(); $item['language'] = BL::getWorkingLanguage(); $item['title'] = $this->frm->getField('title')->getValue(); $item['introduction'] = $this->frm->getField('introduction')->getValue(); $item['text'] = $this->frm->getField('text')->getValue(); $item['publish_on'] = BackendModel::getUTCDate(null, BackendModel::getUTCTimestamp($this->frm->getField('publish_on_date'), $this->frm->getField('publish_on_time'))); $item['edited_on'] = BackendModel::getUTCDate(); $item['hidden'] = $this->frm->getField('hidden')->getValue(); $item['allow_comments'] = $this->frm->getField('allow_comments')->getChecked() ? 'Y' : 'N'; $item['status'] = $status; if ($this->imageIsAllowed) { $item['image'] = $this->record['image']; // the image path $imagePath = FRONTEND_FILES_PATH . '/blog/images'; // create folders if needed $fs = new Filesystem(); $fs->mkdir(array($imagePath . '/source', $imagePath . '/128x128')); // If the image should be deleted, only the database entry is refreshed. // The revision should keep it's file. if ($this->frm->getField('delete_image')->isChecked()) { // reset the name $item['image'] = null; } // new image given? if ($this->frm->getField('image')->isFilled()) { // build the image name // we use the previous revision-id in the filename to make the filename unique between // the different revisions, to prevent that a new file would // overwrite images of previous revisions that have the same title, and thus, the same filename $item['image'] = $this->meta->getURL() . '-' . BL::getWorkingLanguage() . '-' . $item['revision_id'] . '.' . $this->frm->getField('image')->getExtension(); // upload the image & generate thumbnails $this->frm->getField('image')->generateThumbnails($imagePath, $item['image']); } elseif ($item['image'] != null) { // generate the new filename $image = new File($imagePath . '/source/' . $item['image']); $newName = $this->meta->getURL() . '-' . BL::getWorkingLanguage() . '-' . $item['revision_id'] . '.' . $image->getExtension(); // extract the filenames excluding …-[language]-[revision-id].jpg // to properly compare them to eachother $regex = '/(.*)-[a-z]{2}-[0-9]+\\.(.*)/'; // only copy if the new name differs from the old filename if (preg_replace($regex, '$1', $newName) != preg_replace($regex, '$1', $item['image'])) { // loop folders foreach (BackendModel::getThumbnailFolders($imagePath, true) as $folder) { $fs->copy($folder['path'] . '/' . $item['image'], $folder['path'] . '/' . $newName); } // assign the new name to the database $item['image'] = $newName; } } } else { $item['image'] = null; } // update the item $item['revision_id'] = BackendBlogModel::update($item); // trigger event BackendModel::triggerEvent($this->getModule(), 'after_edit', array('item' => $item)); // recalculate comment count so the new revision has the correct count BackendBlogModel::reCalculateCommentCount(array($this->id)); // save the tags BackendTagsModel::saveTags($item['id'], $this->frm->getField('tags')->getValue(), $this->URL->getModule()); // active if ($item['status'] == 'active') { // edit search index BackendSearchModel::saveIndex($this->getModule(), $item['id'], array('title' => $item['title'], 'text' => $item['text'])); // ping if ($this->get('fork.settings')->get($this->URL->getModule(), 'ping_services', false)) { BackendModel::ping(SITE_URL . BackendModel::getURLForBlock($this->URL->getModule(), 'detail') . '/' . $this->meta->getURL()); } // build URL $redirectUrl = BackendModel::createURLForAction('Index') . '&report=edited&var=' . urlencode($item['title']) . '&id=' . $this->id . '&highlight=row-' . $item['revision_id']; } elseif ($item['status'] == 'draft') { // draft: everything is saved, so redirect to the edit action $redirectUrl = BackendModel::createURLForAction('Edit') . '&report=saved-as-draft&var=' . urlencode($item['title']) . '&id=' . $item['id'] . '&draft=' . $item['revision_id'] . '&highlight=row-' . $item['revision_id']; } // append to redirect URL if ($this->categoryId != null) { $redirectUrl .= '&category=' . $this->categoryId; } // everything is saved, so redirect to the overview $this->redirect($redirectUrl); } } }