Custom records: main logic
This is pubKit.record.inc.php, containing the main logic for items based on records in custom tables.
<?php
#::::::::::::::::::::::::::::::::::::::::
# Snippet Name: PubKit
# version: E1.0.0
# pubKit.record.inc.php: included file for custom table handling;
# Big overlap with pubkit.inc.php,
# but enough difference to merit a separate file
#
# Oct 2011: snippet now makes tags into array
# Tags added as item properties, no longer explicitly named in item's class
#
# Snippet code sets parameters and function/class file includes;
# it also creates instance of the object representing the DB record
#::::::::::::::::::::::::::::::::::::::::
#;;;;;;;;;; updates ;;;;;;;;;;;;;;;;;;;;;;;
# May 2011: parameter for form name (see main snippet)
# Upload handling
#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
/* Already happened back in the main snippet code:
$item = new $class($docId, $fields, $lang);
*/
// test if input has come back from form (check for hidden field)
$isPostBack = (isset($fields[$formName])) ? true:false;
// 2-stage deletion - first prompt, delete if confirmed
$isDeletion = isset($fields['confirmDeletion']) ? true:false;
// retrieve or set up object for TVs
// tag TVs use class definition in optionsbuilder.class.php
// Note: though not a resource, record can still use MODx TVs
//
if (!empty($item->tvs)) {
foreach ($item->tvs as $tagTv => $tagProps) {
$fieldName = $tagProps['field'];
$options[$tagTv] = new OptionButtons($tagTv, $fieldName);
if (empty($fields[$fieldName])) {
$tagValues[$tagTv] = array();
$tagValues[$tagTv] = $options[$tagTv]->definition['value'];
} else {
if (is_array($fields[$fieldName])) {
$tagValues[$tagTv] = $fields[$fieldName];
} else {
$tagValues[$tagTv] = explode($delimiter,$fields[$fieldName]);
}
}
}
}
if (!isset($fields['displayDate'])) {
$fields['displayDate'] = $item->defaultDate;
}
$message = NULL;
// get form template. No default - must have a chunk or file
// $formtpl will be final output of the snippet
if (isset($formtpl)) {
if (substr($formtpl,0,5) != '@FILE') {
$formtpl = $modx->getChunk($formtpl);
} else {
$formFile = $chunk_place . 'chunk.' . trim(substr($formtpl,6)) . '.html';
$formtpl = file_get_contents($formFile);
}
} else {
$formtpl = $lang['err_form'];
}
// Form submission: check mandatory fields, build error message
if ($isPostBack) {
// handle file upload, flagged by class having uploadFile property
// uses Upload function in pubKit.functions.php
if (isset($item->uploadFile)) {
if ($_FILES[$item->uploadFile]['size'] === 0) {
if (!empty($fields['currentFile'])) {
$item->uploadAttempt = $fields['currentFile'];
} else {
$item->uploadAttempt = 4;
}
} else {
$item->uploadAttempt = Upload($item->uploadFile, $item->filesHome, $item->allowedTypes);
if (!is_numeric($item->uploadAttempt) AND isset($item->fileTV)) {
$item->tvs[$item->fileTV] = $item->uploadAttempt;
}
}
}
$errors = $item->CheckFields($fields);
if (!isset($postid)) {
$errors[] = $lang['err_postid'];
}
if (!empty($errors)) {
foreach ($errors as $error) {
if (empty($error)) {
$error = 'Error message not defined';
}
$message .= "$error <br /> \n";
}
}
// If error messages exist, skip create/update and redisplay form (populated)
if (!empty($message)) {
$message = '<div id="inputErrors">' . $message . '</div>';
$modx->setPlaceholder('errors', $message);
// experimental (= don't remember doing this!)
if (method_exists($item, 'FailLog')) {
$item->FailLog($fields, $message);
}
} else {
// DB record processing, including ordering and sub-ordering if required
// expects table to have column called rank as main ordering parameter
if (in_array('rank', $item->columns)) {
If (empty($fields['rank'])) {
$fields['rank'] = 9999999;
}
$rankAdjust = ($fields['rank'] < $item->rank) ? -1 : +1;
$fields['rank'] = setFormRank($item->table, $fields['rank'], 2, $rankAdjust);
$item->save($docId,$fields);
if (property_exists($item, 'sortOrder')) {
resetFormRank($item->table, 1, $item->sortOrder);
} else {
resetFormRank($item->table, 1, 'rank');
}
} else {
$item->save($docId,$fields);
}
if (!empty($fields['returnId'])) {
$postid = $fields['returnId'];
}
$redirect = TRUE;
}
}
/******************** Form display operations *******************
* New item, re-edit, request/do deletion,
* or redisplay with error messages and entered data
****************************************************************/
if (!empty($docId) && empty($redirect) && empty($message)) {
$item->Populate($docId);
// turn all record fields into $fields array elements
$customFields = $item->customFields($fields, $docId);
$fields = array_merge($fields, $customFields);
if ($isDeletion) {
if($fields['delete'] == 'Yes') {
$item->Delete($docId);
}
$postid = $fields['returnId'];
$redirect = TRUE;
}
elseif ($cmd == 'delete') {
$formtpl = $modx->getChunk($item->delForm);
$modx->setPlaceholder('docId', $docId);
$modx->setPlaceholder('returnId', $fields['returnId']);
$modx->setPlaceholder('delMsg', $item->delMsg);
}
elseif ($cmd == 'move') {
$rankAdjust = ($fields['to'] < $item->rank) ? -1 : +1;
if ($fields['to'] != $item->rank) {
$newRank = setFormRank($item->table, $fields['to'], 2, $rankAdjust);
$updateFields = array('rank'=>$newRank);
$item->save($docId, $updateFields);
resetFormRank($item->table, 1, $item->sortOrder);
}
$postid = $fields['returnId'];
$redirect = TRUE;
}
elseif ($cmd == 'setField') {
// restrict updated fields to request via second argument of Save()
$item = new $class($docId, $fields, $item->lang);
$update = array();
$target = $fields['docField'];
$update[$target] = $fields['myValue'];
$item->Save($docId, $update);
$postid = $fields['returnId'];
$redirect = TRUE;
}
}
else {
$modx->setPlaceholder('itemStatus', $lang['status_new']);
}
// Create HTML code for option buttons/list (optionsbuilder.class.php)
if (!empty($item->tvs) && empty($redirect)) {
foreach ($item->tvs as $tv => $elements) {
$field = $elements['field'];
$current = $fields[$field];
$modx->setPlaceholder($field, $options[$tv]->BuildSet($current, $elements['format']));
// remove from fields so placeholder doesn't get overwritten
unset($fields[$field]);
}
}
// redirect after item creation/update/publication
// NB no default to current document - we're not in a document!
if ($redirect) {
// clear site cache (see pubKit.functions.php) Is this needed for custom table??
if($clearcache == 1){
emptyCache();
}
// redirect to post id (with anchor #+$prefix+docId if reediting)
// postid may be array of IDs for radio button tags for different pages
// allow for alias in place of ID from preview and delete confirmation
//
if (is_numeric($postid)) {
$landing = $modx->makeUrl($postid);
} else {
$landing = $modx->makeUrl(0, $postid);
}
if (isset($fields['preview'])) {
$landing .= ($modx->config['friendly_urls'] == 1) ? '?' : '&';
$landing .= 'template=preview&docid=' . $doc->Get('id');
} else {
$landing .= (!empty($docId)) ? '#' . $prefix . $docId: '';
}
$modx->sendRedirect($landing);
}
/***************** Prepare form for display *****************/
// check user rights
if(!$allowAnyPost && !$modx->isMemberOfWebGroup($postgrp)) {
$formtpl = $lang['err_permission'];
} else {
// populate form fields placeholders with any existing data
// convert quotes etc. so text fields are not mangled
// assuming XHTML, single quotes are left alone
foreach($fields as $n=>$v) {
if (is_string($v)) {
$v = htmlspecialchars($v);
}
$modx->setPlaceholder($n, $v);
}
}
// PubKit can be used for contact forms, guestbook etc, so add some security
if ($secureForm !== FALSE) {
$modx->runSnippet('setSecurityToken');
}
// return form to snippet call, with debug at top
$pubKit = $dbg . $formtpl;
?>
#::::::::::::::::::::::::::::::::::::::::
# Snippet Name: PubKit
# version: E1.0.0
# pubKit.record.inc.php: included file for custom table handling;
# Big overlap with pubkit.inc.php,
# but enough difference to merit a separate file
#
# Oct 2011: snippet now makes tags into array
# Tags added as item properties, no longer explicitly named in item's class
#
# Snippet code sets parameters and function/class file includes;
# it also creates instance of the object representing the DB record
#::::::::::::::::::::::::::::::::::::::::
#;;;;;;;;;; updates ;;;;;;;;;;;;;;;;;;;;;;;
# May 2011: parameter for form name (see main snippet)
# Upload handling
#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
/* Already happened back in the main snippet code:
$item = new $class($docId, $fields, $lang);
*/
// test if input has come back from form (check for hidden field)
$isPostBack = (isset($fields[$formName])) ? true:false;
// 2-stage deletion - first prompt, delete if confirmed
$isDeletion = isset($fields['confirmDeletion']) ? true:false;
// retrieve or set up object for TVs
// tag TVs use class definition in optionsbuilder.class.php
// Note: though not a resource, record can still use MODx TVs
//
if (!empty($item->tvs)) {
foreach ($item->tvs as $tagTv => $tagProps) {
$fieldName = $tagProps['field'];
$options[$tagTv] = new OptionButtons($tagTv, $fieldName);
if (empty($fields[$fieldName])) {
$tagValues[$tagTv] = array();
$tagValues[$tagTv] = $options[$tagTv]->definition['value'];
} else {
if (is_array($fields[$fieldName])) {
$tagValues[$tagTv] = $fields[$fieldName];
} else {
$tagValues[$tagTv] = explode($delimiter,$fields[$fieldName]);
}
}
}
}
if (!isset($fields['displayDate'])) {
$fields['displayDate'] = $item->defaultDate;
}
$message = NULL;
// get form template. No default - must have a chunk or file
// $formtpl will be final output of the snippet
if (isset($formtpl)) {
if (substr($formtpl,0,5) != '@FILE') {
$formtpl = $modx->getChunk($formtpl);
} else {
$formFile = $chunk_place . 'chunk.' . trim(substr($formtpl,6)) . '.html';
$formtpl = file_get_contents($formFile);
}
} else {
$formtpl = $lang['err_form'];
}
// Form submission: check mandatory fields, build error message
if ($isPostBack) {
// handle file upload, flagged by class having uploadFile property
// uses Upload function in pubKit.functions.php
if (isset($item->uploadFile)) {
if ($_FILES[$item->uploadFile]['size'] === 0) {
if (!empty($fields['currentFile'])) {
$item->uploadAttempt = $fields['currentFile'];
} else {
$item->uploadAttempt = 4;
}
} else {
$item->uploadAttempt = Upload($item->uploadFile, $item->filesHome, $item->allowedTypes);
if (!is_numeric($item->uploadAttempt) AND isset($item->fileTV)) {
$item->tvs[$item->fileTV] = $item->uploadAttempt;
}
}
}
$errors = $item->CheckFields($fields);
if (!isset($postid)) {
$errors[] = $lang['err_postid'];
}
if (!empty($errors)) {
foreach ($errors as $error) {
if (empty($error)) {
$error = 'Error message not defined';
}
$message .= "$error <br /> \n";
}
}
// If error messages exist, skip create/update and redisplay form (populated)
if (!empty($message)) {
$message = '<div id="inputErrors">' . $message . '</div>';
$modx->setPlaceholder('errors', $message);
// experimental (= don't remember doing this!)
if (method_exists($item, 'FailLog')) {
$item->FailLog($fields, $message);
}
} else {
// DB record processing, including ordering and sub-ordering if required
// expects table to have column called rank as main ordering parameter
if (in_array('rank', $item->columns)) {
If (empty($fields['rank'])) {
$fields['rank'] = 9999999;
}
$rankAdjust = ($fields['rank'] < $item->rank) ? -1 : +1;
$fields['rank'] = setFormRank($item->table, $fields['rank'], 2, $rankAdjust);
$item->save($docId,$fields);
if (property_exists($item, 'sortOrder')) {
resetFormRank($item->table, 1, $item->sortOrder);
} else {
resetFormRank($item->table, 1, 'rank');
}
} else {
$item->save($docId,$fields);
}
if (!empty($fields['returnId'])) {
$postid = $fields['returnId'];
}
$redirect = TRUE;
}
}
/******************** Form display operations *******************
* New item, re-edit, request/do deletion,
* or redisplay with error messages and entered data
****************************************************************/
if (!empty($docId) && empty($redirect) && empty($message)) {
$item->Populate($docId);
// turn all record fields into $fields array elements
$customFields = $item->customFields($fields, $docId);
$fields = array_merge($fields, $customFields);
if ($isDeletion) {
if($fields['delete'] == 'Yes') {
$item->Delete($docId);
}
$postid = $fields['returnId'];
$redirect = TRUE;
}
elseif ($cmd == 'delete') {
$formtpl = $modx->getChunk($item->delForm);
$modx->setPlaceholder('docId', $docId);
$modx->setPlaceholder('returnId', $fields['returnId']);
$modx->setPlaceholder('delMsg', $item->delMsg);
}
elseif ($cmd == 'move') {
$rankAdjust = ($fields['to'] < $item->rank) ? -1 : +1;
if ($fields['to'] != $item->rank) {
$newRank = setFormRank($item->table, $fields['to'], 2, $rankAdjust);
$updateFields = array('rank'=>$newRank);
$item->save($docId, $updateFields);
resetFormRank($item->table, 1, $item->sortOrder);
}
$postid = $fields['returnId'];
$redirect = TRUE;
}
elseif ($cmd == 'setField') {
// restrict updated fields to request via second argument of Save()
$item = new $class($docId, $fields, $item->lang);
$update = array();
$target = $fields['docField'];
$update[$target] = $fields['myValue'];
$item->Save($docId, $update);
$postid = $fields['returnId'];
$redirect = TRUE;
}
}
else {
$modx->setPlaceholder('itemStatus', $lang['status_new']);
}
// Create HTML code for option buttons/list (optionsbuilder.class.php)
if (!empty($item->tvs) && empty($redirect)) {
foreach ($item->tvs as $tv => $elements) {
$field = $elements['field'];
$current = $fields[$field];
$modx->setPlaceholder($field, $options[$tv]->BuildSet($current, $elements['format']));
// remove from fields so placeholder doesn't get overwritten
unset($fields[$field]);
}
}
// redirect after item creation/update/publication
// NB no default to current document - we're not in a document!
if ($redirect) {
// clear site cache (see pubKit.functions.php) Is this needed for custom table??
if($clearcache == 1){
emptyCache();
}
// redirect to post id (with anchor #+$prefix+docId if reediting)
// postid may be array of IDs for radio button tags for different pages
// allow for alias in place of ID from preview and delete confirmation
//
if (is_numeric($postid)) {
$landing = $modx->makeUrl($postid);
} else {
$landing = $modx->makeUrl(0, $postid);
}
if (isset($fields['preview'])) {
$landing .= ($modx->config['friendly_urls'] == 1) ? '?' : '&';
$landing .= 'template=preview&docid=' . $doc->Get('id');
} else {
$landing .= (!empty($docId)) ? '#' . $prefix . $docId: '';
}
$modx->sendRedirect($landing);
}
/***************** Prepare form for display *****************/
// check user rights
if(!$allowAnyPost && !$modx->isMemberOfWebGroup($postgrp)) {
$formtpl = $lang['err_permission'];
} else {
// populate form fields placeholders with any existing data
// convert quotes etc. so text fields are not mangled
// assuming XHTML, single quotes are left alone
foreach($fields as $n=>$v) {
if (is_string($v)) {
$v = htmlspecialchars($v);
}
$modx->setPlaceholder($n, $v);
}
}
// PubKit can be used for contact forms, guestbook etc, so add some security
if ($secureForm !== FALSE) {
$modx->runSnippet('setSecurityToken');
}
// return form to snippet call, with debug at top
$pubKit = $dbg . $formtpl;
?>