Select Git revision
RequestModel.php
RequestModel.php 28.54 KiB
<?php
class Requests_RequestModel extends Unl_Model
{
const FILE_TYPE_SYLLABUS = 'syllabus';
const FILE_TYPE_CROSSLIST_MEMO = 'crosslist memo';
const FILE_TYPE_IS_NARRATIVE = 'isNarrative';
const FILE_TYPE_OTHER = 'other';
static protected $_typeMap;
static public function find($id)
{
$db = Zend_Registry::get('db');
$select = new Zend_Db_Select($db);
$select->from(array('r' => 'creqRequests'));
$select->join(array('t' => 'creqRequestTypes'), 'r.type = t.requestTypeId', array('type' => 'name', 'module'));
if (Unl_Util::isArray($id)) {
if (count($id) == 0) {
return new Unl_Model_Collection(__CLASS__);
}
$select->where('r.requestId IN (?)', $id);
} else {
$select->where('r.requestId = ?', $id);
}
$records = $select->query()->fetchAll();
$objects = new Unl_Model_Collection(__CLASS__);
foreach ($records as $record) {
$record['files'] = array();
$object = Unl_Model_Registry::getInstance()->getOrAdd(new self($record));
$objects[$object->getId()] = $object;
}
$select = new Zend_Db_Select($db);
$select->from(array('r' => 'creqRequestFiles'));
$select->join(array('f' => 'creqFiles'), 'r.file = f.fileId');
if (Unl_Util::isArray($id)) {
$select->where('r.request IN (?)', $id);
} else {
$select->where('r.request = ?', $id);
}
$records = $select->query()->fetchAll();
foreach ($records as $record) {
$objectId = $record['request'];
$requestFileId = $record['requestFileId'];
$objects[$objectId]->_data['files'][$requestFileId] = $record;
}
foreach ($objects as $object) {
foreach($object->_data['files'] as $fileId => $file) {
if ($file['data'] == '') {
$object->_data['files'][$fileId]['data'] = self::_loadFileFromDisk($file['hash']);
}
}
}
// Most recent approval time
$select = new Zend_Db_Select($db);
$select->from(array('h' => 'creqApprovalHistories'), array('request', 'time' => 'MAX(time)'));
$select->group('request');
if (Unl_Util::isArray($id)) {
$select->where('h.request IN (?)', $id);
} else {
$select->where('h.request = ?', $id);
}
$records = $select->query()->fetchAll();
foreach ($records as $record) {
$objectId = $record['request'];
$time = $record['time'];
$objects[$objectId]->_data['lastApprovalTime'] = $time;
}
foreach ($objects as $object) {
$object->_setClean();
}
if (Unl_Util::isArray($id)) {
return $objects;
} else {
return $objects[$id];
}
}
static public function findByRole($role, $visibleOnly = true)
{
$db = Zend_Registry::get('db');
$select = new Zend_Db_Select($db);
if (Unl_Util::isArray($role)) {
if (count($role) == 0) {
return new Unl_Model_Collection(__CLASS__);
}
$roleId = array();
foreach ($role as $aRole) {
$roleId[] = $aRole->getId();
}
} else {
$roleId = $role->getId();
}
$records = array();
$requestIds = array();
// if user is a member of the "root" role, get all active requests
if ((Unl_Util::isArray($roleId) && in_array(1, $roleId)) || $roleId == 1) {
$select = new Zend_Db_Select($db);
$select->from(array('r' => 'creqRequests'), array('requestId'));
$select->where('r.complete != ?', 'yes');
$records = array_merge($records, $select->query()->fetchAll());
foreach ($records as $recordId => $record) {
$records[$recordId]['approvalBodyRole'] = 1;
$records[$recordId]['visible'] = 'yes';
$records[$recordId]['canEdit'] = 'yes';
$requestIds[] = $record['requestId'];
}
}
$select = new Zend_Db_Select($db);
/* old way
$select->from(array('q' => 'creqApprovalBodyRoleQueues'), array('approvalBodyRole', 'visible', 'canEdit'));
$select->join(array('r' => 'creqRequests'), 'q.request = r.requestId', array('requestId'));
if (Unl_Util::isArray($roleId)) {
$select->where('q.approvalBodyRole IN (?)', $roleId);
} else {
$select->where('q.approvalBodyRole = ?', $roleId);
}
if ($visibleOnly) {
$select->where('q.visible = ?', 'yes');
}
*/
$select->from(array('r' => 'creqRequests'), array('requestId'));
$select->join(array('s' => 'creqRequestStacks'), 'r.stackPointer = s.requestStackId', array());
$select->join(array('p' => 'creqApprovalActionParticipants'), 's.action = p.approvalAction', array('approvalBodyRole', 'canEdit'));
if (Unl_Util::isArray($roleId)) {
$select->where('p.approvalBodyRole IN (?)', $roleId);
} else {
$select->where('p.approvalBodyRole = ?', $roleId);
}
$records = array_merge($select->query()->fetchAll(), $records);
foreach ($records as $record) {
$requestIds[] = $record['requestId'];
}
self::find($requestIds);
$objects = array();
foreach ($records as $record) {
$recordRoleId = $record['approvalBodyRole'];
$requestId = $record['requestId'];
unset($record['approvalBodyRole']);
if (!$objects[$recordRoleId] instanceof Unl_Model_Collection) {
$objects[$recordRoleId] = new Unl_Model_Collection(__CLASS__);
}
$object = Unl_Model_Registry::getInstance()->get(__CLASS__, $requestId);
$object->_data = array_merge($object->_data, $record);
$objects[$recordRoleId][$object->getId()] = $object;
}
if (Unl_Util::isArray($roleId)) {
return $objects;
} else {
return $objects[$roleId];
}
}
static public function findByWatchingRole($role)
{
$db = Zend_Registry::get('db');
$roleId = $role->getId();
$select = new Zend_Db_Select($db);
$select->from(array('w' => 'creqRequestWatchers'));
if (Unl_Util::isArray($roleId)) {
if (count($roleId) == 0) {
return new Unl_Model_Collection(__CLASS__);
}
$select->where('w.watchingApprovalRole IN (?)', $roleId);
} else {
$select->where('w.watchingApprovalRole = ?', $roleId);
}
$records = $select->query()->fetchAll();
$requestIds = array();
foreach ($records as $record) {
$requestIds[] = $record['request'];
}
self::find($requestIds);
$objects = array();
foreach ($records as $record) {
$recordRoleId = $record['watchingApprovalRole'];
$requestId = $record['request'];
unset($record['watchingApprovalRole']);
if (!$objects[$recordRoleId] instanceof Unl_Model_Collection) {
$objects[$recordRoleId] = new Unl_Model_Collection(__CLASS__);
}
$object = Unl_Model_Registry::getInstance()->get(__CLASS__, $requestId);
$objects[$recordRoleId][$object->getId()] = $object;
}
if (Unl_Util::isArray($roleId)) {
return $objects;
} else {
return $objects[$roleId];
}
}
static public function findByUser($user, $completeOnly = false)
{
$db = Zend_Registry::get('db');
$userId = $user->getId();
$select = new Zend_Db_Select($db);
$select = new Zend_Db_Select($db);
$select->from(array('r' => 'creqRequests'), array('owner', 'requestId'));
if (Unl_Util::isArray($userId)) {
$select->where('r.owner IN (?)', $userId);
} else {
$select->where('r.owner = ?', $userId);
}
if ($completeOnly) {
$select->where('r.complete = ?', 'no');
}
$records = $select->query()->fetchAll();
$requestIds = array();
foreach ($records as $recordId => $record) {
$records[$recordId]['visible'] = 'yes';
$records[$recordId]['canEdit'] = $records[$recordId]['submitterAttentionRequired'];
$requestIds[] = $record['requestId'];
}
self::find($requestIds);
$objects = array();
if (Unl_Util::isArray($userId)) {
foreach ($userId as $aUserId) {
$objects[$aUserId] = new Unl_Model_Collection(__CLASS__);
}
} else {
$objects[$userId] = new Unl_Model_Collection(__CLASS__);
}
foreach ($records as $record) {
$ownerId = $record['owner'];
$requestId = $record['requestId'];
unset($record['approvalBodyRole']);
if (!$objects[$ownerId] instanceof Unl_Model_Collection) {
$objects[$ownerId] = new Unl_Model_Collection(__CLASS__);
}
$object = Unl_Model_Registry::getInstance()->get(__CLASS__, $requestId);
$object->_data = array_merge($object->_data, $record);
$objects[$ownerId][$object->getId()] = $object;
}
if (Unl_Util::isArray($userId)) {
return $objects;
} else {
return $objects[$userId];
}
}
static protected function _loadTypeMap()
{
if (Unl_Util::isArray(self::$_typeMap)) {
return;
}
$db = Zend_Registry::get('db');
$select = new Zend_Db_Select($db);
$select->from('creqRequestTypes');
$data = $select->query()->fetchAll();
foreach ($data as $row) {
self::$_typeMap[$row['requestTypeId']] = $row['name'];
}
}
static protected function _getTypeIdFromName($name)
{
self::_loadTypeMap();
return array_search($name, self::$_typeMap);
}
static protected function _getTypeNameFromId($id)
{
self::_loadTypeMap();
return self::$_typeMap[$id];
}
static public function getTypes()
{
self::_loadTypeMap();
return self::$_typeMap;
}
static public function fetchNew()
{
$data = array(
'requestId' => null,
'owner' => null,
'justification' => null,
'stackPointer' => null,
'state' => null,
'submitterAttentionRequired' => 'no',
'type' => null,
'complete' => 'no',
'module' => null,
'files' => array()
);
$new = new self($data);
$new->_setClean();
return $new;
}
static public function save($models)
{
$db = Zend_Registry::get('db');
$db->beginTransaction();
$unsavedData = array();
foreach ($models as $id => $model) {
$unsavedData[$id] = $model->_data;
}
try {
if (!Unl_Util::isArray($models)) {
$collection = new Unl_Model_Collection(__CLASS__);
$collection[] = $models;
$models = $collection;
}
$modelsToInsert = array();
$modelsToUpdate = array();
$requestTableColumns = array('owner', 'justification', 'stackPointer', 'state', 'submitterAttentionRequired', 'type', 'complete');
foreach ($models as $model) {
$data = array_intersect_key($model->_data, array_flip($requestTableColumns));
$cleanData = array_intersect_key($model->_cleanData, array_flip($requestTableColumns));
if ($data == $cleanData) {
continue;
}
if ($model->getId()) {
$modelsToUpdate[] = $model;
} else {
$modelsToInsert[] = $model;
}
}
self::_insertRequestRows($modelsToInsert);
self::_updateRequestRows($modelsToUpdate);
$filesToInsert = array();
$filesToUpdate = array();
foreach ($models as $model) {
foreach ($model->_data['files'] as $fileId => $file) {
$model->_data['files'][$fileId]['request'] = $model->getId();
$fileRef = array(
'model' => $model,
'fileId' => $fileId
);
if ($fileId < 0) {
$filesToInsert[] = $fileRef;
} else {
$filesToUpdate[] = $fileRef;
}
}
}
$filesToDelete = array();
foreach ($models as $model) {
$cleanFileIds = array_keys($model->_cleanData['files']);
$dirtyFileIds = array_keys($model->_data['files']);
foreach ($cleanFileIds as $cleanFileId) {
if (!in_array($cleanFileId, $dirtyFileIds)) {
$filesToDelete[] = $model->_cleanData['files'][$cleanFileId];
}
}
}
self::_insertFileRows($filesToInsert);
self::_updateFileRows($filesToUpdate);
self::_deleteFileRows($filesToDelete);
foreach ($models as $model) {
foreach (array_keys($model->_data['files']) as $fileKey) {
if ($fileKey >= 0) {
continue;
}
$newFileKey = $model->_data['files'][$fileKey]['requestFileId'];
$model->_data['files'][$newFileKey] = $model->_data['files'][$fileKey];
unset($model->_data['files'][$fileKey]);
}
}
foreach ($models as $model) {
$model->_setClean();
}
$db->commit();
} catch (Exception $e) {
$db->rollback();
foreach ($models as $id => $model) {
$model->_data = $unsavedData[$id];
}
throw $e;
}
}
static protected function _insertRequestRows($models)
{
if (count($models) == 0) {
return;
}
$db = Zend_Registry::get('db');
$sql = 'INSERT INTO creqRequests (owner, justification, stackPointer, state, submitterAttentionRequired, type, complete) VALUES ';
$sqlParts = array();
foreach ($models as $model) {
$sqlParts[] = $db->quoteInto('(?, ', $model->_data['owner'])
. $db->quoteInto('?, ' , $model->_data['justification'])
. $db->quoteInto('?, ' , $model->_data['stackPointer'])
. $db->quoteInto('?, ' , $model->_data['state'])
. $db->quoteInto('?, ' , $model->_data['submitterAttentionRequired'])
. $db->quoteInto('?, ' , self::_getTypeIdFromName($model->_data['type']))
. $db->quoteInto('?)' , $model->_data['complete']);
}
$sql .= implode(', ', $sqlParts);
$db->query($sql);
$lastId = $db->lastInsertId();
foreach ($models as $model) {
$model->_data['requestId'] = $lastId;
$lastId++;
}
}
static protected function _updateRequestRows($models)
{
if (count($models) == 0) {
return;
}
$db = Zend_Registry::get('db');
$sql = 'CREATE TEMPORARY TABLE creqRequestsUpdate '
. 'SELECT * FROM creqRequests LIMIT 0';
$db->query($sql);
$sql = 'INSERT INTO creqRequestsUpdate VALUES ';
$sqlParts = array();
foreach ($models as $model) {
$sqlParts[] = $db->quoteInto('(?, ', $model->_data['requestId'])
. $db->quoteInto('?, ' , $model->_data['owner'])
. $db->quoteInto('?, ' , $model->_data['justification'])
. $db->quoteInto('?, ' , $model->_data['stackPointer'])
. $db->quoteInto('?, ' , $model->_data['state'])
. $db->quoteInto('?, ' , $model->_data['submitterAttentionRequired'])
. $db->quoteInto('?, ' , self::_getTypeIdFromName($model->_data['type']))
. $db->quoteInto('?)' , $model->_data['complete']);
}
$sql .= implode(', ', $sqlParts);
$db->query($sql);
$sql = 'UPDATE creqRequests AS a, '
. ' creqRequestsUpdate AS b '
. 'SET a.requestId = b.requestId, '
. ' a.owner = b.owner, '
. ' a.justification = b.justification, '
. ' a.stackPointer = b.stackPointer, '
. ' a.state = b.state, '
. ' a.submitterAttentionRequired = b.submitterAttentionRequired, '
. ' a.type = b.type, '
. ' a.complete = b.complete '
. 'WHERE a.requestId = b.requestId ';
$db->query($sql);
$db->query('DROP TABLE creqRequestsUpdate');
}
static protected function _insertFileRows($models)
{
if (count($models) == 0) {
return;
}
$db = Zend_Registry::get('db');
$sql = 'INSERT INTO creqFiles (title, mimeType, data, hash) VALUES ';
$sqlParts = array();
foreach ($models as $model) {
$file = $model['model']->_data['files'][$model['fileId']];
$file['hash'] = hash('whirlpool', $file['data']);
if (strlen($file['data']) >= 0) {
self::_saveFileToDisk($file['data']);
$file['data'] = "''";
} else {
$file['data'] = '0x' . bin2hex($file['data']);
}
$sqlParts[] = $db->quoteInto('(?, ', $file['title'])
. $db->quoteInto('?, ' , $file['mimeType'])
. $file['data'] . ', '
. $db->quoteInto('?)' , $file['hash']);
}
$sql .= implode(', ', $sqlParts);
$db->query($sql);
$lastId = $db->lastInsertId();
foreach ($models as $model) {
$model['model']->_data['files'][$model['fileId']]['fileId'] = $lastId;
$lastId++;
}
$sql = 'INSERT INTO creqRequestFiles (file, request, type) VALUES ';
$sqlParts = array();
foreach ($models as $model) {
$file = $model['model']->_data['files'][$model['fileId']];
$model = $model['model'];
$sqlParts[] = $db->quoteInto('(?, ', $file['fileId'])
. $db->quoteInto('?, ' , $model->getId())
. $db->quoteInto('?)' , $file['type']);
}
$sql .= implode(', ', $sqlParts);
$db->query($sql);
$lastId = $db->lastInsertId();
foreach ($models as $model) {
$model['model']->_data['files'][$model['fileId']]['requestFileId'] = $lastId;
$lastId++;
}
}
static protected function _updateFileRows($models)
{
if (count($models) == 0) {
return;
}
$db = Zend_Registry::get('db');
$sql = 'CREATE TEMPORARY TABLE creqFilesUpdate '
. 'SELECT * FROM creqFiles LIMIT 0';
$db->query($sql);
$sql = 'INSERT INTO creqFilesUpdate VALUES ';
$sqlParts = array();
foreach ($models as $model) {
$file = $model['model']->_data['files'][$model['fileId']];
$file['hash'] = hash('whirlpool', $file['data']);
if (strlen($file['data']) >= 0) {
self::_saveFileToDisk($file['data']);
$file['data'] = "''";
} else {
$file['data'] = '0x' . bin2hex($file['data']);
}
$sqlParts[] = $db->quoteInto('(?, ', $file['fileId'])
. $db->quoteInto('?, ' , $file['title'])
. $db->quoteInto('?, ' , $file['mimeType'])
. $file['data'] . ', '
. $db->quoteInto('?)' , $file['hash']);
}
$sql .= implode(', ', $sqlParts);
$db->query($sql);
$sql = 'UPDATE creqFiles AS a, '
. ' creqFilesUpdate AS b '
. 'SET a.title = b.title, '
. ' a.mimeType = b.mimeType, '
. ' a.data = b.data, '
. ' a.hash = b.hash '
. 'WHERE a.fileId = b.fileId ';
$db->query($sql);
$db->query('DROP TABLE creqFilesUpdate');
$sql = 'CREATE TEMPORARY TABLE creqRequestFilesUpdate '
. 'SELECT * FROM creqRequestFiles LIMIT 0';
$db->query($sql);
$sql = 'INSERT INTO creqRequestFilesUpdate VALUES ';
$sqlParts = array();
foreach ($models as $model) {
$file = $model['model']->_data['files'][$model['fileId']];
$model = $model['model'];
$sqlParts[] = $db->quoteInto('(?, ', $file['requestFileId'])
. $db->quoteInto('?, ' , $file['fileId'])
. $db->quoteInto('?, ' , $model->getId())
. $db->quoteInto('?)' , $file['type']);
}
$sql .= implode(', ', $sqlParts);
$db->query($sql);
$sql = 'UPDATE creqRequestFiles AS a, '
. ' creqRequestFilesUpdate AS b '
. 'SET a.file = b.file, '
. ' a.request = b.request, '
. ' a.type = b.type '
. 'WHERE a.requestFileId = b.requestFileId ';
$db->query($sql);
$db->query('DROP TABLE creqRequestFilesUpdate');
}
static protected function _deleteFileRows($models)
{
if (count($models) == 0) {
return;
}
$db = Zend_Registry::get('db');
$requestFileIds = array();
$fileIds = array();
foreach ($models as $model) {
$requestFileIds[] = $model['requestFileId'];
$fileIds[] = $model['fileId'];
}
$sql = $db->quoteInto('DELETE FROM creqRequestFiles WHERE requestFileId IN (?)', $requestFileIds);
$db->query($sql);
$sql = $db->quoteInto('DELETE FROM creqFiles WHERE fileId IN (?)', $fileIds);
$db->query($sql);
}
static protected function _saveFileToDisk($data)
{
$hash = hash('whirlpool', $data);
$path = APPLICATION_DIR
. DIRECTORY_SEPARATOR
. 'uploads'
. DIRECTORY_SEPARATOR
. substr($hash, 0, 1)
. DIRECTORY_SEPARATOR
. substr($hash, 1, 2);
if (!file_exists($path)) {
@mkdir($path, 0755, true);
}
file_put_contents($path . DIRECTORY_SEPARATOR . $hash, $data);
}
static protected function _loadFileFromDisk($hash)
{
$path = APPLICATION_DIR
. DIRECTORY_SEPARATOR
. 'uploads'
. DIRECTORY_SEPARATOR
. substr($hash, 0, 1)
. DIRECTORY_SEPARATOR
. substr($hash, 1, 2);
if (!file_exists($path)) {
@mkdir($path, 0755, true);
}
$data = @file_get_contents($path . DIRECTORY_SEPARATOR . $hash);
return $data;
}
public function __sleep()
{
foreach ($this->_data['files'] as &$file) {
if (!$file['data']) {
continue;
}
self::_saveFileToDisk($file['data']);
$file['data'] = '';
}
return array_keys(get_object_vars($this));
}
public function __wakeup()
{
foreach ($this->_data['files'] as &$file) {
if ($file['data']) {
continue;
}
$file['data'] = self::_loadFileFromDisk($file['hash']);
}
}
public function getId()
{
return $this->_data['requestId'];
}
public function getType()
{
return $this->_data['type'];
}
public function getTypeId()
{
return self::_getTypeIdFromName($this->_data['type']);
}
public function setType($type)
{
if (!in_array($type, array('NewCourse', 'ChangeCourse', 'RemoveCourse', 'AddISToCourse', 'NewCourseWithIS', 'NewCourseWithACE', 'AddACEToCourse', 'AddACEAndChangeCourse', 'RemoveACEFromCourse', 'RemoveACEAndChangeCourse'))) {
throw new Exception('Unknown request type!');
}
$this->_data['type'] = $type;
}
public function isVisible()
{
return (bool) ($this->_data['visible'] == 'yes');
}
public function isEditable() {
return (bool) ($this->_data['canEdit'] == 'yes');
}
public function isComplete() {
return (bool) ($this->_data['complete'] == 'yes');
}
public function setComplete($complete = true)
{
if ($complete) {
$this->_data['complete'] = 'yes';
} else {
$this->_data['complete'] = 'no';
}
}
public function isSubmitterAttentionRequired()
{
return (bool) ($this->_data['submitterAttentionRequired'] == 'yes');
}
public function setSubmitterAttentionRequired($set = true)
{
if ($set) {
$this->_data['submitterAttentionRequired'] = 'yes';
} else {
$this->_data['submitterAttentionRequired'] = 'no';
}
}
public function getOwner()
{
return $this->_data['owner'];
}
public function setOwner(Auth_UserModel $owner)
{
$this->_data['owner'] = $owner->getId();
}
public function getState()
{
return $this->_data['state'];
}
public function setState($state)
{
$this->_data['state'] = $state;
}
public function getModule()
{
return $this->_data['module'];
}
public function setModule($module)
{
$this->_data['module'] = $module;
}
public function getJustification()
{
return $this->_data['justification'];
}
public function setJustification($justification)
{
$this->_data['justification'] = $justification;
}
public function getFile($type)
{
$requestedFile = null;
foreach ($this->_data['files'] as $file) {
if ($file['type'] == $type) {
$requestedFile = $file;
break;
}
}
return $requestedFile;
}
public function getFileById($id)
{
return $this->_data['files'][$id];
}
public function getFiles($type)
{
$requestedFiles = array();
foreach ($this->_data['files'] as $id => $file) {
if ($file['type'] == $type) {
$requestedFiles[$id] = $file;
}
}
return $requestedFiles;
}
public function addFile($type, $title, $mimeType, $data)
{
$lowestId = min(array_keys($this->_data['files']));
if (!($lowestId < 0)) {
$lowestId = 0;
}
$lowestId--;
$newFile = array(
'type' => $type,
'title' => $title,
'mimeType' => $mimeType,
'data' => $data,
'hash' => hash('whirlpool', $data)
);
$this->_data['files'][$lowestId] = $newFile;
}
public function setFile($type, $title, $mimeType, $data)
{
$found = false;
foreach ($this->_data['files'] as $id => $file) {
if ($file['type'] == $type) {
$this->_data['files'][$id]['title'] = $title;
$this->_data['files'][$id]['mimeType'] = $mimeType;
$this->_data['files'][$id]['data'] = $data;
$this->_data['files'][$id]['hash'] = hash('whirlpool', $data);
$found = true;
}
}
if ($found) {
return;
}
$lowestId = min(array_keys($this->_data['files']));
if (!($lowestId < 0)) {
$lowestId = 0;
}
$lowestId--;
$newFile = array(
'type' => $type,
'title' => $title,
'mimeType' => $mimeType,
'data' => $data,
'hash' => hash('whirlpool', $data)
);
$this->_data['files'][$lowestId] = $newFile;
}
public function removeFile($type)
{
foreach ($this->_data['files'] as $fileId => $file) {
if ($file['type'] == $type) {
unset($this->_data['files'][$fileId]);
}
}
}
public function removeFileById($id)
{
unset($this->_data['files'][$id]);
}
public function getStackPointer()
{
return $this->_data['stackPointer'];
}
public function setStackPointer(Requests_StackModel $stack)
{
$this->_data['stackPointer'] = $stack->getId();
}
public function clearStackPointer()
{
$this->_data['stackPointer'] = NULL;
}
public function getLastApprovalTime()
{
$time = $this->_data['lastApprovalTime'];
if ($time > 0) {
return new Zend_Date($time);
}
return null;
}
public function isValid()
{
//TODO: add criteria for this being valid
if (!$this->getJustification()) {
return false;
}
return true;
}
}