classes/Gems/Agenda.php
<?php
/**
*
* @package Gems
* @subpackage Agenda
* @author Matijs de Jong <mjong@magnafacta.nl>
* @copyright Copyright (c) 2013 Erasmus MC
* @license New BSD License
*/
use Gems\Agenda\AppointmentFilterInterface;
use Gems\Agenda\AppointmentSelect;
use Gems\Agenda\EpisodeOfCare;
/**
*
*
* @package Gems
* @subpackage Agenda
* @copyright Copyright (c) 2013 Erasmus MC
* @license New BSD License
* @since Class available since version 1.6.2
*/
class Gems_Agenda extends \Gems_Loader_TargetLoaderAbstract
{
/**
*
* @var \Gems_Agenda_Appointment[]
*/
private $_appointments = array();
/**
*
* @var AppointmentFilterInterface[]
*/
private $_filters = array();
/**
*
* @var string
*/
public $appointmentDisplayFormat = 'dd-MM-yyyy HH:mm';
/**
*
* @var string
*/
public $episodeDisplayFormat = 'dd-MM-yyyy';
/**
*
* @var \Zend_Cache_Core
*/
protected $cache;
/**
* Allows sub classes of \Gems_Loader_LoaderAbstract to specify the subdirectory where to look for.
*
* @var string $cascade An optional subdirectory where this subclass always loads from.
*/
protected $cascade = 'Agenda';
/**
*
* @var \Zend_Db_Adapter_Abstract
*/
protected $db;
/**
*
* @var \Gems_Loader
*/
protected $loader;
/**
*
* @var \Zend_Translate
*/
protected $translate;
/**
*
* @var \Zend_Translate_Adapter
*/
protected $translateAdapter;
/**
* @var \Gems_Util
*/
protected $util;
/**
*
* @param type $container A container acting as source for \MUtil_Registry_Source
* @param array $dirs The directories where to look for requested classes
*/
public function __construct($container, array $dirs)
{
parent::__construct($container, $dirs);
// Make sure the tracker is known
$this->addRegistryContainer(array('agenda' => $this));
}
/**
* Copy from \Zend_Translate_Adapter
*
* Translates the given string
* returns the translation
*
* @param string $text Translation string
* @param string|\Zend_Locale $locale (optional) Locale/Language to use, identical with locale
* identifier, @see \Zend_Locale for more information
* @return string
*/
public function _($text, $locale = null)
{
return $this->translateAdapter->_($text, $locale);
}
/**
* Get the select statement for appointments in getAppointments()
*
* Allows for overruling on project level
*
* @return \Zend_Db_Select
*/
protected function _getAppointmentSelect()
{
$select = $this->db->select();
$select->from('gems__appointments')
->joinLeft( 'gems__agenda_activities', 'gap_id_activity = gaa_id_activity')
->joinLeft('gems__agenda_procedures', 'gap_id_procedure = gapr_id_procedure')
->joinLeft('gems__locations', 'gap_id_location = glo_id_location')
->order('gap_admission_time DESC');
return $select;
}
/**
* Called after the check that all required registry values
* have been set correctly has run.
*
* This function is no needed if the classes are setup correctly
*
* @return void
*/
public function afterRegistry()
{
parent::afterRegistry();
$this->initTranslateable();
}
/**
* Add Activities to the table
*
* Override this method for other defaults
*
* @param string $name
* @param int $organizationId
* @return array
*/
public function addActivity($name, $organizationId)
{
$model = new \MUtil_Model_TableModel('gems__agenda_activities');
\Gems_Model::setChangeFieldsByPrefix($model, 'gaa');
$values = array(
'gaa_name' => $name,
'gaa_id_organization' => $organizationId,
'gaa_match_to' => $name,
'gaa_active' => 1,
'gaa_filter' => 0,
);
$result = $model->save($values);
$this->cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, array('activity', 'activities'));
return $result;
}
/**
* Add HealthcareStaff to the table
*
* Override this method for other defaults
*
* @param string $name
* @param int $organizationId
* @return array
*/
public function addHealthcareStaff($name, $organizationId)
{
$model = new \MUtil_Model_TableModel('gems__agenda_staff');
\Gems_Model::setChangeFieldsByPrefix($model, 'gas');
$values = array(
'gas_name' => $name,
'gas_id_organization' => $organizationId,
'gas_match_to' => $name,
'gas_active' => 1,
'gas_filter' => 0,
);
$result = $model->save($values);
$this->cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, array('staff'));
return $result;
}
/**
*
* @param type $name
* @param type $organizationId
* @param array $matches
* @return array
*/
public function addLocation($name, $organizationId, $matches)
{
if (empty($matches)) {
// A new match
$values = array(
'glo_name' => $name,
'glo_organizations' => ':' . $organizationId . ':',
'glo_match_to' => $name,
'glo_active' => 1,
'glo_filter' => 0,
);
} else {
// Update
$first = reset($matches);
// Change this match, add this organization
$values = array(
'glo_id_location' => $first['glo_id_location'],
'glo_organizations' => ':' . implode(':', array_keys($matches)) . ':' .
$organizationId . ':'
);
}
$model = new \MUtil_Model_TableModel('gems__locations');
\Gems_Model::setChangeFieldsByPrefix($model, 'glo');
$result = $model->save($values);
$this->cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, array('location', 'locations'));
return $result;
}
/**
* Add Procedure to the table
*
* Override this method for other defaults
*
* @param string $name
* @param int $organizationId
* @return array
*/
public function addProcedure($name, $organizationId)
{
$model = new \MUtil_Model_TableModel('gems__agenda_procedures');
\Gems_Model::setChangeFieldsByPrefix($model, 'gapr');
$values = array(
'gapr_name' => $name,
'gapr_id_organization' => $organizationId,
'gapr_match_to' => $name,
'gapr_active' => 1,
'gapr_filter' => 0,
);
$result = $model->save($values);
$this->cache->clean(\Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG, array('procedure', 'procedures'));
return $result;
}
/**
* Dynamically load and create a [Gems|Project]_Agenda_ class
*
* @param string $className
* @param mixed $param1
* @param mixed $param2
* @return object
*/
public function createAgendaClass($className, $param1 = null, $param2 = null)
{
$params = func_get_args();
array_shift($params);
return $this->_loadClass($className, true, $params);
}
/**
* Create agenda select
*
* @param string|array $fields The appointment fields to select
* @return \Gems\Agenda\AppointmentSelect
*/
public function createAppointmentSelect($fields = '*')
{
return $this->_loadClass('AppointmentSelect', true, array($fields));
}
/**
* Get all active respondents for this user
*
* @param int $respondentId When null $patientNr is required
* @param int $organizationId
* @param string $patientNr Optional for when $respondentId is null
* @param string $where Optional extra where statement
* @return array appointmentId => appointment description
*/
public function getActiveAppointments($respondentId, $organizationId, $patientNr = null, $where = null)
{
if ($where) {
$where = "($where) AND ";
} else {
$where = "";
}
$where .= sprintf('gap_status IN (%s)', $this->getStatusKeysActiveDbQuoted());
return $this->getAppointments($respondentId, $organizationId, $patientNr, $where);
}
/**
*
* @param int $organizationId Optional
* @return array activity_id => name
*/
public function getActivities($organizationId = null)
{
$cacheId = __CLASS__ . '_' . __FUNCTION__ . '_' . $organizationId;
if ($results = $this->cache->load($cacheId)) {
return $results;
}
$select = $this->db->select();
$select->from('gems__agenda_activities', array('gaa_id_activity', 'gaa_name'))
->order('gaa_name');
if ($organizationId) {
// Check only for active when with $orgId: those are usually used
// with editing, while the whole list is used for display.
$select->where('gaa_active = 1')
->where('(
gaa_id_organization IS NULL
AND
gaa_name NOT IN (SELECT gaa_name FROM gems__agenda_activities WHERE gaa_id_organization = ?)
) OR
gaa_id_organization = ?', $organizationId);
}
// \MUtil_Echo::track($select->__toString());
$results = $this->db->fetchPairs($select);
$this->cache->save($results, $cacheId, array('activities'));
return $results;
}
/**
* Overrule this function to adapt the display of the agenda items for each project
*
* @see \Gems_Agenda_Appointment->getDisplayString()
*
* @param array $row Row containing result select
* @return string
*/
public function getAppointmentDisplay(array $row)
{
$date = new \MUtil_Date($row['gap_admission_time'], 'yyyy-MM-dd HH:mm:ss');
$results[] = $date->toString($this->appointmentDisplayFormat);
if ($row['gaa_name']) {
$results[] = $row['gaa_name'];
}
if ($row['gapr_name']) {
$results[] = $row['gapr_name'];
}
if ($row['glo_name']) {
$results[] = $row['glo_name'];
}
return implode($this->_('; '), $results);
}
/**
* Get an appointment object
*
* @param mixed $appointmentData Appointment id or array containing appointment data
* @return \Gems_Agenda_Appointment
*/
public function getAppointment($appointmentData)
{
if (! $appointmentData) {
throw new \Gems_Exception_Coding('Provide at least the apppointment id when requesting an appointment.');
}
if (is_array($appointmentData)) {
if (!isset($appointmentData['gap_id_appointment'])) {
throw new \Gems_Exception_Coding(
'$appointmentData array should atleast have a key "gap_id_appointment" containing the requested appointment id'
);
}
$appointmentId = $appointmentData['gap_id_appointment'];
} else {
$appointmentId = $appointmentData;
}
// \MUtil_Echo::track($appointmentId, $appointmentData);
if (! isset($this->_appointments[$appointmentId])) {
$this->_appointments[$appointmentId] = $this->_loadClass('appointment', true, array($appointmentData));
} elseif (is_array($appointmentData)) {
// Make sure the new values are set in the object
$this->_appointments[$appointmentId]->refresh($appointmentData);
}
return $this->_appointments[$appointmentId];
}
/**
* Get all appointments for a respondent
*
* @param int $respondentId When null $patientNr is required
* @param int $organizationId
* @param string $patientNr Optional for when $respondentId is null
* @param string $where Optional extra where statement
* @return array appointmentId => appointment description
*/
public function getAppointments($respondentId, $organizationId, $patientNr = null, $where = null)
{
$select = $this->_getAppointmentSelect();
if ($where) {
$select->where($where);
}
if ($respondentId) {
$select->where('gap_id_user = ?', $respondentId)
->where('gap_id_organization = ?', $organizationId);
} else {
// Join might have been created in _getAppointmentSelect
$from = $select->getPart(\Zend_Db_Select::FROM);
if (! isset($from['gems__respondent2org'])) {
$select->joinInner(
'gems__respondent2org',
'gap_id_user = gr2o_id_user AND gap_id_organization = gr2o_id_organization',
array()
);
}
$select->where('gr2o_patient_nr = ?', $patientNr)
->where('gr2o_id_organization = ?', $organizationId);
}
// \MUtil_Echo::track($select->__toString());
$rows = $this->db->fetchAll($select);
if (! $rows) {
return array();
}
$results = array();
foreach ($rows as $row) {
$results[$row['gap_id_appointment']] = $this->getAppointmentDisplay($row);
}
return $results;
}
/**
* Get all appointments for an episode
*
* @param int|Episode $episode Episode Id or object
* @return array appointmentId => appointment object
*/
public function getAppointmentsForEpisode($episode)
{
$select = $this->_getAppointmentSelect();
if ($episode instanceof EpisodeOfCare) {
$episodeId = $episode->getId();
} else {
$episodeId = $episode;
}
$select->where('gap_id_episode = ?', $episodeId);
// \MUtil_Echo::track($select->__toString());
$rows = $this->db->fetchAll($select);
if (! $rows) {
return array();
}
$results = array();
foreach ($rows as $row) {
$results[$row['gap_id_appointment']] = $this->getAppointment($row);
}
return $results;
}
/**
* Get a selection list of coding systems used
*
* @return array code => label
*/
public function getDiagnosisCodingSystems()
{
return [
'DBC' => $this->_('DBC (Dutch Diagnosis Treatment Code)'),
'manual' => $this->_('Manual (organization specific)'),
];
}
/**
* Get an appointment object
*
* @param mixed $episodeData Episode id or array containing episode data
* @return \Gems\Agenda\EpisodeOfCare
*/
public function getEpisodeOfCare($episodeData)
{
if (! $episodeData) {
throw new \Gems_Exception_Coding('Provide at least the episode id when requesting an episode of care.');
}
if (is_array($episodeData)) {
if (!isset($episodeData['gec_episode_of_care_id'])) {
throw new \Gems_Exception_Coding(
'$episodeData array should atleast have a key "gec_episode_of_care_id" containing the requested episode id'
);
}
}
// \MUtil_Echo::track($appointmentId, $appointmentData);
return $this->_loadClass('episodeOfCare', true, array($episodeData));
}
/**
* Get the status codes for all episode of care items
*
* @return array code => label
*/
public function getEpisodeStatusCodes()
{
$codes = $this->getEpisodeStatusCodesActive() +
$this->getEpisodeStatusCodesInactive();
asort($codes);
return $codes;
}
/**
* Get the status codes for active episode of care items
*
* see https://www.hl7.org/fhir/episodeofcare.html
*
* @return array code => label
*/
public function getEpisodeStatusCodesActive()
{
// A => active, C => Cancelled, E => Error, F => Finished, O => Onhold, P => Planned, W => Waitlist
$codes = array(
'A' => $this->_('Active'),
'F' => $this->_('Finished'),
'O' => $this->_('On hold'),
'P' => $this->_('Planned'),
'W' => $this->_('Waitlist'),
);
asort($codes);
return $codes;
}
/**
* Get the status codes for inactive episode of care items
*
* @return array code => label
*/
public function getEpisodeStatusCodesInactive()
{
$codes = array(
'C' => $this->_('Cancelled'),
'E' => $this->_('Erroneous input'),
);
asort($codes);
return $codes;
}
/**
* Get the options list episodes for episodes
*
* @param array $episodes
* @return array of $episodeId => Description
*/
public function getEpisodesAsOptions(array $episodes)
{
$options = [];
foreach ($episodes as $id => $episode) {
if ($episode instanceof EpisodeOfCare) {
$options[$id] = $episode->getDisplayString();
}
}
return $options;
}
/**
* Get the episodes for a respondent
*
* @param \Gems_Tracker_Respondent $respondent
* @param $where mixed Optional extra string or array filter
* @return array of $episodeId => \Gems\Agenda\EpisodeOfCare
*/
public function getEpisodesFor(\Gems_Tracker_Respondent $respondent, $where = null)
{
return $this->getEpisodesForRespId($respondent->getId(), $respondent->getOrganizationId(), $where);
}
/**
* Get the episodes for a respondent
*
* @param int $respondentId
* @param int $orgId
* @param $where mixed Optional extra string or array filter
* @return array of $episodeId => \Gems\Agenda\EpisodeOfCare
*/
public function getEpisodesForRespId($respondentId, $orgId, $where = null)
{
$select = $this->db->select();
$select->from('gems__episodes_of_care')
->where('gec_id_user = ?', $respondentId)
->where('gec_id_organization = ?', $orgId)
->order('gec_startdate DESC');
if ($where) {
if (is_array($where)) {
foreach ($where as $expr => $param) {
if (is_int($expr)) {
$select->where($param);
} else {
$select->where($expr, $param);
}
}
} else {
$select->where($where);
}
}
// \MUtil_Echo::track($select->__toString());
$episodes = $this->db->fetchAll($select);
$output = [];
foreach ($episodes as $episodeData) {
$episode = $this->getEpisodeOfCare($episodeData);
$output[$episode->getId()] = $episode;
}
return $output;
}
/**
* Load the list of assignable filters
*
* @return array filter_id => label
*/
public function getFilterList()
{
$cacheId = __CLASS__ . '_' . __FUNCTION__;
$output = $this->cache->load($cacheId);
if ($output) {
return $output;
}
$output = $this->db->fetchPairs("SELECT gaf_id, COALESCE(gaf_manual_name, gaf_calc_name) "
. "FROM gems__appointment_filters WHERE gaf_active = 1 ORDER BY gaf_id_order");
$this->cache->save($output, $cacheId, array('appointment_filters'));
return $output;
}
/**
* Get the field names in appontments with their labels as the value
*
* @return array fieldname => label
*/
public final function getFieldLabels()
{
$output = \Mutil_Ra::column('label', $this->getFieldData());
asort($output);
return $output;
}
/**
* Get a structured nested array contain information on all the appointment
*
* @return array fieldname => array(label[, tableName, tableId, tableLikeFilter))
*/
protected function getFieldData()
{
return array(
'gap_id_organization' => array(
'label' => $this->_('Organization'),
'tableName' => 'gems__organizations',
'tableId' => 'gor_id_organization',
'tableLikeFilter' => "gor_active = 1 AND gor_name LIKE '%s'",
),
'gap_source' => array(
'label' => $this->_('Source of appointment'),
),
'gap_id_attended_by' => array(
'label' => $this->_('With'),
'tableName' => 'gems__agenda_staff',
'tableId' => 'gas_id_staff',
'tableLikeFilter' => "gas_active = 1 AND gas_name LIKE '%s'",
),
'gap_id_referred_by' => array(
'label' => $this->_('Referrer'),
'tableName' => 'gems__agenda_staff',
'tableId' => 'gas_id_staff',
'tableLikeFilter' => "gas_active = 1 AND gas_name LIKE '%s'",
),
'gap_id_activity' => array(
'label' => $this->_('Activity'),
'tableName' => 'gems__agenda_activities',
'tableId' => 'gaa_id_activity',
'tableLikeFilter' => "gaa_active = 1 AND gaa_name LIKE '%s'",
),
'gap_id_procedure' => array(
'label' => $this->_('Procedure'),
'tableName' => 'gems__agenda_procedures',
'tableId' => 'gapr_id_procedure',
'tableLikeFilter' => "gapr_active = 1 AND gapr_name LIKE '%s'",
),
'gap_id_location' => array(
'label' => $this->_('Location'),
'tableName' => 'gems__locations',
'tableId' => 'glo_id_location',
'tableLikeFilter' => "glo_active = 1 AND glo_name LIKE '%s'",
),
'gap_subject' => array(
'label' => $this->_('Subject'),
),
);
}
/**
* Get a filter from the database
*
* @param $filterId Id of a single filter
* @return AppointmentFilterInterface or null
*/
public function getFilter($filterId)
{
static $filters = array();
if (isset($filters[$filterId])) {
return $filters[$filterId];
}
$found = $this->getFilters("SELECT *
FROM gems__appointment_filters LEFT JOIN gems__track_appointments ON gaf_id = gtap_filter_id
WHERE gaf_active = 1 AND gaf_id = $filterId LIMIT 1");
if ($found) {
$filters[$filterId] = reset($found);
return $filters[$filterId];
}
}
/**
* Get the filters from the database
*
* @param $sql string|\Zend_Db_Select SQL statement
* @return AppointmentFilterInterface[]
*/
public function getFilters($sql)
{
$classes = array();
$filterRows = $this->db->fetchAll($sql);
$output = array();
// \MUtil_Echo::track($filterRows);
foreach ($filterRows as $key => $filter) {
$className = $filter['gaf_class'];
if (! isset($classes[$className])) {
$classes[$className] = $this->newFilterObject($className);
}
$filterObject = clone $classes[$className];
if ($filterObject instanceof AppointmentFilterInterface) {
$filterObject->exchangeArray($filter);
$output[$key] = $filterObject;
}
}
// \MUtil_Echo::track(count($filterRows), count($output));
return $output;
}
/**
*
* @param int $organizationId Optional
* @return array activity_id => name
*/
public function getHealthcareStaff($organizationId = null)
{
$cacheId = __CLASS__ . '_' . __FUNCTION__ . '_' . $organizationId;
if ($results = $this->cache->load($cacheId)) {
return $results;
}
$select = $this->db->select();
$select->from('gems__agenda_staff', array('gas_id_staff', 'gas_name'))
->order('gas_name');
if ($organizationId) {
// Check only for active when with $orgId: those are usually used
// with editing, while the whole list is used for display.
$select->where('gas_active = 1')
->where('gas_id_organization = ?', $organizationId);
}
// \MUtil_Echo::track($select->__toString());
$results = $this->db->fetchPairs($select);
$this->cache->save($results, $cacheId, array('staff'));
return $results;
}
/**
* Returns an array with identical key => value pairs containing care provision locations.
*
* @param int $orgId Optional to select for single organization
* @return array
*/
public function getLocations($orgId = null)
{
// Make sure no invalid data gets through
$orgId = intval($orgId);
$cacheId = __CLASS__ . '_' . __FUNCTION__ . '_' . $orgId;
if ($results = $this->cache->load($cacheId)) {
return $results;
}
$select = $this->db->select();
$select->from('gems__locations', array('glo_id_location', 'glo_name'))
->order('glo_name');
if ($orgId) {
// Check only for active when with $orgId: those are usually used
// with editing, while the whole list is used for display.
$select->where('glo_active = 1');
$select->where("glo_organizations LIKE '%:$orgId:%'");
}
$results = $this->db->fetchPairs($select);
$this->cache->save($results, $cacheId, array('locations'));
return $results;
}
/**
* Returns an array with identical key => value pairs containing care provision locations with organiation names
*
* @return array loId => label
*/
public function getLocationsWithOrganization()
{
$cacheId = __CLASS__ . '_' . __FUNCTION__;
if ($results = $this->cache->load($cacheId)) {
return $results;
}
$select = $this->db->select();
$select->from('gems__locations', array('glo_id_location', 'glo_name', 'glo_organizations'))
->order('glo_name');
$orgList = $this->util->getDbLookup()->getOrganizations();
$locations = $this->db->fetchAll($select);
$results = [];
if ($locations) {
foreach ($locations as $location) {
$orgs = array_filter(explode(':', trim($location['glo_organizations'], ':')));
if ($orgs) {
$orgNames = [];
foreach ($orgs as $orgId) {
if (isset($orgList[$orgId])) {
$orgNames[$orgId] = $orgList[$orgId];
}
}
$orgLabel = sprintf($this->_(' (%s)'), implode($this->_(', '), $orgNames));
} else {
$orgLabel = '';
}
$results[$location['glo_id_location']] = $location['glo_name'] . $orgLabel;
}
}
$this->cache->save($results, $cacheId, array('locations'));
return $results;
}
/**
*
* @param int $organizationId Optional
* @return array activity_id => name
*/
public function getProcedures($organizationId = null)
{
$cacheId = __CLASS__ . '_' . __FUNCTION__ . '_' . $organizationId;
if ($results = $this->cache->load($cacheId)) {
return $results;
}
$select = $this->db->select();
$select->from('gems__agenda_procedures', array('gapr_id_procedure', 'gapr_name'))
->order('gapr_name');
if ($organizationId) {
// Check only for active when with $orgId: those are usually used
// with editing, while the whole list is used for display.
$select->where('gapr_active = 1')
->where('(
gapr_id_organization IS NULL
AND
gapr_name NOT IN (SELECT gapr_name FROM gems__agenda_procedures WHERE gapr_id_procedure = ?)
) OR
gapr_id_organization = ?', $organizationId);
}
// \MUtil_Echo::track($select->__toString());
$results = $this->db->fetchPairs($select);
$this->cache->save($results, $cacheId, array('procedures'));
return $results;
}
/**
* Get the status codes for all active agenda items
*
* @return array code => label
*/
public function getStatusCodes()
{
$codes = $this->getStatusCodesActive() +
$this->getStatusCodesInactive();
asort($codes);
return $codes;
}
/**
* Get the status codes for active agenda items
*
* @return array code => label
*/
public function getStatusCodesActive()
{
$codes = array(
'AC' => $this->_('Active appointment'),
'CO' => $this->_('Completed appointment'),
);
asort($codes);
return $codes;
}
/**
* Get the status codes for inactive agenda items
*
* @return array code => label
*/
public function getStatusCodesInactive()
{
$codes = array(
'AB' => $this->_('Aborted appointment'),
'CA' => $this->_('Cancelled appointment'),
);
asort($codes);
return $codes;
}
/**
* Get the status keys for active agenda items
*
* @return array nr => code
*/
public function getStatusKeysActive()
{
return array_keys($this->getStatusCodesActive());
}
/**
* Get the status keys for active agenda items as a quoted db query string for use in "x IN (?)"
*
* @return \Zend_Db_Expr
*/
public function getStatusKeysActiveDbQuoted()
{
$codes = array();
foreach ($this->getStatusKeysActive() as $key) {
$codes[] = $this->db->quote($key);
}
return new \Zend_Db_Expr(implode(", ", $codes));
}
/**
* Get the status keys for inactive agenda items
*
* @return array nr => code
*/
public function getStatusKeysInactive()
{
return array_keys($this->getStatusCodesInactive());
}
/**
* Get the status keys for active agenda items as a quoted db query string for use in "x IN (?)"
*
* @return \Zend_Db_Expr
*/
public function getStatusKeysInactiveDbQuoted()
{
$codes = array();
foreach ($this->getStatusKeysInactive() as $key) {
$codes[] = $this->db->quote($key);
}
return new \Zend_Db_Expr(implode(", ", $codes));
}
/**
* Get the element that allows to create a track from an appointment
*
* When adding a new type, make sure to modify \Gems_Agenda_Appointment too
* @see \Gems_Agenda_Appointment::getCreatorCheckMethod()
*
* @return array For element setting
*/
public function getTrackCreateElement()
{
return [
'elementClass' => 'Radio',
'multiOptions' => $this->getTrackCreateOptions(),
'label' => $this->_('When not assigned'),
'onclick' => 'this.form.submit();',
];
}
/**
* Get the element that allows to create a track from an appointment
*
* When adding a new type, make sure to modify \Gems_Agenda_Appointment too
* @see \Gems_Agenda_Appointment::getCreatorCheckMethod()
*
* @return array Code => label
*/
public function getTrackCreateOptions()
{
return [
0 => $this->_('Do nothing'),
4 => $this->_('Create new on minimum start date difference'),
3 => $this->_('Create always (unless the appointment already assigned)'),
2 => $this->_('Create new on minimum end date difference'),
5 => $this->_('Create new when all surveys have been completed'),
1 => $this->_('Create new when all surveys have been completed and on minimum end date'),
];
}
/**
* Get the type codes for agenda items
*
* @return array code => label
*/
public function getTypeCodes()
{
return array(
'A' => $this->_('Ambulatory'),
'E' => $this->_('Emergency'),
'F' => $this->_('Field'),
'H' => $this->_('Home'),
'I' => $this->_('Inpatient'),
'S' => $this->_('Short stay'),
'V' => $this->_('Virtual'),
);
}
/**
* Function that checks the setup of this class/traight
*
* This function is not needed if the variables have been defined correctly in the
* source for this object and theose variables have been applied.
*
* return @void
*/
protected function initTranslateable()
{
if ($this->translateAdapter instanceof \Zend_Translate_Adapter) {
// OK
return;
}
if ($this->translate instanceof \Zend_Translate) {
// Just one step
$this->translateAdapter = $this->translate->getAdapter();
return;
}
if ($this->translate instanceof \Zend_Translate_Adapter) {
// It does happen and if it is all we have
$this->translateAdapter = $this->translate;
return;
}
// Make sure there always is an adapter, even if it is fake.
$this->translateAdapter = new \MUtil_Translate_Adapter_Potemkin();
}
/**
* Returns true when the status code is active
*
* @param string $code
* @return boolean
*/
public function isStatusActive($code)
{
$stati = $this->getStatusCodesActive();
return isset($stati[$code]);
}
/**
* Load the filters from cache or elsewhere
*
* @return AppointmentFilterInterface[]
*/
protected function loadDefaultFilters()
{
if ($this->_filters) {
return $this->_filters;
}
$cacheId = __CLASS__ . '_' . __FUNCTION__;
$output = $this->cache->load($cacheId);
if ($output) {
foreach ($output as $key => $filterObject) {
// Filterobjects should not serialize anything loaded from a source
if ($filterObject instanceof \MUtil_Registry_TargetInterface) {
$this->applySource($filterObject);
}
$this->_filters[$key] = $filterObject;
}
return $this->_filters;
}
$this->_filters = $this->getFilters("SELECT *
FROM gems__appointment_filters INNER JOIN
gems__track_appointments ON gaf_id = gtap_filter_id INNER JOIN
gems__tracks ON gtap_id_track = gtr_id_track
WHERE gaf_active = 1 AND gtr_active = 1 AND gtr_date_start <= CURRENT_DATE AND
(gtr_date_until IS NULL OR gtr_date_until >= CURRENT_DATE)
ORDER BY gaf_id_order, gtap_id_order, gtap_id_track");
$this->cache->save($this->_filters, $cacheId, array('appointment_filters', 'tracks'));
return $this->_filters;
}
/**
* Find an activity code for the name and organization.
*
* @param string $name The name to match against
* @param int $organizationId Organization id
* @param boolean $create Create a match when it does not exist
* @return int or null
*/
public function matchActivity($name, $organizationId, $create = true)
{
$cacheId = __CLASS__ . '_' . __FUNCTION__;
$matches = $this->cache->load($cacheId);
if (! $matches) {
$matches = array();
$select = $this->db->select();
$select->from('gems__agenda_activities', array(
'gaa_id_activity', 'gaa_match_to', 'gaa_id_organization', 'gaa_filter',
));
$result = $this->db->fetchAll($select);
foreach ($result as $row) {
if (null === $row['gaa_id_organization']) {
$key = 'null';
} else {
$key = $row['gaa_id_organization'];
}
foreach (explode('|', $row['gaa_match_to']) as $match) {
$matches[$match][$key] = $row['gaa_filter'] ? false : $row['gaa_id_activity'];
}
}
$this->cache->save($matches, $cacheId, array('activities'));
}
if (isset($matches[$name])) {
if (isset($matches[$name][$organizationId])) {
return $matches[$name][$organizationId];
}
if (isset($matches[$name]['null'])) {
return $matches[$name]['null'];
}
}
if (! $create) {
return null;
}
$result = $this->addActivity($name, $organizationId);
return $result['gaa_filter'] ? false : $result['gaa_id_activity'];
}
/**
*
* @param mixed $to \Gems_Agenda_Appointment:EpsiodeOfCare
* @return AppointmentFilterInterface[]
*/
public function matchFilters($to)
{
$filters = $this->loadDefaultFilters();
$output = array();
if ($to instanceof \Gems_Agenda_Appointment) {
foreach ($filters as $filter) {
if ($filter instanceof AppointmentFilterInterface) {
if ($filter->matchAppointment($to)) {
$output[] = $filter;
}
}
}
} elseif ($to instanceof EpisodeOfCare) {
foreach ($filters as $filter) {
if ($filter instanceof AppointmentFilterInterface) {
if ($filter->matchEpisode($to)) {
$output[] = $filter;
}
}
}
} else {
throw new \Gems_Exception_Coding('The $to paramater must be either an appointment or an episode object.');
}
return $output;
}
/**
* Find a healt care provider for the name and organization.
*
* @param string $name The name to match against
* @param int $organizationId Organization id
* @param boolean $create Create a match when it does not exist
* @return int gas_id_staff staff id
*/
public function matchHealthcareStaff($name, $organizationId, $create = true)
{
$cacheId = __CLASS__ . '_' . __FUNCTION__;
$matches = $this->cache->load($cacheId);
if (! $matches) {
$matches = array();
$select = $this->db->select();
$select->from('gems__agenda_staff')
->order('gas_name');
$result = $this->db->fetchAll($select);
foreach ($result as $row) {
foreach (explode('|', $row['gas_match_to']) as $match) {
$matches[$match][$row['gas_id_organization']] = $row['gas_filter'] ? false : $row['gas_id_staff'];
}
}
$this->cache->save($matches, $cacheId, array('staff'));
}
if (isset($matches[$name])) {
if ($organizationId) {
if (isset($matches[$name][$organizationId])) {
return $matches[$name][$organizationId];
}
} else {
// Return the first location among the organizations
return reset($matches[$name]);
}
}
if (! $create) {
return null;
}
$result = $this->addHealthcareStaff($name, $organizationId);
return $result['gas_filter'] ? false : $result['gas_id_staff'];
}
/**
* Find a location for the name and organization.
*
* @param string $name The name to match against
* @param int $organizationId Organization id
* @param boolean $create Create a match when it does not exist
* @return array location
*/
public function matchLocation($name, $organizationId, $create = true)
{
$cacheId = __CLASS__ . '_' . __FUNCTION__;
$matches = $this->cache->load($cacheId);
if (! $matches) {
$matches = array();
$select = $this->db->select();
$select->from('gems__locations')
->order('glo_name');
$result = $this->db->fetchAll($select);
foreach ($result as $row) {
foreach (explode('|', $row['glo_match_to']) as $match) {
foreach (explode(':', trim($row['glo_organizations'], ':')) as $subOrg) {
$matches[$match][$subOrg] = $row;
}
}
}
$this->cache->save($matches, $cacheId, array('locations'));
}
if (isset($matches[$name])) {
if ($organizationId) {
if (isset($matches[$name][$organizationId])) {
return $matches[$name][$organizationId];
}
// Not in this organization, if we create we update the record
} else {
// Return the first location among the organizations
return reset($matches[$name]);
}
} else {
$matches[$name] = null;
}
if (! $create) {
return null;
}
$result = $this->addLocation($name, $organizationId, $matches[$name]);
return $result;
}
/**
* Find a procedure code for the name and organization.
*
* @param string $name The name to match against
* @param int $organizationId Organization id
* @param boolean $create Create a match when it does not exist
* @return int or null
*/
public function matchProcedure($name, $organizationId, $create = true)
{
$cacheId = __CLASS__ . '_' . __FUNCTION__;
$matches = $this->cache->load($cacheId);
if (! $matches) {
$matches = array();
$select = $this->db->select();
$select->from('gems__agenda_procedures', array(
'gapr_id_procedure', 'gapr_match_to', 'gapr_id_organization', 'gapr_filter',
));
$result = $this->db->fetchAll($select);
foreach ($result as $row) {
if (null === $row['gapr_id_organization']) {
$key = 'null';
} else {
$key = $row['gapr_id_organization'];
}
foreach (explode('|', $row['gapr_match_to']) as $match) {
$matches[$match][$key] = $row['gapr_filter'] ? false : $row['gapr_id_procedure'];
}
}
$this->cache->save($matches, $cacheId, array('procedures'));
}
if (isset($matches[$name])) {
if (isset($matches[$name][$organizationId])) {
return $matches[$name][$organizationId];
}
if (isset($matches[$name]['null'])) {
return $matches[$name]['null'];
}
}
if (! $create) {
return null;
}
$result = $this->addProcedure($name, $organizationId);
return $result['gapr_filter'] ? false : $result['gapr_id_procedure'];
}
/**
* Creates a new filter class object
*
* @param string $className The part after *_Agenda_Filter_
* @return object
*/
public function newFilterObject($className)
{
return $this->_loadClass("Filter\\$className", true);
}
/**
*
* @return \Gems\Agenda\AppointmentFilterModel
*/
public function newFilterModel()
{
return $this->_loadClass('AppointmentFilterModel', true);
}
/**
* Copy from \Zend_Translate_Adapter
*
* Translates the given string using plural notations
* Returns the translated string
*
* @see \Zend_Locale
* @param string $singular Singular translation string
* @param string $plural Plural translation string
* @param integer $number Number for detecting the correct plural
* @param string|\Zend_Locale $locale (Optional) Locale/Language to use, identical with
* locale identifier, @see \Zend_Locale for more information
* @return string
*/
public function plural($singular, $plural, $number, $locale = null)
{
$args = func_get_args();
return call_user_func_array(array($this->translateAdapter, 'plural'), $args);
}
/**
* Reset internally held data for testing
*
* @return $this
*/
public function reset()
{
$this->_appointments = [];
$this->_filters = [];
return $this;
}
}