Your IP : 216.73.216.85


Current Path : /home/smartconb/www/armencom33/modules/mod_azdirectory/src/Helper/
Upload File :
Current File : /home/smartconb/www/armencom33/modules/mod_azdirectory/src/Helper/AzdirectoryHelper.php

<?php
/**
 * @package        A-Z Directory
 * @subpackage     mod_azdirectory
 * @copyright      Copyright (C) 2016 Bmore Creative, Inc. All rights reserved.
 * @license        GNU General Public License version 2 or later; see LICENSE.txt
 *
 * @website        https://www.bmorecreativeinc.com/joomla/extensions
 */

namespace Joomla\Module\Azdirectory\Site\Helper;

// no direct access
defined('_JEXEC') or die('Restricted access');

use Joomla\CMS\Application\CMSApplication;
use Joomla\CMS\Date\Date;
use Joomla\CMS\Filter\InputFilter;
use Joomla\CMS\Filter\OutputFilter;
use Joomla\CMS\Helper\ModuleHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\Component\Fields\Administrator\Helper\FieldsHelper;
use Joomla\Database\DatabaseInterface;
use Joomla\Input\Input;
use Joomla\Registry\Registry;
use RuntimeException;

class AzdirectoryHelper
{
    private static $azInstance = [];

    /**
     * The Joomla application object
     *
     * @var CMSApplication|null
     */
    private $app;

    /**
     * The module instance
     *
     * @var    \stdClass
     * @since  7.1.0
     */
    private $module;

    /**
     * The module parameters
     *
     * @var Registry|null
     */
    private $params = null;

    /**
     * Database
     *
     * @var       DatabaseInterface
     * @since  7.1.1
     */
    private $dbo;

    /**
     * Constructor
     *
     * @param   array  $config  Configuration parameters
     */
    public function __construct(array $config = [])
    {
        mb_internal_encoding('utf-8');

        $params = $config['params'] ?? null;

        if ($params instanceof Registry) {
            $this->params = $params;
        }

        $this->module = $config['module'] ?? null;
    }

    /**
     * Set the database.
     *
     * @param   DatabaseInterface  $db  The database.
     *
     * @return  void
     *
     * @since   7.1.1
     */
    public function setDatabase(DatabaseInterface $db): void
    {
        $this->dbo = $db;
    }

    /**
     * Method to format name
     */
    public function azFormatName($name, $lastnameFirst)
    {
        if ($lastnameFirst == 1) :
            $parser    = new FullNameParserHelper();
            $words     = $parser->parse_name($name);
            $lastname  = $words['lname'];
            $firstname = $words['fname'];
            $name      = $lastname . ", " . $firstname;
        endif;
        return $name;
    }

    /**
     * Method to sanitize telephone numbers
     */
    public function azSanitizeTelephone($telephone)
    {
        return str_replace(["+", "-"], "", filter_var($telephone, FILTER_SANITIZE_NUMBER_INT));
    }

    /**
     * Method to sanitize URLs
     */
    public function azSanitizeURL($url)
    {
        $filter = InputFilter::getInstance();
        return $filter->clean($url, "string");
    }

    /**
     * Method to get contact information based on first letter of last name
     */
    public function getContactsAjax()
    {
        $app = $this->app;

        // Get the data
        $azdata     = $app->input->getString('data');
        $azdata     = is_array($azdata) ? $azdata : [$azdata];
        $lastletter = filter_var($azdata['letter'] ?? 'All', FILTER_SANITIZE_STRING);
        $start      = filter_var($azdata['start'] ?? 0, FILTER_SANITIZE_NUMBER_INT);
        $title      = filter_var($azdata['title'] ?? null, FILTER_SANITIZE_STRING);

        $this->module = ModuleHelper::getModule('azdirectory', $title);
        $this->params = new Registry($this->module->params);

        $input = clone $this->app->input;
        $input->set('lastletter', $lastletter);
        $input->set('_az_start', $start);

        $layoutData = array_merge([
            'module'   => $this->module,
            'app'      => $this->app,
            'input'    => $this->app->input,
            'params'   => $this->params,
            'template' => $this->app->getTemplate(),
        ], $this->getLayoutData($input));

        ob_clean();

        extract($layoutData);

        // checks for layout override first, then checks for original
        include ModuleHelper::getLayoutPath($this->module->module, $this->params->get('layout', 'default'));

        $app->close();
    }

