1785 lines
58 KiB
PHP
1785 lines
58 KiB
PHP
<?php
|
|
/**
|
|
* @package JEM
|
|
* @copyright (C) 2013-2024 joomlaeventmanager.net
|
|
* @copyright (C) 2005-2009 Christoph Lukes
|
|
* @license https://www.gnu.org/licenses/gpl-3.0 GNU/GPL
|
|
*/
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use Joomla\CMS\HTML\HTMLHelper;
|
|
use Joomla\CMS\Language\Text;
|
|
use Joomla\CMS\Factory;
|
|
use Joomla\CMS\Uri\Uri;
|
|
use Joomla\CMS\Filesystem\File;
|
|
use Joomla\CMS\Filesystem\Folder;
|
|
use Joomla\CMS\Filesystem\Path;
|
|
use Joomla\CMS\Log\LogEntry;
|
|
use Joomla\CMS\Log\Log;
|
|
use Joomla\CMS\Table\Table;
|
|
use Joomla\Registry\Registry;
|
|
use Joomla\CMS\Component\ComponentHelper;
|
|
use Joomla\CMS\Plugin\PluginHelper;
|
|
use Joomla\CMS\Router\Route;
|
|
use Joomla\CMS\Application\ApplicationHelper;
|
|
use Joomla\CMS\Date\Date;
|
|
|
|
// ensure JemFactory is loaded (because this class is used by modules or plugins too)
|
|
require_once(JPATH_SITE.'/components/com_jem/factory.php');
|
|
|
|
/**
|
|
* Holds some usefull functions to keep the code a bit cleaner
|
|
*/
|
|
class JemHelper
|
|
{
|
|
/**
|
|
* Pulls settings from database and stores in an static object
|
|
*
|
|
* @return object
|
|
*/
|
|
static public function config()
|
|
{
|
|
static $config;
|
|
|
|
if (!is_object($config)) {
|
|
$jemConfig = JemConfig::getInstance();
|
|
$config = clone $jemConfig->toObject(); // We need a copy to ensure not to store 'params' we add below!
|
|
|
|
$config->params = ComponentHelper::getParams('com_jem');
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* Pulls settings from database and stores in an static object
|
|
*
|
|
* @return object
|
|
*/
|
|
static public function globalattribs()
|
|
{
|
|
static $globalregistry;
|
|
if (!is_object($globalregistry)) {
|
|
$globalregistry = new Registry(self::config()->globalattribs);
|
|
}
|
|
|
|
return $globalregistry;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the CSS-settings from database and stores in an static object
|
|
*/
|
|
static public function retrieveCss()
|
|
{
|
|
static $registryCSS;
|
|
if (!is_object($registryCSS)) {
|
|
$registryCSS = new Registry(self::config()->css);
|
|
}
|
|
|
|
return $registryCSS;
|
|
}
|
|
|
|
/**
|
|
* Setup a file logger for JEM.
|
|
*/
|
|
static public function addFileLogger()
|
|
{
|
|
// Let admin choose the log level.
|
|
$jemconfig = JemConfig::getInstance()->toRegistry();
|
|
$lvl = (int)$jemconfig->get('globalattribs.loglevel', 0);
|
|
|
|
switch ($lvl) {
|
|
case 1: // ERROR or higher
|
|
$loglevel = Log::ERROR * 2 - 1;
|
|
break;
|
|
case 2: // WARNING or higher
|
|
$loglevel = Log::WARNING * 2 - 1;
|
|
break;
|
|
case 3: // INFO or higher
|
|
$loglevel = Log::INFO * 2 - 1;
|
|
break;
|
|
case 4: // DEBUG or higher
|
|
$loglevel = Log::DEBUG * 2 - 1;
|
|
break;
|
|
case 5: // ALL
|
|
$loglevel = Log::ALL;
|
|
break;
|
|
case 0: // OFF
|
|
default:
|
|
$loglevel = 0;
|
|
break;
|
|
}
|
|
|
|
if ($loglevel > 0) {
|
|
Log::addLogger(array('text_file' => 'jem.log.php', 'text_entry_format' => '{DATE} {TIME} {PRIORITY} {CATEGORY} {WHERE} : {MESSAGE}'), $loglevel, array('JEM'));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add en entry to JEM's log file.
|
|
*
|
|
* @param $message The message to print
|
|
* @param $where The location the message was generated, default: null
|
|
* @param $type The log level, default: DEBUG
|
|
*/
|
|
static public function addLogEntry($message, $where = null, $type = Log::DEBUG)
|
|
{
|
|
$logEntry = new LogEntry($message, $type, 'JEM');
|
|
$logEntry->where = empty($where) ? '' : ($where . '()');
|
|
|
|
Log::add($logEntry);
|
|
}
|
|
|
|
/**
|
|
* Performs daily scheduled cleanups
|
|
*
|
|
* Currently it archives and removes outdated events
|
|
* and takes care of the recurrence of events
|
|
*/
|
|
static public function cleanup($forced = 0)
|
|
{
|
|
$jemsettings = JemHelper::config();
|
|
$weekstart = $jemsettings->weekdaystart;
|
|
|
|
$now = time(); // UTC
|
|
$offset = idate('Z'); // timezone offset for "new day" test
|
|
$lastupdate = (int)$jemsettings->lastupdate;
|
|
$runningupdate = isset($jemsettings->runningupdate) ? $jemsettings->runningupdate : 0;
|
|
$maxexectime = get_cfg_var('max_execution_time');
|
|
$delay = min(86400, max(300, $maxexectime * 2));
|
|
|
|
// New (local) day since last update?
|
|
$nrdaysnow = floor(($now + $offset) / 86400);
|
|
$nrdaysupdate = floor(($lastupdate + $offset) / 86400);
|
|
|
|
if (($nrdaysnow > $nrdaysupdate) || $forced) {
|
|
JemHelper::addLogEntry('forced: ' . $forced . ', now: '. $now . ', last update: ' . $lastupdate .
|
|
', running update: ' . $runningupdate . ', delay: ' . $delay . ', tz-offset: ' . $offset, __METHOD__);
|
|
|
|
if (($runningupdate + $delay) < $now) {
|
|
// Set timestamp of running cleanup
|
|
JemConfig::getInstance()->set('runningupdate', $now);
|
|
|
|
JemHelper::addLogEntry(' do cleanup...', __METHOD__);
|
|
|
|
// trigger an event to let plugins handle whatever cleanup they want to do.
|
|
if (PluginHelper::importPlugin('jem')) {
|
|
$dispatcher = JemFactory::getDispatcher();
|
|
$dispatcher->triggerEvent('onJemBeforeCleanup', array($jemsettings, $forced));
|
|
}
|
|
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
$query = $db->getQuery(true);
|
|
|
|
// Get the last event occurence of each recurring published events, with unlimited repeat, or last date not passed.
|
|
// Ignore published field to prevent duplicate events.
|
|
$query = ' SELECT id, CASE recurrence_first_id WHEN 0 THEN id ELSE recurrence_first_id END AS first_id, '
|
|
. ' recurrence_number, recurrence_type, recurrence_limit_date, recurrence_limit, recurrence_byday, '
|
|
. ' MAX(dates) as dates, MAX(enddates) as enddates, MAX(recurrence_counter) as counter '
|
|
. ' FROM #__jem_events '
|
|
. ' WHERE recurrence_type <> "0" '
|
|
. ' AND CASE WHEN recurrence_limit_date IS null THEN 1 ELSE NOW() < recurrence_limit_date END '
|
|
. ' AND recurrence_number <> "0" '
|
|
. ' GROUP BY first_id'
|
|
. ' ORDER BY dates DESC';
|
|
|
|
$db->SetQuery($query);
|
|
$recurrence_array = $db->loadAssocList();
|
|
|
|
// If there are results we will be doing something with it
|
|
foreach ($recurrence_array as $recurrence_row)
|
|
{
|
|
// get the info of reference event for the duplicates
|
|
$ref_event = Table::getInstance('Event', 'JemTable');
|
|
$ref_event->load($recurrence_row['id']);
|
|
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
$query = $db->getQuery(true);
|
|
$query->select('*');
|
|
$query->from($db->quoteName('#__jem_events').' AS a');
|
|
$query->where('id = '.(int)$recurrence_row['id']);
|
|
$db->setQuery($query);
|
|
$reference = $db->loadAssoc();
|
|
|
|
// if reference event is "unpublished"(0) new event is "unpublished" too
|
|
// but on "archived"(2) and "trashed"(-2) reference events create "published"(1) event
|
|
if ($reference['published'] != 0) {
|
|
$reference['published'] = 1;
|
|
}
|
|
|
|
// the first day of the week is used for certain rules
|
|
$recurrence_row['weekstart'] = $weekstart;
|
|
|
|
// calculate next occurence date
|
|
$recurrence_row = JemHelper::calculate_recurrence($recurrence_row);
|
|
|
|
switch ($recurrence_row["recurrence_type"]) {
|
|
case 1:
|
|
$anticipation = $jemsettings->recurrence_anticipation_day;
|
|
break;
|
|
case 2:
|
|
$anticipation = $jemsettings->recurrence_anticipation_week;
|
|
break;
|
|
case 3:
|
|
$anticipation = $jemsettings->recurrence_anticipation_month;
|
|
break;
|
|
case 4:
|
|
$anticipation = $jemsettings->recurrence_anticipation_week;
|
|
break;
|
|
case 5:
|
|
$anticipation = $jemsettings->recurrence_anticipation_year;
|
|
break;
|
|
default:
|
|
$anticipation = $jemsettings->recurrence_anticipation_day;
|
|
break;
|
|
}
|
|
|
|
// add events as long as we are under the interval and under the limit, if specified.
|
|
$shieldDate = new Date('now + ' . $anticipation . ' month');
|
|
while (($recurrence_row['recurrence_limit_date'] == null
|
|
|| strtotime($recurrence_row['dates']) <= strtotime($recurrence_row['recurrence_limit_date']))
|
|
&& strtotime($recurrence_row['dates']) <= strtotime($shieldDate))
|
|
{
|
|
$new_event = Table::getInstance('Event', 'JemTable');
|
|
$new_event->bind($reference, array('id', 'hits', 'dates', 'enddates','checked_out_time','checked_out'));
|
|
$new_event->recurrence_first_id = $recurrence_row['first_id'];
|
|
$new_event->recurrence_counter = $recurrence_row['counter'] + 1;
|
|
$new_event->dates = $recurrence_row['dates'];
|
|
$new_event->enddates = $recurrence_row['enddates'];
|
|
$new_event->_autocreate = true; // to tell table class this has to be stored AS IS (the underscore is important!)
|
|
|
|
if ($new_event->store())
|
|
{
|
|
$recurrence_row['counter']++;
|
|
//duplicate categories event relationships
|
|
$query = ' INSERT INTO #__jem_cats_event_relations (itemid, catid) '
|
|
. ' SELECT ' . $db->Quote($new_event->id) . ', catid FROM #__jem_cats_event_relations '
|
|
. ' WHERE itemid = ' . $db->Quote($ref_event->id);
|
|
$db->setQuery($query);
|
|
|
|
if ($db->execute() === false) {
|
|
// run query always but don't show error message to "normal" users
|
|
$user = JemFactory::getUser();
|
|
if($user->authorise('core.manage')) {
|
|
echo Text::_('Error saving categories for event "' . $ref_event->title . '" new recurrences\n');
|
|
}
|
|
}
|
|
}
|
|
|
|
$recurrence_row = JemHelper::calculate_recurrence($recurrence_row);
|
|
}
|
|
}
|
|
|
|
//delete outdated events
|
|
if ($jemsettings->oldevent == 1) {
|
|
$query = 'DELETE FROM #__jem_events WHERE dates > 0 AND '
|
|
.' DATE_SUB(NOW(), INTERVAL '.(int)$jemsettings->minus.' DAY) > (IF (enddates IS NOT NULL, enddates, dates))';
|
|
$db->SetQuery($query);
|
|
$db->execute();
|
|
}
|
|
|
|
//Set state archived of outdated events
|
|
if ($jemsettings->oldevent == 2) {
|
|
$query = 'UPDATE #__jem_events SET published = 2 WHERE dates > 0 AND '
|
|
.' DATE_SUB(NOW(), INTERVAL '.(int)$jemsettings->minus.' DAY) > (IF (enddates IS NOT NULL, enddates, dates)) '
|
|
.' AND published = 1';
|
|
$db->SetQuery($query);
|
|
$db->execute();
|
|
}
|
|
|
|
//Set state trashed of outdated events
|
|
if ($jemsettings->oldevent == 3) {
|
|
$query = 'UPDATE #__jem_events SET published = -2 WHERE dates > 0 AND '
|
|
.' DATE_SUB(NOW(), INTERVAL '.(int)$jemsettings->minus.' DAY) > (IF (enddates IS NOT NULL, enddates, dates)) '
|
|
.' AND published = 1';
|
|
$db->SetQuery($query);
|
|
$db->execute();
|
|
}
|
|
|
|
//Set state unpublished of outdated events
|
|
if ($jemsettings->oldevent == 4) {
|
|
$query = 'UPDATE #__jem_events SET published = 0 WHERE dates > 0 AND '
|
|
.' DATE_SUB(NOW(), INTERVAL '.(int)$jemsettings->minus.' DAY) > (IF (enddates IS NOT NULL, enddates, dates)) '
|
|
.' AND published = 1';
|
|
$db->SetQuery($query);
|
|
$db->execute();
|
|
}
|
|
|
|
// Cleanup registrations
|
|
$query = 'DELETE FROM #__jem_register WHERE event NOT IN (SELECT id FROM #__jem_events)';
|
|
$db->SetQuery($query);
|
|
$db->execute();
|
|
|
|
// Set timestamp of last cleanup
|
|
JemConfig::getInstance()->set('lastupdate', $now);
|
|
// Clear timestamp of running cleanup
|
|
JemConfig::getInstance()->set('runningupdate', 0);
|
|
}
|
|
|
|
JemHelper::addLogEntry('finished.', __METHOD__);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* this methode calculate the next date
|
|
*/
|
|
static public function calculate_recurrence($recurrence_row)
|
|
{
|
|
// get the recurrence information
|
|
$recurrence_number = $recurrence_row['recurrence_number'];
|
|
$recurrence_type = $recurrence_row['recurrence_type'];
|
|
|
|
$day_time = 86400; // 60s * 60min * 24h
|
|
$week_time = $day_time * 7;
|
|
$date_array = JemHelper::generate_date($recurrence_row['dates'], $recurrence_row['enddates']);
|
|
|
|
switch($recurrence_type) {
|
|
case "1":
|
|
// +1 hour for the Summer to Winter clock change
|
|
$start_day = mktime(1, 0, 0, $date_array["month"], $date_array["day"], $date_array["year"]);
|
|
$start_day = $start_day + ($recurrence_number * $day_time);
|
|
break;
|
|
case "2":
|
|
// +1 hour for the Summer to Winter clock change
|
|
$start_day = mktime(1, 0, 0, $date_array["month"], $date_array["day"], $date_array["year"]);
|
|
$start_day = $start_day + ($recurrence_number * $week_time);
|
|
break;
|
|
case "3": // month recurrence
|
|
/*
|
|
* warning here, we have to make sure the date exists:
|
|
* 31 of october + 1 month = 31 of november, which doesn't exists => skip the date!
|
|
*/
|
|
$start_day = mktime(1,0,0,($date_array["month"] + $recurrence_number),$date_array["day"],$date_array["year"]);
|
|
|
|
$i = 1;
|
|
while (date('d', $start_day) != $date_array["day"] && $i < 20) { // not the same day of the month... try next date !
|
|
$i++;
|
|
$start_day = mktime(1,0,0,($date_array["month"] + $recurrence_number*$i),$date_array["day"],$date_array["year"]);
|
|
}
|
|
break;
|
|
case "4": // weekday
|
|
// the selected weekdays
|
|
$selected = JemHelper::convert2CharsDaysToInt(explode(',', $recurrence_row['recurrence_byday']), 0);
|
|
$days_names = array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
|
|
$litterals = array('first', 'second', 'third', 'fourth', 'fifth');
|
|
if (count($selected) == 0)
|
|
{
|
|
// this shouldn't happen, but if it does, to prevent problem use the current weekday for the repetition.
|
|
Factory::getApplication()->enqueueMessage(Text::_('COM_JEM_WRONG_EVENTRECURRENCE_WEEKDAY'), 'warning');
|
|
$current_weekday = (int) $date_array["weekday"];
|
|
$selected = array($current_weekday);
|
|
}
|
|
|
|
$start_day = null;
|
|
foreach ($selected as $s)
|
|
{
|
|
$next = null;
|
|
$nextmonth = null;
|
|
|
|
switch ($recurrence_number) {
|
|
case 7: // before last 'x' of the month
|
|
$next = strtotime("previous ".$days_names[$s].' - 1 week ',
|
|
mktime(1,0,0,$date_array["month"]+1 ,1,$date_array["year"]));
|
|
$nextmonth = strtotime("previous ".$days_names[$s].' - 1 week ',
|
|
mktime(1,0,0,$date_array["month"]+2 ,1,$date_array["year"]));
|
|
break;
|
|
case 6: // last 'x' of the month
|
|
$next = strtotime("previous ".$days_names[$s],
|
|
mktime(1,0,0,$date_array["month"]+1 ,1,$date_array["year"]));
|
|
$nextmonth = strtotime("previous ".$days_names[$s],
|
|
mktime(1,0,0,$date_array["month"]+2 ,1,$date_array["year"]));
|
|
break;
|
|
case 5: // 5th of the month
|
|
$currentMonth = $date_array["month"];
|
|
do {
|
|
$timeFisrtDayMonth = mktime(1,0,0, $currentMonth ,1,$date_array["year"]);
|
|
$timeLastDayNextMonth = mktime(23, 59, 59, $currentMonth+1, 0, $date_array["year"]);
|
|
$next = strtotime($litterals[$recurrence_number - 1] . " " . $days_names[$s] . ' of this month',$timeFisrtDayMonth);
|
|
$currentMonth++;
|
|
} while ($next > $timeLastDayNextMonth || $next < $date_array['unixtime']);
|
|
break;
|
|
case 4: // xth 'x' of the month
|
|
case 3:
|
|
case 2:
|
|
case 1:
|
|
default:
|
|
$next = strtotime($litterals[$recurrence_number-1]." ".$days_names[$s].' of this month',
|
|
mktime(1,0,0,$date_array["month"] ,1,$date_array["year"]));
|
|
$nextmonth = strtotime($litterals[$recurrence_number-1]." ".$days_names[$s].' of this month',
|
|
mktime(1,0,0,$date_array["month"]+1 ,1,$date_array["year"]));
|
|
break;
|
|
}
|
|
|
|
// is the next / nextm day eligible for next date ?
|
|
if ($next && $next > strtotime($recurrence_row['dates'])) // after current date !
|
|
{
|
|
if (!$start_day || $start_day > $next) { // comes before the current 'start_date'
|
|
$start_day = $next;
|
|
}
|
|
}
|
|
if ($nextmonth && (!$start_day || $start_day > $nextmonth)) {
|
|
$start_day = $nextmonth;
|
|
}
|
|
}
|
|
break;
|
|
case "5": // year recurrence
|
|
$start_day = mktime(1,0,0,($date_array["month"]),$date_array["day"],$date_array["year"]+ $recurrence_number);
|
|
break;
|
|
}
|
|
|
|
if (!$start_day) {
|
|
return false;
|
|
}
|
|
$recurrence_row['dates'] = date("Y-m-d", $start_day);
|
|
|
|
if ($recurrence_row['enddates']) {
|
|
$recurrence_row['enddates'] = date("Y-m-d", $start_day + $date_array["day_diff"]);
|
|
}
|
|
|
|
if ($start_day < $date_array["unixtime"]) {
|
|
throw new Exception(Text::_('COM_JEM_RECURRENCE_DATE_GENERATION_ERROR'), 500);
|
|
}
|
|
|
|
return $recurrence_row;
|
|
}
|
|
|
|
/**
|
|
* Method to dissolve recurrence of given id.
|
|
*
|
|
* @param int The id to clear as recurrence first id.
|
|
*
|
|
* @return boolean True on success.
|
|
*/
|
|
static public function dissolve_recurrence($first_id)
|
|
{
|
|
// Sanitize the id.
|
|
$first_id = (int)$first_id;
|
|
|
|
if (empty($first_id)) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
$db->setQuery('UPDATE #__jem_events'
|
|
. ' SET recurrence_first_id = 0, recurrence_type = 0'
|
|
. ' , recurrence_counter = 0, recurrence_number = 0'
|
|
. ' , recurrence_limit = 0, recurrence_limit_date = null'
|
|
. ' , recurrence_byday = ' . $db->quote('')
|
|
. ' WHERE recurrence_first_id = ' . $first_id
|
|
);
|
|
$db->execute();
|
|
} catch (Exception $e) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This method deletes an image file if unused.
|
|
*
|
|
* @param string $type one of 'event', 'venue', 'category', 'events', 'venues', 'categories'
|
|
* @param mixed $filename filename as stored in db, or null (which deletes all unused files)
|
|
*
|
|
* @return bool true on success, false on error
|
|
* @access public
|
|
*/
|
|
static public function delete_unused_image_files($type, $filename = null)
|
|
{
|
|
switch ($type) {
|
|
case 'event':
|
|
case 'events':
|
|
$folder = 'events';
|
|
$countquery_tmpl = ' SELECT id FROM #__jem_events WHERE datimage = ';
|
|
$imagequery = ' SELECT datimage AS image, COUNT(*) AS count FROM #__jem_events GROUP BY datimage';
|
|
break;
|
|
case 'venue':
|
|
case 'venues':
|
|
$folder = 'venues';
|
|
$countquery_tmpl = ' SELECT id FROM #__jem_venues WHERE locimage = ';
|
|
$imagequery = ' SELECT locimage AS image, COUNT(*) AS count FROM #__jem_venues GROUP BY locimage';
|
|
break;
|
|
case 'category':
|
|
case 'categories':
|
|
$folder = 'categories';
|
|
$countquery_tmpl = ' SELECT id FROM #__jem_categories WHERE image = ';
|
|
$imagequery = ' SELECT image, COUNT(*) AS count FROM #__jem_categories GROUP BY image';
|
|
break;
|
|
default;
|
|
return false;
|
|
}
|
|
|
|
$fullPath = Path::clean(JPATH_SITE.'/images/jem/'.$folder.'/'.$filename);
|
|
$fullPaththumb = Path::clean(JPATH_SITE.'/images/jem/'.$folder.'/small/'.$filename);
|
|
if (is_file($fullPath)) {
|
|
// Count usage and don't delete if used elsewhere.
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
$db->setQuery($countquery_tmpl . $db->quote($filename));
|
|
if (null === ($usage = $db->loadObjectList())) {
|
|
return false;
|
|
}
|
|
if (empty($usage)) {
|
|
File::delete($fullPath);
|
|
if (File::exists($fullPaththumb)) {
|
|
File::delete($fullPaththumb);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
elseif (empty($filename) && is_dir($fullPath)) {
|
|
// get image files used
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
$db->setQuery($imagequery);
|
|
if (null === ($used = $db->loadAssocList('image', 'count'))) {
|
|
return false;
|
|
}
|
|
|
|
// get all files and delete if not in $used
|
|
$fileList = Folder::files($fullPath);
|
|
if ($fileList !== false) {
|
|
foreach ($fileList as $file)
|
|
{
|
|
if (is_file($fullPath.$file) && substr($file, 0, 1) != '.' && !isset($used[$file])) {
|
|
File::delete($fullPath.$file);
|
|
if (File::exists($fullPaththumb.$file)) {
|
|
File::delete($fullPaththumb.$file);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* This method deletes attachment files if unused.
|
|
*
|
|
* @param mixed $type one of 'event', 'venue', 'category', ... or false for all
|
|
*
|
|
* @return bool true on success, false on error
|
|
* @access public
|
|
*/
|
|
static public function delete_unused_attachment_files($type = false)
|
|
{
|
|
$jemsettings = JemHelper::config();
|
|
$basepath = JPATH_SITE.'/'.$jemsettings->attachments_path;
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
$res = true;
|
|
|
|
// Get list of all folders matching type (format is "$type$id")
|
|
$folders = Folder::folders($basepath, ($type ? '^'.$type : '.'), false, false, array('.', '..'));
|
|
|
|
// Get list of all used attachments of given type
|
|
$fnames = array();
|
|
foreach ($folders as $f) {
|
|
$fnames[] = $db->Quote($f);
|
|
}
|
|
$query = ' SELECT object, file '
|
|
. ' FROM #__jem_attachments ';
|
|
if (!empty($fnames)) {
|
|
$query .= ' WHERE object IN ('.implode(',', $fnames).')';
|
|
}
|
|
$db->setQuery($query);
|
|
$files_used = $db->loadObjectList();
|
|
$files = array();
|
|
foreach ($files_used as $used) {
|
|
$files[$used->object.'/'.$used->file] = true;
|
|
}
|
|
|
|
// Delete unused files and folders (ignore 'index.html')
|
|
foreach ($folders as $folder) {
|
|
$files = Folder::files($basepath.'/'.$folder, '.', false, false, array('index.html'), array());
|
|
if (!empty($files)) {
|
|
foreach ($files as $file) {
|
|
if (!array_key_exists($folder.'/'.$file, $files)) {
|
|
$res &= File::delete($basepath.'/'.$folder.'/'.$file);
|
|
}
|
|
}
|
|
}
|
|
$files = Folder::files($basepath.'/'.$folder, '.', false, true, array('index.html'), array());
|
|
if (empty($files)) {
|
|
$res &= Folder::delete($basepath.'/'.$folder);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* this method generate the date string to a date array
|
|
*
|
|
* @param string the date string
|
|
* @return array the date informations
|
|
* @access public
|
|
*/
|
|
static public function generate_date($startdate, $enddate)
|
|
{
|
|
$validStardate = JemHelper::isValidDate($startdate);
|
|
$validEnddate = JemHelper::isValidDate($enddate);
|
|
|
|
if($validStardate) {
|
|
$startdate = explode("-", $startdate);
|
|
$date_array = array("year" => $startdate[0],
|
|
"month" => $startdate[1],
|
|
"day" => $startdate[2],
|
|
"weekday" => date("w",mktime(1,0,0,$startdate[1],$startdate[2],$startdate[0])),
|
|
"unixtime" => mktime(1,0,0,$startdate[1],$startdate[2],$startdate[0]));
|
|
|
|
if ($validEnddate) {
|
|
$enddate = explode("-", $enddate);
|
|
$day_diff = (mktime(1, 0, 0, $enddate[1], $enddate[2], $enddate[0]) - mktime(1, 0, 0, $startdate[1], $startdate[2], $startdate[0]));
|
|
$date_array["day_diff"] = $day_diff;
|
|
}
|
|
|
|
|
|
return $date_array;
|
|
}else{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* return day number of the week starting with 0 for first weekday
|
|
*
|
|
* @param array of 2 letters day
|
|
* @return array of int
|
|
*/
|
|
static function convert2CharsDaysToInt($days, $firstday = 0)
|
|
{
|
|
$result = array();
|
|
foreach ($days as $day)
|
|
{
|
|
switch (strtoupper($day))
|
|
{
|
|
case 'MO':
|
|
$result[] = 1 - $firstday;
|
|
break;
|
|
case 'TU':
|
|
$result[] = 2 - $firstday;
|
|
break;
|
|
case 'WE':
|
|
$result[] = 3 - $firstday;
|
|
break;
|
|
case 'TH':
|
|
$result[] = 4 - $firstday;
|
|
break;
|
|
case 'FR':
|
|
$result[] = 5 - $firstday;
|
|
break;
|
|
case 'SA':
|
|
$result[] = 6 - $firstday;
|
|
break;
|
|
case 'SU':
|
|
$result[] = (7 - $firstday) % 7;
|
|
break;
|
|
default:
|
|
\Joomla\CMS\Factory::getApplication()->enqueueMessage(Text::_('COM_JEM_WRONG_EVENTRECURRENCE_WEEKDAY'), 'warning');
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
|
|
/**
|
|
* Build the select list for access level
|
|
*/
|
|
static public function getAccesslevelOptions($ownonly = false, $disabledLevels = false)
|
|
{
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
$where = '';
|
|
$selDisabled = '';
|
|
if ($ownonly) {
|
|
$levels = Factory::getApplication()->getIdentity()->getAuthorisedViewLevels();
|
|
$allLevels = $levels;
|
|
if (!empty($disabledLevels)) {
|
|
if (!is_array($disabledLevels)) {
|
|
$disabledLevels = array($disabledLevels);
|
|
}
|
|
foreach ($disabledLevels as $level) {
|
|
if (((int)$level > 0) && (!in_array((int)$level, $levels))) {
|
|
$allLevels[] = $level;
|
|
}
|
|
}
|
|
$selDisabled = ', IF (id IN ('.implode(',', $levels).'), \'\', \'disabled\') AS disabled';
|
|
}
|
|
$where = ' WHERE id IN ('.implode(',', $allLevels).')';
|
|
}
|
|
|
|
$query = 'SELECT id AS value, title AS text' . $selDisabled
|
|
. ' FROM #__viewlevels'
|
|
. $where
|
|
. ' ORDER BY ordering, id'
|
|
;
|
|
|
|
//JemHelper::addLogEntry('AccessLevel query: ' . $query, __METHOD__);
|
|
|
|
$db->setQuery($query);
|
|
$groups = $db->loadObjectList();
|
|
|
|
//JemHelper::addLogEntry('result: ' . print_r($groups, true), __METHOD__);
|
|
|
|
return $groups;
|
|
}
|
|
|
|
static public function buildtimeselect($max, $name, $selected, $class = array('class'=>'inputbox'))
|
|
{
|
|
$timelist = array();
|
|
$timelist[0] = HTMLHelper::_('select.option', '', '');
|
|
|
|
if ($max == 23) {
|
|
// does user prefer 12 or 24 hours format?
|
|
$jemreg = JemConfig::getInstance()->toRegistry();
|
|
$format = $jemreg->get('formathour', false);
|
|
} else {
|
|
$format = false;
|
|
}
|
|
|
|
foreach (range(0, $max) as $value) {
|
|
if ($value < 10) {
|
|
$value = '0'.$value;
|
|
}
|
|
|
|
$timelist[] = HTMLHelper::_('select.option', $value, ($format ? date($format, strtotime("$value:00:00")) : $value));
|
|
}
|
|
|
|
return HTMLHelper::_('select.genericlist', $timelist, $name, $class, 'value', 'text', $selected);
|
|
}
|
|
|
|
/**
|
|
* returns mime type of a file
|
|
*
|
|
* @param string file path
|
|
* @return string mime type
|
|
*/
|
|
static public function getMimeType($filename)
|
|
{
|
|
if (function_exists('finfo_open')) {
|
|
$finfo = finfo_open(FILEINFO_MIME);
|
|
$mimetype = finfo_file($finfo, $filename);
|
|
finfo_close($finfo);
|
|
return $mimetype;
|
|
}
|
|
else if (function_exists('mime_content_type') && 0)
|
|
{
|
|
return mime_content_type($filename);
|
|
}
|
|
else
|
|
{
|
|
$mime_types = array(
|
|
'txt' => 'text/plain',
|
|
'htm' => 'text/html',
|
|
'html' => 'text/html',
|
|
'php' => 'text/html',
|
|
'css' => 'text/css',
|
|
'js' => 'application/javascript',
|
|
'json' => 'application/json',
|
|
'xml' => 'application/xml',
|
|
'swf' => 'application/x-shockwave-flash',
|
|
'flv' => 'video/x-flv',
|
|
|
|
// images
|
|
'png' => 'image/png',
|
|
'jpe' => 'image/jpeg',
|
|
'jpeg' => 'image/jpeg',
|
|
'jpg' => 'image/jpeg',
|
|
'gif' => 'image/gif',
|
|
'bmp' => 'image/bmp',
|
|
'ico' => 'image/vnd.microsoft.icon',
|
|
'tiff' => 'image/tiff',
|
|
'tif' => 'image/tiff',
|
|
'svg' => 'image/svg+xml',
|
|
'svgz' => 'image/svg+xml',
|
|
|
|
// archives
|
|
'zip' => 'application/zip',
|
|
'rar' => 'application/x-rar-compressed',
|
|
'exe' => 'application/x-msdownload',
|
|
'msi' => 'application/x-msdownload',
|
|
'cab' => 'application/vnd.ms-cab-compressed',
|
|
|
|
// audio/video
|
|
'mp3' => 'audio/mpeg',
|
|
'qt' => 'video/quicktime',
|
|
'mov' => 'video/quicktime',
|
|
|
|
// adobe
|
|
'pdf' => 'application/pdf',
|
|
'psd' => 'image/vnd.adobe.photoshop',
|
|
'ai' => 'application/postscript',
|
|
'eps' => 'application/postscript',
|
|
'ps' => 'application/postscript',
|
|
|
|
// ms office
|
|
'doc' => 'application/msword',
|
|
'rtf' => 'application/rtf',
|
|
'xls' => 'application/vnd.ms-excel',
|
|
'ppt' => 'application/vnd.ms-powerpoint',
|
|
|
|
// open office
|
|
'odt' => 'application/vnd.oasis.opendocument.text',
|
|
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
|
|
);
|
|
|
|
//$ext = strtolower(array_pop(explode('.',$filename)));
|
|
$var = explode('.',$filename);
|
|
$ext = strtolower(array_pop($var));
|
|
if (array_key_exists($ext, $mime_types)) {
|
|
return $mime_types[$ext];
|
|
}
|
|
else {
|
|
return 'application/octet-stream';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* updates waiting list of specified event
|
|
*
|
|
* @param int event id
|
|
* @param boolean bump users off/to waiting list
|
|
* @return bool
|
|
*/
|
|
static public function updateWaitingList($event)
|
|
{
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
|
|
// get event details for registration
|
|
$query = ' SELECT maxplaces, waitinglist, reservedplaces FROM #__jem_events WHERE id = ' . $db->Quote($event);
|
|
$db->setQuery($query);
|
|
$event_places = $db->loadObject();
|
|
|
|
// get attendees after deletion, and their status
|
|
$query = 'SELECT r.id, r.waiting, r.places'
|
|
. ' FROM #__jem_register AS r'
|
|
. ' WHERE r.status = 1 AND r.event = '.$db->Quote($event)
|
|
. ' ORDER BY r.uregdate ASC '
|
|
;
|
|
$db->SetQuery($query);
|
|
$res = $db->loadObjectList();
|
|
|
|
$registered = 0;
|
|
$waitingregs = array();
|
|
foreach ((array) $res as $r)
|
|
{
|
|
if ($r->waiting) {
|
|
$waitingregs[] = $r;
|
|
} else {
|
|
$registered+=$r->places;
|
|
}
|
|
}
|
|
//Add the Reserved Places of the event
|
|
$registered+=$event_places->reservedplaces;
|
|
|
|
if (($registered < $event_places->maxplaces) && count($waitingregs))
|
|
{
|
|
$placesavailable = $event_places->maxplaces - $registered;
|
|
// need to bump users to attending status
|
|
foreach ($waitingregs as $waitreg)
|
|
{
|
|
if($waitreg->places <= $placesavailable)
|
|
{
|
|
$query = ' UPDATE #__jem_register SET waiting = 0 WHERE id = ' . $waitreg->id;
|
|
$db->setQuery($query);
|
|
if ($db->execute() === false)
|
|
{
|
|
Factory::getApplication()->enqueueMessage(
|
|
Text::_(
|
|
'COM_JEM_FAILED_BUMPING_USERS_FROM_WAITING_TO_CONFIRMED_LIST'
|
|
) . ': ' . $db->getErrorMsg(),
|
|
'warning'
|
|
);
|
|
}
|
|
else
|
|
{
|
|
PluginHelper::importPlugin('jem');
|
|
$dispatcher = JemFactory::getDispatcher();
|
|
$res = $dispatcher->triggerEvent('onUserOnOffWaitinglist', array($waitreg->id));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Adds attendees numbers to rows
|
|
*
|
|
* @param $data reference to event rows
|
|
* @return false on error, $data on success
|
|
*/
|
|
static public function getAttendeesNumbers(& $data)
|
|
{
|
|
// Make sure this is an array and it is not empty
|
|
if (!is_array($data) || !count($data)) {
|
|
return false;
|
|
}
|
|
|
|
// Get the ids of events
|
|
$ids = array();
|
|
foreach ($data as $event) {
|
|
$ids[] = (int)$event->id;
|
|
}
|
|
$ids = implode(",", $ids);
|
|
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
|
|
// status 1: user registered (attendee or waiting list), status -1: user exlicitely unregistered, status 0: user is invited but hadn't answered yet
|
|
$query = ' SELECT COUNT(id) as total,'
|
|
. ' SUM(IF(status = 1 AND waiting = 0, places, 0)) AS registered,'
|
|
. ' SUM(IF(status = 1 AND waiting > 0, places, 0)) AS waiting,'
|
|
. ' SUM(IF(status = -1, places, 0)) AS unregistered,'
|
|
. ' SUM(IF(status = 0, places, 0)) AS invited,'
|
|
. ' event '
|
|
. ' FROM #__jem_register '
|
|
. ' WHERE event IN (' . $ids .')'
|
|
. ' GROUP BY event ';
|
|
|
|
$db->setQuery($query);
|
|
$res = $db->loadObjectList('event');
|
|
|
|
foreach ($data as $k => &$event) { // by reference for direct edit
|
|
if (isset($res[$event->id])) {
|
|
$event->regTotal = $res[$event->id]->total;
|
|
$event->regCount = $res[$event->id]->registered;
|
|
$event->reserved = $event->reservedplaces;
|
|
$event->waiting = $res[$event->id]->waiting;
|
|
$event->unregCount = $res[$event->id]->unregistered;
|
|
$event->invited = $res[$event->id]->invited;
|
|
} else {
|
|
$event->regTotal = 0;
|
|
$event->regCount = 0;
|
|
$event->reserved = 0;
|
|
$event->waiting = 0;
|
|
$event->unregCount = 0;
|
|
$event->invited = 0;
|
|
}
|
|
$event->available = max(0, $event->maxplaces - $event->regCount -$event->reservedplaces);
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* returns timezone name
|
|
*/
|
|
static public function getTimeZoneName()
|
|
{
|
|
$user = JemFactory::getUser();
|
|
$userTz = $user->getParam('timezone');
|
|
$timeZone = Factory::getConfig()->get('offset');
|
|
|
|
/* disabled for now
|
|
if($userTz) {
|
|
$timeZone = $userTz;
|
|
}
|
|
*/
|
|
return $timeZone;
|
|
}
|
|
|
|
/**
|
|
* return initialized calendar tool class for ics export
|
|
*
|
|
* @return object
|
|
*/
|
|
static public function getCalendarTool()
|
|
{
|
|
require_once JPATH_SITE.'/components/com_jem/classes/iCalcreator.class.php';
|
|
$timezone_name = JemHelper::getTimeZoneName();
|
|
|
|
$vcal = new vcalendar();
|
|
if (!file_exists(JPATH_SITE.'/cache/com_jem')) {
|
|
Folder::create(JPATH_SITE.'/cache/com_jem');
|
|
}
|
|
$vcal->setConfig('directory', JPATH_SITE.'/cache/com_jem');
|
|
$vcal->setProperty("calscale", "GREGORIAN");
|
|
$vcal->setProperty('method', 'PUBLISH');
|
|
if ($timezone_name) {
|
|
$vcal->setProperty("X-WR-TIMEZONE", $timezone_name);
|
|
}
|
|
return $vcal;
|
|
}
|
|
|
|
static public function icalAddEvent(&$calendartool, $event)
|
|
{
|
|
require_once JPATH_SITE.'/components/com_jem/classes/iCalcreator.class.php';
|
|
$jemsettings = JemHelper::config();
|
|
$timezone_name = JemHelper::getTimeZoneName();
|
|
$config = Factory::getConfig();
|
|
$sitename = $config->get('sitename');
|
|
$uri = Uri::getInstance();
|
|
|
|
// get categories names
|
|
$categories = array();
|
|
foreach ($event->categories as $c) {
|
|
$categories[] = $c->catname;
|
|
}
|
|
|
|
// no start date...
|
|
$validdate = JemHelper::isValidDate($event->dates);
|
|
|
|
if (!$event->dates || !$validdate) {
|
|
return false;
|
|
}
|
|
|
|
// make end date same as start date if not set
|
|
if (!$event->enddates) {
|
|
$event->enddates = $event->dates;
|
|
}
|
|
|
|
// start
|
|
if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/', $event->dates, $start_date)) {
|
|
throw new Exception(Text::_('COM_JEM_ICAL_EXPORT_WRONG_STARTDATE_FORMAT'), 0);
|
|
}
|
|
|
|
$date = array('year' => (int) $start_date[1], 'month' => (int) $start_date[2], 'day' => (int) $start_date[3]);
|
|
|
|
// all day event if start time is not set
|
|
if (!$event->times) // all day !
|
|
{
|
|
$dateparam = array('VALUE' => 'DATE');
|
|
|
|
// for ical all day events, dtend must be send to the next day
|
|
$event->enddates = date('Y-m-d', strtotime($event->enddates.' +1 day'));
|
|
|
|
if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/', $event->enddates, $end_date)) {
|
|
throw new Exception(Text::_('COM_JEM_ICAL_EXPORT_WRONG_ENDDATE_FORMAT'), 0);
|
|
}
|
|
|
|
$date_end = array('year' => $end_date[1], 'month' => $end_date[2], 'day' => $end_date[3]);
|
|
$dateendparam = array('VALUE' => 'DATE');
|
|
}
|
|
else // not all day events, there is a start time
|
|
{
|
|
if (!preg_match('/([0-9]{2}):([0-9]{2}):([0-9]{2})/', $event->times, $start_time)) {
|
|
throw new Exception(Text::_('COM_JEM_ICAL_EXPORT_WRONG_STARTTIME_FORMAT'), 0);
|
|
}
|
|
|
|
$date['hour'] = $start_time[1];
|
|
$date['min'] = $start_time[2];
|
|
$date['sec'] = $start_time[3];
|
|
$dateparam = array('VALUE' => 'DATE-TIME');
|
|
if ($jemsettings->ical_tz == 1) {
|
|
$dateparam['TZID'] = $timezone_name;
|
|
}
|
|
|
|
if (!$event->endtimes || $event->endtimes == '00:00:00') {
|
|
$event->endtimes = $event->times;
|
|
}
|
|
|
|
// if same day but end time < start time, change end date to +1 day
|
|
if ($event->enddates == $event->dates &&
|
|
strtotime($event->dates.' '.$event->endtimes) < strtotime($event->dates.' '.$event->times))
|
|
{
|
|
$event->enddates = date('Y-m-d', strtotime($event->enddates.' +1 day'));
|
|
}
|
|
|
|
if (!preg_match('/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/', $event->enddates, $end_date)) {
|
|
throw new Exception(Text::_('COM_JEM_ICAL_EXPORT_WRONG_ENDDATE_FORMAT'), 0);
|
|
}
|
|
|
|
$date_end = array('year' => $end_date[1], 'month' => $end_date[2], 'day' => $end_date[3]);
|
|
|
|
if (!preg_match('/([0-9]{2}):([0-9]{2}):([0-9]{2})/', $event->endtimes, $end_time)) {
|
|
throw new Exception(Text::_('COM_JEM_ICAL_EXPORT_WRONG_STARTTIME_FORMAT'), 0);
|
|
}
|
|
|
|
$date_end['hour'] = $end_time[1];
|
|
$date_end['min'] = $end_time[2];
|
|
$date_end['sec'] = $end_time[3];
|
|
$dateendparam = array('VALUE' => 'DATE-TIME');
|
|
if ($jemsettings->ical_tz == 1) {
|
|
$dateendparam['TZID'] = $timezone_name;
|
|
}
|
|
}
|
|
|
|
// item description text
|
|
$description = $event->title.'\\n';
|
|
$description .= Text::_('COM_JEM_CATEGORY').': '.implode(', ', $categories).'\\n';
|
|
|
|
$link = $uri->root().JemHelperRoute::getEventRoute($event->slug);
|
|
$link = Route::_($link);
|
|
$description .= Text::_('COM_JEM_ICS_LINK').': '.$link.'\\n';
|
|
|
|
// location
|
|
$location = array($event->venue);
|
|
if (isset($event->street) && !empty($event->street)) {
|
|
$location[] = $event->street;
|
|
}
|
|
|
|
if (isset($event->postalCode) && !empty($event->postalCode) && isset($event->city) && !empty($event->city)) {
|
|
$location[] = $event->postalCode.' '.$event->city;
|
|
} else {
|
|
if (isset($event->postalCode) && !empty($event->postalCode)) {
|
|
$location[] = $event->postalCode;
|
|
}
|
|
if (isset($event->city) && !empty($event->city)) {
|
|
$location[] = $event->city;
|
|
}
|
|
}
|
|
|
|
if (isset($event->countryname) && !empty($event->countryname)) {
|
|
$exp = explode(",",$event->countryname);
|
|
$location[] = $exp[0];
|
|
}
|
|
|
|
$location = implode(",", $location);
|
|
|
|
$e = new vevent();
|
|
$e->setProperty('summary', $event->title);
|
|
$e->setProperty('categories', implode(', ', $categories));
|
|
$e->setProperty('dtstart', $date, $dateparam);
|
|
if (count($date_end)) {
|
|
$e->setProperty('dtend', $date_end, $dateendparam);
|
|
}
|
|
$e->setProperty('description', $description);
|
|
if ($location != '') {
|
|
$e->setProperty('location', $location);
|
|
}
|
|
$e->setProperty('url', $link);
|
|
$e->setProperty('uid', 'event'.$event->id.'@'.$sitename);
|
|
$calendartool->addComponent($e); // add component to calendar
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* return true is a date is valid (not null, or 0000-00...)
|
|
*
|
|
* @param string $date
|
|
* @return boolean
|
|
*/
|
|
static public function isValidDate($date)
|
|
{
|
|
if (is_null($date)) {
|
|
return false;
|
|
}
|
|
if ($date == '0000-00-00' || $date == '0000-00-00 00:00:00') {
|
|
return false;
|
|
}
|
|
if (!strtotime($date)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* return true is a time is valid (not null, or 00:00:00...)
|
|
*
|
|
* @param string $time
|
|
* @return boolean
|
|
*/
|
|
static public function isValidTime($time)
|
|
{
|
|
if (is_null($time)) {
|
|
return false;
|
|
}
|
|
|
|
if (!strtotime($time)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Returns array of positive numbers
|
|
*
|
|
* @param mixed array or string with comma separated list of ids
|
|
* @return mixed array of numbers greater zero or false
|
|
*/
|
|
static public function getValidIds($ids_in)
|
|
{
|
|
$ids_out = array();
|
|
if($ids_in) {
|
|
$tmp = is_array($ids_in) ? $ids_in : explode(',', $ids_in);
|
|
if (!empty($tmp)) {
|
|
foreach ($tmp as $id) {
|
|
if ((int)$id > 0) {
|
|
$ids_out[] = (int)$id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (empty($ids_out) ? false : $ids_out);
|
|
}
|
|
|
|
/**
|
|
* Creates a tooltip
|
|
*/
|
|
static public function caltooltip($tooltip, $title = '', $text = '', $href = '', $class = '', $time = '', $color = '')
|
|
{
|
|
HTMLHelper::_('bootstrap.tooltip');
|
|
if (0) { /* old style using 'hasTip' */
|
|
$title = HTMLHelper::tooltipText($title, '<div style="font-weight:normal;">'.$tooltip.'</div>', 0);
|
|
} else { /* new style using 'has Tooltip' */
|
|
$class = str_replace('hasTip', '', $class) . ' hasTooltip';
|
|
$title = HTMLHelper::tooltipText($title, $tooltip, 0); // this calls htmlspecialchars()
|
|
}
|
|
$tooltip = '';
|
|
|
|
|
|
if ($href) {
|
|
$href = Route::_ ($href);
|
|
$tip = '<span class="'.$class.'" data-bs-toggle="tooltip" title="'.$title.$tooltip.'"><a href="'.$href.'">'.$time.$text.'</a></span>';
|
|
} else {
|
|
$tip = '<span class="'.$class.'" data-bs-toggle="tooltip" title="'.$title.$tooltip.'">'.$text.'</span>';
|
|
}
|
|
|
|
return $tip;
|
|
}
|
|
|
|
/**
|
|
* Function to retrieve IP
|
|
* @author: https://gist.github.com/cballou/2201933
|
|
*/
|
|
static public function retrieveIP()
|
|
{
|
|
$ip_keys = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR');
|
|
foreach ($ip_keys as $key) {
|
|
if (array_key_exists($key, $_SERVER) === true) {
|
|
foreach (explode(',', $_SERVER[$key]) as $ip) {
|
|
// trim for safety measures
|
|
$ip = trim($ip);
|
|
// attempt to validate IP
|
|
if (self::validate_ip($ip)) {
|
|
return $ip;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : false;
|
|
}
|
|
|
|
/**
|
|
* Ensures an ip address is both a valid IP and does not fall within
|
|
* a private network range.
|
|
*
|
|
* @author: https://gist.github.com/cballou/2201933
|
|
*/
|
|
static public function validate_ip($ip)
|
|
{
|
|
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static public function getLayoutStyleSuffix()
|
|
{
|
|
$jemsettings = self::config();
|
|
$layoutstyle = isset($jemsettings->layoutstyle) ? (int)$jemsettings->layoutstyle : 0;
|
|
|
|
return $layoutstyle === 1 ? 'responsive' : '';
|
|
|
|
}
|
|
|
|
/**
|
|
* Get the path to a layout for a module respecting layout style configured in JEM Settings.
|
|
*
|
|
* @param string $module The name of the module
|
|
* @param string $layout The name of the module layout. If alternative layout, in the form template:filename.
|
|
*
|
|
* @return string The path to the module layout
|
|
*
|
|
* @since 2.3
|
|
*/
|
|
public static function getModuleLayoutPath($module, $layout = 'default')
|
|
{
|
|
$template = Factory::getApplication()->getTemplate();
|
|
$defaultLayout = $layout;
|
|
$suffix = self::getLayoutStyleSuffix();
|
|
|
|
if (strpos($layout, ':') !== false)
|
|
{
|
|
// Get the template and file name from the string
|
|
$temp = explode(':', $layout);
|
|
$template = $temp[0] === '_' ? $template : $temp[0];
|
|
$layout = $temp[1];
|
|
$defaultLayout = $temp[1] ?: 'default';
|
|
}
|
|
|
|
// Build the template and base path for the layout
|
|
$pathes = array();
|
|
if (!empty($suffix)) {
|
|
$pathes[] = JPATH_THEMES . '/' . $template . '/html/' . $module . '/' . $suffix . '/' . $layout . '.php';
|
|
$pathes[] = JPATH_BASE . '/modules/' . $module . '/tmpl/' . $suffix . '/' . $defaultLayout . '.php';
|
|
}
|
|
$pathes[] = JPATH_THEMES . '/' . $template . '/html/' . $module . '/' . $layout . '.php';
|
|
$pathes[] = JPATH_BASE . '/modules/' . $module . '/tmpl/' . $defaultLayout . '.php';
|
|
|
|
// Return the first match
|
|
foreach ($pathes as $path) {
|
|
if (file_exists($path)) {
|
|
return $path;
|
|
}
|
|
}
|
|
// last chance
|
|
return JPATH_BASE . '/modules/' . $module . '/tmpl/default.php';
|
|
}
|
|
|
|
static public function loadCss($css)
|
|
{
|
|
$settings = self::retrieveCss();
|
|
$suffix = self::getLayoutStyleSuffix();
|
|
$app = Factory::getApplication();
|
|
$document = $app->getDocument();
|
|
$uri = Uri::getInstance();
|
|
$url = $uri->root();
|
|
if (!empty($suffix)) {
|
|
$suffix = '-' . $suffix;
|
|
}
|
|
|
|
if ($settings->get('css_' . $css . '_usecustom', '0')) {
|
|
|
|
# we want to use custom so now check if we've a file
|
|
$file = $settings->get('css_' . $css . '_customfile');
|
|
$is_file = false;
|
|
|
|
# something was filled, now check if we've a valid file
|
|
if ($file) {
|
|
$file = preg_replace('%^/([^/]*)%', '$1', $file); // remove leading single slash
|
|
$is_file = File::exists(JPATH_SITE . '/media/com_jem/css/custom/' . $file);
|
|
|
|
if ($is_file) {
|
|
# at this point we do have a valid file but let's check the extension too.
|
|
$ext = File::getExt($file);
|
|
if ($ext != 'css') {
|
|
# the file is valid but the extension not so let's return false
|
|
$is_file = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($is_file) {
|
|
# we do have a valid file so we will use it.
|
|
// $css = HTMLHelper::_('stylesheet', $file, array(), false);
|
|
$css = $document->addStyleSheet($url.'media/com_jem/css/custom/' . $file);
|
|
} else {
|
|
# unfortunately we don't have a valid file so we're looking at the default
|
|
// $files = HTMLHelper::_('stylesheet', 'com_jem/' . $css . $suffix . '.css', array(), true, true);
|
|
$files = $document->addStyleSheet($url.'media/com_jem/css/custom/' . $css . $suffix . '.css');
|
|
if (!empty($files)) {
|
|
# we have to call this stupid function twice; no other way to know if something was loaded
|
|
// $css = HTMLHelper::_('stylesheet', 'com_jem/' . $css . $suffix . '.css', array(), true);
|
|
$css = $document->addStyleSheet($url.'media/com_jem/css/custom/' . $css . $suffix . '.css');
|
|
|
|
} else {
|
|
# no css for layout style configured, so use the default css
|
|
// $css = HTMLHelper::_('stylesheet', 'com_jem/' . $css . '.css', array(), true);
|
|
$css = $document->addStyleSheet($url.'media/com_jem/css/custom/'. $css. '.css');
|
|
|
|
}
|
|
}
|
|
} else {
|
|
# here we want to use the normal css
|
|
// $files = HTMLHelper::_('stylesheet', 'com_jem/' . $css . $suffix . '.css', array(), true, true);
|
|
$files = $document->addStyleSheet($url.'media/com_jem/css/' . $css . $suffix . '.css');
|
|
|
|
if (!empty($files)) {
|
|
# we have to call this stupid function twice; no other way to know if something was loaded
|
|
// $css = HTMLHelper::_('stylesheet', 'com_jem/' . $css . $suffix . '.css', array(), true);
|
|
$css = $document->addStyleSheet($url.'media/com_jem/css/' . $css . $suffix . '.css');
|
|
|
|
} else {
|
|
# no css for layout style configured, so use the default css
|
|
// $css = HTMLHelper::_('stylesheet', 'com_jem/' . $css . '.css', array(), true);
|
|
$css = $document->addStyleSheet($url.'media/com_jem/css/'. $css. '.css');
|
|
|
|
}
|
|
}
|
|
|
|
return $css;
|
|
}
|
|
|
|
/**
|
|
* Get the url to a css file for a module respecting layout style configured in JEM Settings.
|
|
*
|
|
* @param string $module The name of the module
|
|
* @param string $css The name of the css file (in the root path). If null, the name of module is used (in the suffix directory).
|
|
*
|
|
* @since 2.3
|
|
*/
|
|
public static function loadModuleStyleSheet($module, $css = null)
|
|
{
|
|
$app = Factory::getApplication();
|
|
$wa = $app->getDocument()->getWebAssetManager();
|
|
$templateName = $app->getTemplate();
|
|
$suffix = self::getLayoutStyleSuffix();
|
|
|
|
if (empty($css)) {
|
|
$css = $module;
|
|
$filestyle = ($suffix? $suffix . '/':'') . $css . '.css';
|
|
}else{
|
|
$filestyle = $css . '.css';
|
|
}
|
|
|
|
//Search for template overrides
|
|
if(file_exists(JPATH_BASE . '/templates/' . $templateName . '/html/' . $module . '/' . $filestyle)) {
|
|
$wa->registerAndUseStyle($module . ($css? '.' . $css: ''), 'templates/' . $templateName . '/html/'. $module . '/' . $filestyle);
|
|
}
|
|
//Search in media folder
|
|
else if (file_exists(JPATH_BASE . '/media/' . $module . '/css/' . $filestyle)) {
|
|
$wa->registerAndUseStyle($module . ($css? '.' . $css: ''), 'media/' . $module . '/css/' . $filestyle);
|
|
}
|
|
//Search in the module
|
|
else if (file_exists(JPATH_BASE . '/modules/' . $module . '/tmpl/' . $filestyle)) {
|
|
$wa->registerAndUseStyle($module . ($css? '.' . $css: ''), 'modules/'. $module . '/tmpl/' . $filestyle);
|
|
}
|
|
//Error the css file doesn't found
|
|
else {
|
|
JemHelper::addLogEntry("Warning: The " . $filestyle . " file doesn't found.", __METHOD__);
|
|
}
|
|
}
|
|
|
|
static public function loadIconFont()
|
|
{
|
|
$jemsettings = JemHelper::config();
|
|
if ($jemsettings->useiconfont == 1) {
|
|
# This will automaticly search for 'font-awesome.css' if site is in debug mode.
|
|
# Note: css files must be stored on /media/com_jem/css/ to be conform to Joomla and also allow template overrides.
|
|
HTMLHelper::_('stylesheet', 'media/vendor/fontawesome-free/css/font-awesome.min.css', array(), true);
|
|
HTMLHelper::_('stylesheet', 'com_jem/css/jem-icon-font.css', array(), true);
|
|
}
|
|
}
|
|
|
|
static public function defineCenterMap($data = false)
|
|
{
|
|
# retrieve venue
|
|
$venue = $data->getValue('venue');
|
|
|
|
if ($venue) {
|
|
# latitude/longitude
|
|
$lat = $data->getValue('latitude');
|
|
$long = $data->getValue('longitude');
|
|
|
|
if ($lat == 0.000000) {
|
|
$lat = null;
|
|
}
|
|
|
|
if ($long == 0.000000) {
|
|
$long = null;
|
|
}
|
|
|
|
if ($lat && $long) {
|
|
$location = '['.$data->getValue('latitude').','.$data->getValue('longitude').']';
|
|
} else {
|
|
# retrieve address-info
|
|
$postalCode = $data->getValue('postalCode');
|
|
$city = $data->getValue('city');
|
|
$street = $data->getValue('street');
|
|
|
|
$location = '"'.$street.' '.$postalCode.' '.$city.'"';
|
|
}
|
|
$location = 'location:'.$location.',';
|
|
} else {
|
|
$location = '';
|
|
}
|
|
|
|
return $location;
|
|
}
|
|
|
|
/**
|
|
* Load Custom CSS
|
|
*
|
|
* @return boolean
|
|
*/
|
|
static public function loadCustomCss()
|
|
{
|
|
$app = Factory::getApplication();
|
|
$document = $app->getDocument();
|
|
$settings = self::retrieveCss();
|
|
$jemsettings = self::config();
|
|
$layoutstyle = isset($jemsettings->layoutstyle) ? (int)$jemsettings->layoutstyle : 0;
|
|
$style = "";
|
|
|
|
# background-colors
|
|
$bg_filter = $settings->get('css_color_bg_filter');
|
|
$bg_h2 = $settings->get('css_color_bg_h2');
|
|
$bg_jem = $settings->get('css_color_bg_jem');
|
|
$bg_table_th = $settings->get('css_color_bg_table_th');
|
|
$bg_table_td = $settings->get('css_color_bg_table_td');
|
|
$bg_table_tr_entry2 = $settings->get('css_color_bg_table_tr_entry2');
|
|
$bg_table_tr_hover = $settings->get('css_color_bg_table_tr_hover');
|
|
$bg_table_tr_featured = $settings->get('css_color_bg_table_tr_featured');
|
|
# border-colors
|
|
$border_filter = $settings->get('css_color_border_filter');
|
|
$border_h2 = $settings->get('css_color_border_h2');
|
|
$border_table_th = $settings->get('css_color_border_table_th');
|
|
$border_table_td = $settings->get('css_color_border_table_td');
|
|
# font-color
|
|
$font_table_h2 = $settings->get('css_color_font_h2');
|
|
$font_table_th = $settings->get('css_color_font_table_th');
|
|
$font_table_td = $settings->get('css_color_font_table_td');
|
|
$font_table_td_a = $settings->get('css_color_font_table_td_a');
|
|
|
|
switch ($layoutstyle) {
|
|
case 1: // 'responsive'
|
|
if (!empty($bg_filter)) {
|
|
$style .= "div#jem #jem_filter {background-color:".$bg_filter.";}";
|
|
}
|
|
if (!empty($bg_h2)) {
|
|
$style .= "div#jem h2 {background-color:".$bg_h2.";}";
|
|
}
|
|
if (!empty($bg_jem)) {
|
|
$style .= "div#jem {background-color:".$bg_jem.";}";
|
|
}
|
|
if (!empty($bg_table_th)) {
|
|
$style .= "div#jem .jem-misc, div#jem .jem-sort-small {background-color:" . $bg_table_th . ";}";
|
|
}
|
|
if (!empty($bg_table_td)) { //Caused by the row-layout of JEM-Responsive, there exist no cells, we use that for row-color
|
|
$style .= "div#jem .eventlist li:nth-child(odd) {background-color:" . $bg_table_td . ";}";
|
|
}
|
|
if (!empty($bg_table_tr_entry2)) {
|
|
$style .= "div#jem .eventlist li:nth-child(even) {background-color:" . $bg_table_tr_entry2 . ";}";
|
|
}
|
|
if (!empty($bg_table_tr_featured)) {
|
|
$style .= "div#jem .eventlist .jem-featured {background-color:" . $bg_table_tr_featured . ";}";
|
|
}
|
|
// Important: :hover must be after .featured to overrule
|
|
if (!empty($bg_table_tr_hover)) {
|
|
$style .= "div#jem .eventlist li:hover {background-color:" . $bg_table_tr_hover . ";}";
|
|
}
|
|
if (!empty($border_filter)) {
|
|
$style .= "div#jem #jem_filter {border: 1px solid " . $border_filter . ";}";
|
|
}
|
|
if (!empty($border_h2)) {
|
|
$style .= "div#jem h2 {border: 1px solid " . $border_h2 . ";}";
|
|
}
|
|
if (!empty($border_table_th)) {
|
|
$style .= "div#jem .jem-misc, div#jem .jem-sort-small {border: 1px solid " . $border_table_th . ";}";
|
|
}
|
|
if (!empty($border_table_td)) {
|
|
$style .= "div#jem .jem-event, div#jem .jem-event:first-child {border-color: " . $border_table_td . ";}";
|
|
}
|
|
if (!empty($font_table_h2)) {
|
|
$style .= "div#jem h2 {color:" . $font_table_h2 . ";}";
|
|
}
|
|
if (!empty($font_table_th)) {
|
|
$style .= "div#jem .jem-misc, div#jem .jem-sort-small {color:" . $font_table_th . ";}";
|
|
}
|
|
if (!empty($font_table_td)) {
|
|
$style .= "div#jem .jem-event {color:" . $font_table_td . ";}";
|
|
}
|
|
if (!empty($font_table_td_a)) {
|
|
$style .= "div#jem .jem-event a {color:" . $font_table_td_a . ";}";
|
|
}
|
|
break;
|
|
case 2: // 'alternative'
|
|
if (!empty($bg_filter)) {
|
|
$style .= "div#jem #jem_filter {background-color:".$bg_filter.";}";
|
|
}
|
|
if (!empty($bg_h2)) {
|
|
$style .= "div#jem h2 {background-color:".$bg_h2.";}";
|
|
}
|
|
if (!empty($bg_jem)) {
|
|
$style .= "div#jem {background-color:".$bg_jem.";}";
|
|
}
|
|
if (!empty($bg_table_th)) {
|
|
$style .= "div#jem div.eventtable .sectiontableheader {background-color:" . $bg_table_th . ";}";
|
|
}
|
|
if (!empty($bg_table_td)) {
|
|
$style .= "div#jem div.eventtable .sectiontableentry:nth-child(even) {background-color:" . $bg_table_td . ";}";
|
|
}
|
|
if (!empty($bg_table_tr_entry2)) {
|
|
$style .= "div#jem div.eventtable .sectiontableentry:nth-child(odd) {background-color:" . $bg_table_tr_entry2 . ";}";
|
|
}
|
|
if (!empty($bg_table_tr_featured)) {
|
|
$style .= "div#jem div.eventtable .sectiontableentry.featured {background-color:" . $bg_table_tr_featured . ";}";
|
|
}
|
|
// Important: :hover must be after .featured to overrule
|
|
if (!empty($bg_table_tr_hover)) {
|
|
$style .= "div#jem div.eventtable .sectiontableentry:hover {background-color:" . $bg_table_tr_hover . ";}";
|
|
}
|
|
if (!empty($border_filter)) {
|
|
$style .= "div#jem #jem_filter {border-color:" . $border_filter . ";}";
|
|
}
|
|
if (!empty($border_h2)) {
|
|
$style .= "div#jem h2 {border-color:".$border_h2.";}";
|
|
}
|
|
if (!empty($border_table_th)) {
|
|
$style .= "div#jem div.eventtable .sectiontableheader {border-color:" . $border_table_th . ";}";
|
|
}
|
|
if (!empty($border_table_td)) {
|
|
$style .= "div#jem div.eventtable .sectiontableentry {border-color:" . $border_table_td . ";}";
|
|
}
|
|
if (!empty($font_table_h2)) {
|
|
$style .= "div#jem h2 {color:" . $font_table_h2 . ";}";
|
|
}
|
|
if (!empty($font_table_th)) {
|
|
$style .= "div#jem div.eventtable .sectiontableheader {color:" . $font_table_th . ";}";
|
|
}
|
|
if (!empty($font_table_td)) {
|
|
$style .= "div#jem div.eventtable .sectiontableentry {color:" . $font_table_td . ";}";
|
|
}
|
|
if (!empty($font_table_td_a)) {
|
|
$style .= "div#jem div.eventtable .sectiontableentry a {color:" . $font_table_td_a . ";}";
|
|
}
|
|
break;
|
|
default: // 'original'
|
|
if (!empty($bg_filter)) {
|
|
$style .= "div#jem #jem_filter {background-color:".$bg_filter.";}";
|
|
}
|
|
if (!empty($bg_h2)) {
|
|
$style .= "div#jem h2 {background-color:".$bg_h2.";}";
|
|
}
|
|
if (!empty($bg_jem)) {
|
|
$style .= "div#jem {background-color:".$bg_jem.";}";
|
|
}
|
|
if (!empty($bg_table_th)) {
|
|
$style .= "div#jem table.eventtable th {background-color:" . $bg_table_th . ";}";
|
|
}
|
|
if (!empty($bg_table_td)) {
|
|
$style .= "div#jem table.eventtable td {background-color:" . $bg_table_td . ";}";
|
|
}
|
|
if (!empty($bg_table_tr_entry2)) {
|
|
$style .= "div#jem table.eventtable tr.sectiontableentry2 td {background-color:" . $bg_table_tr_entry2 . ";}";
|
|
}
|
|
if (!empty($bg_table_tr_featured)) {
|
|
$style .= "div#jem table.eventtable tr.featured td {background-color:" . $bg_table_tr_featured . ";}";
|
|
}
|
|
// Important: :hover must be after .featured to overrule
|
|
if (!empty($bg_table_tr_hover)) {
|
|
$style .= "div#jem table.eventtable tr:hover td {background-color:" . $bg_table_tr_hover . ";}";
|
|
}
|
|
if (!empty($border_filter)) {
|
|
$style .= "div#jem #jem_filter {border-color:" . $border_filter . ";}";
|
|
}
|
|
if (!empty($border_h2)) {
|
|
$style .= "div#jem h2 {border-color:".$border_h2.";}";
|
|
}
|
|
if (!empty($border_table_th)) {
|
|
$style .= "div#jem table.eventtable th {border-color:" . $border_table_th . ";}";
|
|
}
|
|
if (!empty($border_table_td)) {
|
|
$style .= "div#jem table.eventtable td {border-color:" . $border_table_td . ";}";
|
|
}
|
|
if (!empty($font_table_h2)) {
|
|
$style .= "div#jem h2 {color:" . $font_table_h2 . ";}";
|
|
}
|
|
if (!empty($font_table_th)) {
|
|
$style .= "div#jem table.eventtable th {color:" . $font_table_th . ";}";
|
|
}
|
|
if (!empty($font_table_td)) {
|
|
$style .= "div#jem table.eventtable td {color:" . $font_table_td . ";}";
|
|
}
|
|
if (!empty($font_table_td_a)) {
|
|
$style .= "div#jem table.eventtable td a {color:" . $font_table_td_a . ";}";
|
|
}
|
|
break;
|
|
} // switch
|
|
|
|
$document->addStyleDeclaration($style);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Loads Custom Tags
|
|
*
|
|
* @return boolean
|
|
*/
|
|
static public function loadCustomTag()
|
|
{
|
|
$app = Factory::getApplication();
|
|
$document = $app->getDocument();
|
|
$tag = "";
|
|
$tag .= "<!--[if IE]><style type='text/css'>.floattext{zoom:1;}, * html #jem dd { height: 1%; }</style><![endif]-->";
|
|
|
|
$document->addCustomTag($tag);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get a variable from the manifest file (actually, from the manifest cache).
|
|
*
|
|
* @param $column manifest_cache(1),params(2)
|
|
* @param $setting name of setting to retrieve
|
|
* @param $type compononent(1), plugin(2)
|
|
* @param $name name to search in column name
|
|
*/
|
|
static public function getParam($column, $setting, $type, $name)
|
|
{
|
|
switch ($column) {
|
|
case 1:
|
|
$column = 'manifest_cache';
|
|
break;
|
|
case 2:
|
|
$column = 'params';
|
|
break;
|
|
}
|
|
|
|
switch ($type) {
|
|
case 1:
|
|
$type = 'component';
|
|
break;
|
|
case 2:
|
|
$type = 'plugin';
|
|
break;
|
|
case 3:
|
|
$type = 'module';
|
|
break;
|
|
}
|
|
|
|
$db = Factory::getContainer()->get('DatabaseDriver');
|
|
$query = $db->getQuery(true);
|
|
$query->select(array($column));
|
|
$query->from('#__extensions');
|
|
$query->where(array('name = '.$db->quote($name),'type = '.$db->quote($type)));
|
|
$db->setQuery($query);
|
|
|
|
$manifest = json_decode($db->loadResult(), true);
|
|
$result = $manifest[ $setting ];
|
|
|
|
if (empty($result)) {
|
|
$result = 'N/A';
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
static public function getCountryOptions()
|
|
{
|
|
$options = array();
|
|
$options = array_merge(JemHelperCountries::getCountryOptions(),$options);
|
|
|
|
array_unshift($options, HTMLHelper::_('select.option', '0', Text::_('COM_JEM_SELECT_COUNTRY')));
|
|
|
|
return $options;
|
|
}
|
|
|
|
/**
|
|
* This method transliterates a string into a URL
|
|
* safe string or returns a URL safe UTF-8 string
|
|
* based on the global configuration
|
|
*
|
|
* @param string $string String to process
|
|
*
|
|
* @return string Processed string
|
|
*
|
|
* @see ApplicationHelper
|
|
* @since 2.1.7
|
|
*/
|
|
static public function stringURLSafe($string)
|
|
{
|
|
return ApplicationHelper::stringURLSafe($string);
|
|
}
|
|
|
|
/**
|
|
* This method returns true if a string is within another string.
|
|
*
|
|
* @param string $masterstring
|
|
* @param string $string
|
|
* @return boolean
|
|
*/
|
|
static public function jemStringContains($masterstring, $string)
|
|
{
|
|
return ($masterstring && $string && strpos($masterstring, $string) !== false);
|
|
}
|
|
}
|