    /**
     * Get the data to pass to the view template
     *
     * @return  array
     * @since   7.1.0
     */
    public function getLayoutData(?Input $input = null): array
    {
        $input = $input ?? $this->app->input;

        $layoutData = [];

        // Push all parameters as layout data.
        foreach ($this->params->getIterator() as $key => $value) {
            if (is_string($value)) {
                $value = htmlspecialchars($value);
                $this->params->set($key, $value);
                $layoutData[$key] = $value;
            }
        }

        $layoutData['params'] = $this->params;

        // Handle `lastletter` parameter in the URL
        $lastLetter = $input->getString('lastletter');

        if (is_null($lastLetter)) {
            // handle configured last letter
            $defaultLetter = $this->params->get('defaultletter', '');

            if (in_array(
                $this->params->get('sortorder', 'ln'),
                ['fn', 'component', 'sortfield'],
                true
            )) {
                $defaultLetter = $this->params->get('defaultletterfn', '');
            }

            $lastLetter = (($defaultLetter === 'All') ? Text::_('JALL') : $defaultLetter);
        }

        $layoutData['lastletter'] = $lastLetter;

        // Get the rest of the layout data from the helper
        $start = $input->getInt('_az_start', 0);
        [$contacts, $total, $start] = $this->azGenerateQuery($lastLetter, $start);

        $layoutData['contacts']        = $contacts;
        $layoutData['total']           = $total;
        $layoutData['start']           = $start;
        $layoutData['az']              = $this;
        $layoutData['azdirectory']     = $this->getAZDirectory();
        $layoutData['modAZAssetsPath'] = Uri::base() . 'media/' . $this->module->module . '/images/';

        return $layoutData;
    }

    /**
     * Method to generate SQL query
     *
     * @param   string    $letter  The currently active letter, or "All"
     * @param   int       $start   How many records to skip
     * @param   Registry  $params  The module parameters
     *
     * @return array
     */
    public function azGenerateQuery(string $letter, int $start): array
    {
        // Get the database object
        $db = $this->getDatabase();
        // Get configuration parameters
        $catid      = $this->params->get('id');
        $tagid      = $this->params->get('tags');
        $sortorder  = $this->params->get('sortorder');
        $pagination = $this->params->get('pagination');
        $alphabet   = $this->params->get('swedish', [0]);
        // Populate variables used in the queries
        $published  = 1;
        $authorised = $this->app->getIdentity()->getAuthorisedViewLevels();
        $nullDate   = $db->getNullDate();
        $nowDate    = Date::getInstance()->toSql();

        // Initialize query
        // whereIn will automatically use the values and add prepared statements
        $query = $db->getQuery(true)
                    ->select(['*'])
                    ->from($db->quoteName('#__contact_details', 'a'));

        if (!empty($catid[0])) {
            $query->whereIn($db->quoteName('a.catid'), $catid);
        }

        if (!empty($tagid[0])) {
            $query
                ->join(
                    'LEFT',
                    $db->quoteName('#__contentitem_tag_map', 'b') . ' ON (' . $db->quoteName(
                        'a.id'
                    ) . ' = ' . $db->quoteName('b.content_item_id') . ')'
                )
                ->where($db->quoteName('b.type_alias') . ' = ' . $db->quote('com_contact.contact'))
                ->whereIn($db->quoteName('b.tag_id'), $tagid);
        }

        $query
            ->whereIn($db->quoteName('a.access'), $authorised)
            ->where($db->quoteName('a.published') . ' = :published')
            ->andWhere(
                [
                    $db->quoteName('a.publish_up') . ' = :nullDate1',
                    $db->quoteName('a.publish_up') . ' IS NULL',
                    $db->quoteName('a.publish_up') . ' <= :nowDate1',
                ]
            )
            ->andWhere(
                [
                    $db->quoteName('a.publish_down') . ' = :nullDate2',
                    $db->quoteName('a.publish_down') . ' IS NULL',
                    $db->quoteName('a.publish_down') . ' >= :nowDate2',
                ]
            )
            ->bind(':nowDate1', $nowDate)
            ->bind(':nowDate2', $nowDate)
            ->bind(':nullDate1', $nullDate)
            ->bind(':nullDate2', $nullDate)
            ->bind(':published', $published);

        $db->setQuery($query);

        $result = $db->loadObjectList();

        foreach ($result as $record) {
            // Add the targeted letter to each object
            $name = $record->name;

            if ($sortorder == 'ln') {
                $parser         = new FullNameParserHelper();
                $words          = $parser->parse_name($name);
                $record->letter = mb_substr($words['lname'], 0, 1, "utf8");
                $record->ln     = $words['lname'];
            } else {
                $record->letter = mb_substr($name, 0, 1, "utf8");
            }

            // Add the category name to each object
            $record->catname = $this->azCategory($record->catid);

            // Add custom fields to each object
            $record->customfields = $this->azCustomFields($record->id);
        }

        // remove objects where the selected letter is not the targeted letter
        if ($letter != Text::_('JALL')) {
            $result = array_filter($result, function ($a) use ($letter) {
                return $a->letter === $letter;
            });
        }

        $locale = 'en_US.UTF-8';

        if (in_array(1, $alphabet)) {
            $locale = 'sv_SE.UTF-8';
        }

        if (in_array(3, $alphabet)) {
            $locale = 'cs_CZ.UTF-8';
        }

        setlocale(LC_ALL, $locale);

        usort($result, function ($a, $b) use ($sortorder) {
            switch ($sortorder) {
                case 'fn' :
                    return strcoll($a->name, $b->name);
                    break;

                case 'ln' :
                    return strcoll($a->ln, $b->ln);
                    break;

                case 'sortfield' :
                    return strcmp($a->sortname1, $b->sortname1);
                    break;

                case 'component' :
                    return strnatcmp($a->ordering, $b->ordering);
                    break;

                default :
                    return strcoll($a->ln, $b->ln);
            }
        });

        // Get the true number of array entries
        $total_rows = sizeof($result);

        // Pagination if not All
        $result = ($pagination === 'All') ? $result : array_slice($result, $start, $pagination);

        return [$result, $total_rows, $start];
    }

    /**
     * Get the database.
     *
     * @return  DatabaseInterface
     *
     * @throws  RuntimeException May be thrown if the database has not been set.
     * @since   7.1.1
     */
    protected function getDatabase(): DatabaseInterface
    {
        if ($this->dbo) {
            return $this->dbo;
        }

        throw new RuntimeException('Database not set in ' . \get_class($this));
    }

    /**
     * Method to get category title from ID
     */
    public function azCategory($catid)
    {
        // access database object
        $db = $this->getDatabase();

        // initialize query
        $query = $db->getQuery(true)
                    ->select($db->quoteName('title'))
                    ->from($db->quoteName('#__categories'))
                    ->where($db->quoteName('id') . ' = :catid')
                    ->bind(':catid', $catid);

        $db->setQuery($query);

        return $db->loadResult();
    }

    /**
     * Method to get custom fields
     */
    public function azCustomFields($id)
    {
        // load fields model
        \JModelLegacy::addIncludePath( JPATH_ADMINISTRATOR . '/components/com_fields/models', 'FieldsModel' );
        $azModel = \JModelLegacy::getInstance( 'Field', 'FieldsModel', ['ignore_request' => true] );
        // get custom fields by contact ID
        $azCustomFields = FieldsHelper::getFields( 'com_contact.contact', $id, true );
		// convert stdClass object to array
		$azCustomFieldsObj2Arr = json_decode( json_encode( $azCustomFields ), true );
		// create new array with selected keys
		$azCustomFields = array();
		foreach( $azCustomFieldsObj2Arr as $key => $column ) {
			$azCustomFields[$key] = array_intersect_key(
				$column,
				array_flip( ['id', 'fieldparams', 'title', 'type'] )
			);
		}
				
		foreach( $azCustomFields as $key => $column ) {
			// add custom field value to array
			$azCustomFieldValue = $azModel->getFieldValue( $column['id'], $id );
			$azCustomFields[$key]['value'] = $azCustomFieldValue;

			// mimic Joomla behavior for displaying URLs
			if( $column['type'] == 'url' ){
				$azUrlHyperlink = ( $column['fieldparams']['show_url'] == 0 ) ? Text::_( 'JVISIT_LINK' ) : htmlspecialchars( $azCustomFieldValue );
				$azCustomFields[$key]['value'] = '<a href="' . $this->azSanitizeURL( $azCustomFieldValue ) . '" target="_blank" rel="noopener">' .  $azUrlHyperlink . '</a>';
			}
			
			// store the option text as the value for checkboxes, list, and radio
			if( array_key_exists( 'options', $column['fieldparams'] ) ){
				$azOptionText = "";
				// loop through all the options
				foreach( $column['fieldparams']['options'] as $option ){
					// https://github.com/mitydigital/joomla-item-helper/blob/main/ItemHelper.php
					// check if the selected value(s) has the current option
                    // if the value is an array, there are 2 or more options - look inside the value as an array
                    // if the value is a string, there is only one option - compare it is as a string
					if( ( is_array( $azCustomFieldValue ) && in_array( $option['value'], $azCustomFieldValue ) ) || $azCustomFieldValue == $option['value'] ){
						$azOptionText .= $option['name'] . ", ";
					}
				}
				$azCustomFields[$key]['value'] = rtrim( $azOptionText, ", " );
			}
			
			// add title slug to array for class names
			$azCustomFields[$key]['slug'] = OutputFilter::stringURLSafe( $column['title'] );
			// eliminate array entries with empty values
			if( empty( $azCustomFieldValue ) ){
				unset( $azCustomFields[$key] );
			}
		}

        return $azCustomFields;
    }

    /**
     * Get module parameters
     *
     * @param   array  $params  An object containing the module parameters
     */
    public function getAZDirectory()
    {
        $doc = $this->app->getDocument();
        $wam = $doc->getWebAssetManager();

        if (!$wam->getRegistry()->exists('style', 'modazdirectory.bootstrap')) {
            $wam->getRegistry()->addExtensionRegistryFile('mod_azdirectory');
        }

        $nameHyperlink = $this->params->get('name_hyperlink', 0) == 1;

        if ($nameHyperlink == 1) :
            // Load only the standard Bootstrap modal and our custom Bootstrap styles
            $wam->useScript('bootstrap.modal');
            $wam->useStyle('mod_azdirectory.bootstrap');
        endif;

        // set a flag whether to load azModal JS
        $doc->addScriptOptions('mod_azdirectory', [
            'nameHyperlink' => $nameHyperlink,
        ]);

        // pass value for JALL language constant to Javascript
        Text::script('JALL');

        // load standard assets
        $wam->useStyle('mod_azdirectory.directory');

        $loadJS = $this->params->get('loadjs');
        if ($loadJS == 1) :
            $wam->useScript('mod_azdirectory.directory');
        else :
            $wam->useScript('mod_azdirectory.formsubmit');
        endif;

        // Get the database object
        $db = $this->getDatabase();
        // Get configuration parameters
        $sortorder = $this->params->get('sortorder');
        // Populate variables used in the queries
        $published  = 1;
        $authorised = $this->app->getIdentity()->getAuthorisedViewLevels();
        $nullDate   = $db->getNullDate();
        $nowDate    = Date::getInstance()->toSql();

        // initialize query
        // whereIn will automatically use the values and add prepared statements
        $query = $db->getQuery(true)
                    ->select($db->quoteName('name') . " AS name")
                    ->from($db->quoteName('#__contact_details', 'a'));

        $catid = $this->params->get('id');
        if (!empty($catid[0])) :
            $query->whereIn($db->quoteName('a.catid'), $catid);
        endif;

        $tagid = (array)$this->params->get('tags');
        if (!empty($tagid[0])) :
            $query
                ->join(
                    'LEFT',
                    $db->quoteName('#__contentitem_tag_map', 'b') . ' ON (' . $db->quoteName(
                        'a.id'
                    ) . ' = ' . $db->quoteName('b.content_item_id') . ')'
                )
                ->where($db->quoteName('b.type_alias') . ' = ' . $db->quote('com_contact.contact'))
                ->whereIn($db->quoteName('b.tag_id'), $tagid);
        endif;

        $query
            ->whereIn($db->quoteName('a.access'), $authorised)
            ->where($db->quoteName('a.published') . ' = :published')
            ->andWhere(
                [
                    $db->quoteName('a.publish_up') . ' = :nullDate1',
                    $db->quoteName('a.publish_up') . ' IS NULL',
                    $db->quoteName('a.publish_up') . ' <= :nowDate1',
                ]
            )
            ->andWhere(
                [
                    $db->quoteName('a.publish_down') . ' = :nullDate2',
                    $db->quoteName('a.publish_down') . ' IS NULL',
                    $db->quoteName('a.publish_down') . ' >= :nowDate2',
                ]
            )
            ->order($db->quoteName('a.name'))
            ->bind(':nowDate1', $nowDate)
            ->bind(':nowDate2', $nowDate)
            ->bind(':nullDate1', $nullDate)
            ->bind(':nullDate2', $nullDate)
            ->bind(':published', $published);

        $db->setQuery($query);
        $rows  = $db->loadAssocList('name');
        $names = array_keys($rows);

        $letters = $alphabets = [];

        foreach ($names as $key => $name):
            if ($sortorder == 'ln') :
                $parser    = new FullNameParserHelper();
                $words     = $parser->parse_name($name);
                $letters[] = mb_substr($words['lname'], 0, 1, "utf8");
            else:
                $letters[] = mb_substr($name, 0, 1, "utf8");
            endif;
        endforeach;

        $alphabet = $this->params->get('swedish');

        // if no Language is selected, default to English (0)
        if (empty($alphabet)) {
            $alphabet = [0];
            $this->params->set('swedish', $alphabet);
        }

        // if more than 1 alphabet is selected
        if (sizeof($alphabet) > 1):
            // return the first/last letters based on fn/ln sortorder
            $letters = array_unique($letters);

            foreach ($letters as $letter) {
                // get the unicode values
                $unicode = dechex(mb_ord($letter));

                // ensure the unicode values are 4 digits by prepending zeroes
                $unicode = $this->azStrPadUnicode($unicode, 4, '0', STR_PAD_LEFT);

                // add them into Latin or Cyrillic arrays
                if (($unicode >= '0041') && ($unicode <= '024f')) {
                    $alphabets['Latin'][] = $letter;
                } elseif (($unicode >= '0400') && ($unicode <= '04ff')) {
                    $alphabets['Cyrillic'][] = $letter;
                }
            }

            // sort them alphabetically
            if (array_key_exists('Latin', $alphabets) && sizeof($alphabets['Latin']) > 0):
                sort($alphabets['Latin'], SORT_LOCALE_STRING);
            endif;

            if (array_key_exists('Cyrillic', $alphabets) && sizeof($alphabets['Cyrillic']) > 0):
                sort($alphabets['Cyrillic'], SORT_LOCALE_STRING);
            endif;

        else:
            // 1 alphabet is selected
            // convert alphabet array to a string
            $alphabet = array_shift($alphabet);

            $english = range("A", "Z");

            $swedish = ["Å", "Ä", "Ö"];

            $cyrillic = [
                "А",
                "Б",
                "В",
                "Г",
                "Д",
                "Е",
                "Ё",
                "Ж",
                "З",
                "И",
                "Й",
                "К",
                "Л",
                "М",
                "Н",
                "О",
                "П",
                "Р",
                "С",
                "Т",
                "У",
                "Ф",
                "Х",
                "Ц",
                "Ч",
                "Ш",
                "Щ",
                "Ъ",
                "Ы",
                "Ь",
                "Э",
                "Ю",
                "Я",
            ];

            $czech = [
                "A",
                "Á",
                "B",
                "C",
                "Č",
                "D",
                "Ď",
                "E",
                "É",
                "Ě",
                "F",
                "G",
                "H",
                "Ch",
                "I",
                "Í",
                "J",
                "K",
                "L",
                "M",
                "N",
                "Ň",
                "O",
                "Ó",
                "P",
                "Q",
                "R",
                "Ř",
                "S",
                "Š",
                "T",
                "Ť",
                "U",
                "Ú",
                "Ů",
                "V",
                "W",
                "X",
                "Y",
                "Ý",
                "Z",
                "Ž",
            ];

            switch ($alphabet):
                case 1:
                    $alphabets['Latin'] = array_merge($english, $swedish);
                    break;
                case 2:
                    $alphabets['Cyrillic'] = $cyrillic;
                    break;
                case 3:
                    $alphabets['Latin'] = $czech;
                    break;
                default:
                    $alphabets['Latin'] = $english;
            endswitch;
        endif;

        $tmpl    = [];
        $tmpl[0] = $alphabets;
        $tmpl[1] = array_unique($letters);

        return $tmpl;
    }

    private function azStrPadUnicode($str, $pad_len, $pad_str = ' ', $dir = STR_PAD_RIGHT)
    {
        $str_len     = mb_strlen($str);
        $pad_str_len = mb_strlen($pad_str);
        if (!$str_len && ($dir == STR_PAD_RIGHT || $dir == STR_PAD_LEFT)) {
            $str_len = 1; // @debug
        }
        if (!$pad_len || !$pad_str_len || $pad_len <= $str_len) {
            return $str;
        }

        $result = null;
        $repeat = ceil($str_len - $pad_str_len + $pad_len);
        if ($dir == STR_PAD_RIGHT) {
            $result = $str . str_repeat($pad_str, $repeat);
            $result = mb_substr($result, 0, $pad_len);
        } else {
            if ($dir == STR_PAD_LEFT) {
                $result = str_repeat($pad_str, $repeat) . $str;
                $result = mb_substr($result, -$pad_len);
            } else {
                if ($dir == STR_PAD_BOTH) {
                    $length = ($pad_len - $str_len) / 2;
                    $repeat = ceil($length / $pad_str_len);
                    $result = mb_substr(str_repeat($pad_str, $repeat), 0, floor($length))
                              . $str
                              . mb_substr(str_repeat($pad_str, $repeat), 0, ceil($length));
                }
            }
        }

        return $result;
    }

    /**
     * Method to get the default option for the select option
     */
    public function azFirstOption($sortorder)
    {
        $language = $this->app->getLanguage();
        $language->load('mod_azdirectory');

        if ($sortorder == 'ln') :
            $modazfirstoption = Text::_('MOD_AZDIRECTORY_SORTORDER_LN');
        else :
            $modazfirstoption = Text::_('MOD_AZDIRECTORY_SORTORDER_FN');
        endif;

        return $modazfirstoption;
    }

    /**
     * Method to format addresses
     */
    public function azFormatAddress($contact, $postcodeFirst)
    {
        if ($this->azVerify('suburb', $contact) || $this->azVerify('state', $contact) || $this->azVerify(
                'postcode',
                $contact
            )) :

            $lines = [];

            if ($postcodeFirst == 1) :
                // international address format
                $line = [];
                if ($this->azVerify('postcode', $contact)) {
                    $line[] = '<span>' . $contact->postcode . '</span>';
                }
                if ($this->azVerify('suburb', $contact)) {
                    $line[] = '<span>' . $contact->suburb . '</span>';
                }
                if ($this->azVerify('state', $contact)) {
                    $line[] = '<span>' . $contact->state . '</span>';
                }
                $lines[] = implode(' ', $line);
            else :
                // US address format
                $line = [];
                if ($this->azVerify('suburb', $contact)) {
                    $line[] = '<span>' . $contact->suburb . '</span>';
                }
                if ($this->azVerify('state', $contact)) {
                    $line[] = '<span>' . $contact->state . '</span>';
                }
                if (count($line)) {
                    $line = [implode(', ', $line)];
                }
                if ($this->azVerify('postcode', $contact)) {
                    $line[] = '<span>' . $contact->postcode . '</span>';
                }
                $lines[] = implode(' ', $line);
            endif;

            return $lines[0];

        endif;

        return "";
    }

    /**
     * Method to verify valid user data
     */
    public function azVerify($key, $values)
    {
        $param = $this->params->get('show_' . $key);
        $value = $values->$key;
        return (($param == 1) && ($value)) ? 1 : 0;
    }

    /**
     * @param   CMSApplication|null  $app
     */
    public function setApplication(?CMSApplication $app): void
    {
        $this->app = $app;
    }
}