Files
Component-Builder/admin/src/Model/Class_methodsModel.php
Robot 06185f8c3a Release of v5.1.1-alpha1
Move all banners to GitHub. Adds library phpspreadsheet to JCB. Adds import item example to demo component. Updates the Superpower class with the GetRemote class in the plugin. Ensures the super power autoloader triggers the correct repositories.
2025-03-04 21:50:18 +00:00

520 lines
15 KiB
PHP

<?php
/**
* @package Joomla.Component.Builder
*
* @created 30th April, 2015
* @author Llewellyn van der Merwe <https://dev.vdm.io>
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
namespace VDM\Component\Componentbuilder\Administrator\Model;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Application\CMSApplicationInterface;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Plugin\PluginHelper;
use Joomla\CMS\Router\Route;
use Joomla\CMS\User\User;
use Joomla\Utilities\ArrayHelper;
use Joomla\Input\Input;
use VDM\Component\Componentbuilder\Administrator\Helper\ComponentbuilderHelper;
use Joomla\CMS\Helper\TagsHelper;
use VDM\Joomla\Utilities\ArrayHelper as UtilitiesArrayHelper;
use VDM\Joomla\Utilities\ObjectHelper;
use VDM\Joomla\Utilities\StringHelper;
// No direct access to this file
\defined('_JEXEC') or die;
/**
* Class_methods List Model
*
* @since 1.6
*/
class Class_methodsModel extends ListModel
{
/**
* The application object.
*
* @var CMSApplicationInterface The application instance.
* @since 3.2.0
*/
protected CMSApplicationInterface $app;
/**
* The styles array.
*
* @var array
* @since 4.3
*/
protected array $styles = [
'administrator/components/com_componentbuilder/assets/css/admin.css',
'administrator/components/com_componentbuilder/assets/css/class_methods.css'
];
/**
* The scripts array.
*
* @var array
* @since 4.3
*/
protected array $scripts = [
'administrator/components/com_componentbuilder/assets/js/admin.js'
];
/**
* Constructor
*
* @param array $config An array of configuration options (name, state, dbo, table_path, ignore_request).
* @param ?MVCFactoryInterface $factory The factory.
*
* @since 1.6
* @throws \Exception
*/
public function __construct($config = [], MVCFactoryInterface $factory = null)
{
if (empty($config['filter_fields']))
{
$config['filter_fields'] = array(
'a.id','id',
'a.published','published',
'a.access','access',
'a.ordering','ordering',
'a.created_by','created_by',
'a.modified_by','modified_by',
'a.visibility','visibility',
'a.extension_type','extension_type',
'a.name','name'
);
}
parent::__construct($config, $factory);
$this->app ??= Factory::getApplication();
}
/**
* Method to auto-populate the model state.
*
* Note. Calling getState in this method will result in recursion.
*
* @param string $ordering An optional ordering field.
* @param string $direction An optional direction (asc|desc).
*
* @return void
* @since 1.7.0
*/
protected function populateState($ordering = null, $direction = null)
{
$app = $this->app;
// Adjust the context to support modal layouts.
if ($layout = $app->input->get('layout'))
{
$this->context .= '.' . $layout;
}
// Check if the form was submitted
$formSubmited = $app->input->post->get('form_submited');
$access = $this->getUserStateFromRequest($this->context . '.filter.access', 'filter_access', 0, 'int');
if ($formSubmited)
{
$access = $app->input->post->get('access');
$this->setState('filter.access', $access);
}
$published = $this->getUserStateFromRequest($this->context . '.filter.published', 'filter_published', '');
$this->setState('filter.published', $published);
$created_by = $this->getUserStateFromRequest($this->context . '.filter.created_by', 'filter_created_by', '');
$this->setState('filter.created_by', $created_by);
$created = $this->getUserStateFromRequest($this->context . '.filter.created', 'filter_created');
$this->setState('filter.created', $created);
$sorting = $this->getUserStateFromRequest($this->context . '.filter.sorting', 'filter_sorting', 0, 'int');
$this->setState('filter.sorting', $sorting);
$search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
$this->setState('filter.search', $search);
$visibility = $this->getUserStateFromRequest($this->context . '.filter.visibility', 'filter_visibility');
if ($formSubmited)
{
$visibility = $app->input->post->get('visibility');
$this->setState('filter.visibility', $visibility);
}
$extension_type = $this->getUserStateFromRequest($this->context . '.filter.extension_type', 'filter_extension_type');
if ($formSubmited)
{
$extension_type = $app->input->post->get('extension_type');
$this->setState('filter.extension_type', $extension_type);
}
$name = $this->getUserStateFromRequest($this->context . '.filter.name', 'filter_name');
if ($formSubmited)
{
$name = $app->input->post->get('name');
$this->setState('filter.name', $name);
}
// List state information.
parent::populateState($ordering, $direction);
}
/**
* Method to get an array of data items.
*
* @return mixed An array of data items on success, false on failure.
* @since 1.6
*/
public function getItems()
{
// Check in items
$this->checkInNow();
// load parent items
$items = parent::getItems();
// Set values to display correctly.
if (UtilitiesArrayHelper::check($items))
{
// Get the user object if not set.
if (!isset($user) || !ObjectHelper::check($user))
{
$user = $this->getCurrentUser();
}
foreach ($items as $nr => &$item)
{
// Remove items the user can't access.
$access = ($user->authorise('class_method.access', 'com_componentbuilder.class_method.' . (int) $item->id) && $user->authorise('class_method.access', 'com_componentbuilder'));
if (!$access)
{
unset($items[$nr]);
continue;
}
// decode arguments
$item->arguments = base64_decode($item->arguments);
}
}
// set selection value to a translatable value
if (UtilitiesArrayHelper::check($items))
{
foreach ($items as $nr => &$item)
{
// convert visibility
$item->visibility = $this->selectionTranslation($item->visibility, 'visibility');
// convert extension_type
$item->extension_type = $this->selectionTranslation($item->extension_type, 'extension_type');
}
}
// return items
return $items;
}
/**
* Method to convert selection values to translatable string.
*
* @return string The translatable string.
*/
public function selectionTranslation($value,$name)
{
// Array of visibility language strings
if ($name === 'visibility')
{
$visibilityArray = array(
'public' => 'COM_COMPONENTBUILDER_CLASS_METHOD_PUBLIC',
'protected' => 'COM_COMPONENTBUILDER_CLASS_METHOD_PROTECTED',
'private' => 'COM_COMPONENTBUILDER_CLASS_METHOD_PRIVATE',
'public static' => 'COM_COMPONENTBUILDER_CLASS_METHOD_PUBLIC_STATIC',
'protected static' => 'COM_COMPONENTBUILDER_CLASS_METHOD_PROTECTED_STATIC',
'private static' => 'COM_COMPONENTBUILDER_CLASS_METHOD_PRIVATE_STATIC'
);
// Now check if value is found in this array
if (isset($visibilityArray[$value]) && StringHelper::check($visibilityArray[$value]))
{
return $visibilityArray[$value];
}
}
// Array of extension_type language strings
if ($name === 'extension_type')
{
$extension_typeArray = array(
0 => 'COM_COMPONENTBUILDER_CLASS_METHOD_SELECT_AN_OPTION',
'powers' => 'COM_COMPONENTBUILDER_CLASS_METHOD_POWERS',
'components' => 'COM_COMPONENTBUILDER_CLASS_METHOD_COMPONENTS',
'plugins' => 'COM_COMPONENTBUILDER_CLASS_METHOD_PLUGINS',
'modules' => 'COM_COMPONENTBUILDER_CLASS_METHOD_MODULES'
);
// Now check if value is found in this array
if (isset($extension_typeArray[$value]) && StringHelper::check($extension_typeArray[$value]))
{
return $extension_typeArray[$value];
}
}
return $value;
}
/**
* Method to build an SQL query to load the list data.
*
* @return string An SQL query
* @since 1.6
*/
protected function getListQuery()
{
// Get the user object.
$user = $this->getCurrentUser();
// Create a new query object.
$db = $this->getDatabase();
$query = $db->getQuery(true);
// Select some fields
$query->select('a.*');
// From the componentbuilder_item table
$query->from($db->quoteName('#__componentbuilder_class_method', 'a'));
// From the componentbuilder_joomla_plugin_group table.
$query->select($db->quoteName(['g.name','g.id'],['joomla_plugin_group_name','joomla_plugin_group_id']));
$query->join('LEFT', $db->quoteName('#__componentbuilder_joomla_plugin_group', 'g') . ' ON (' . $db->quoteName('a.joomla_plugin_group') . ' = ' . $db->quoteName('g.guid') . ')');
// Filter by published state
$published = $this->getState('filter.published');
if (is_numeric($published))
{
$query->where('a.published = ' . (int) $published);
}
elseif ($published === '')
{
$query->where('(a.published = 0 OR a.published = 1)');
}
// Join over the asset groups.
$query->select('ag.title AS access_level');
$query->join('LEFT', '#__viewlevels AS ag ON ag.id = a.access');
// Filter by access level.
$_access = $this->getState('filter.access');
if ($_access && is_numeric($_access))
{
$query->where('a.access = ' . (int) $_access);
}
elseif (UtilitiesArrayHelper::check($_access))
{
// Secure the array for the query
$_access = ArrayHelper::toInteger($_access);
// Filter by the Access Array.
$query->where('a.access IN (' . implode(',', $_access) . ')');
}
// Implement View Level Access
if (!$user->authorise('core.options', 'com_componentbuilder'))
{
$groups = implode(',', $user->getAuthorisedViewLevels());
$query->where('a.access IN (' . $groups . ')');
}
// Filter by search.
$search = $this->getState('filter.search');
if (!empty($search))
{
if (stripos($search, 'id:') === 0)
{
$query->where('a.id = ' . (int) substr($search, 3));
}
else
{
$search = $db->quote('%' . $db->escape($search) . '%');
$query->where('(a.name LIKE '.$search.' OR a.visibility LIKE '.$search.' OR a.extension_type LIKE '.$search.' OR a.comment LIKE '.$search.' OR a.arguments LIKE '.$search.')');
}
}
// Filter by Visibility.
$_visibility = $this->getState('filter.visibility');
if (is_numeric($_visibility))
{
if (is_float($_visibility))
{
$query->where('a.visibility = ' . (float) $_visibility);
}
else
{
$query->where('a.visibility = ' . (int) $_visibility);
}
}
elseif (StringHelper::check($_visibility))
{
$query->where('a.visibility = ' . $db->quote($db->escape($_visibility)));
}
// Filter by Extension_type.
$_extension_type = $this->getState('filter.extension_type');
if (is_numeric($_extension_type))
{
if (is_float($_extension_type))
{
$query->where('a.extension_type = ' . (float) $_extension_type);
}
else
{
$query->where('a.extension_type = ' . (int) $_extension_type);
}
}
elseif (StringHelper::check($_extension_type))
{
$query->where('a.extension_type = ' . $db->quote($db->escape($_extension_type)));
}
// Add the list ordering clause.
$orderCol = $this->getState('list.ordering', 'a.name');
$orderDirn = $this->getState('list.direction', 'desc');
if ($orderCol != '')
{
// Check that the order direction is valid encase we have a field called direction as part of filers.
$orderDirn = (is_string($orderDirn) && in_array(strtolower($orderDirn), ['asc', 'desc'])) ? $orderDirn : 'desc';
$query->order($db->escape($orderCol . ' ' . $orderDirn));
}
return $query;
}
/**
* Method to get a store id based on model configuration state.
*
* @return string A store id.
* @since 1.6
*/
protected function getStoreId($id = '')
{
// Compile the store id.
$id .= ':' . $this->getState('filter.id');
$id .= ':' . $this->getState('filter.search');
$id .= ':' . $this->getState('filter.published');
// Check if the value is an array
$_access = $this->getState('filter.access');
if (UtilitiesArrayHelper::check($_access))
{
$id .= ':' . implode(':', $_access);
}
// Check if this is only an number or string
elseif (is_numeric($_access)
|| StringHelper::check($_access))
{
$id .= ':' . $_access;
}
$id .= ':' . $this->getState('filter.ordering');
$id .= ':' . $this->getState('filter.created_by');
$id .= ':' . $this->getState('filter.modified_by');
$id .= ':' . $this->getState('filter.visibility');
$id .= ':' . $this->getState('filter.extension_type');
$id .= ':' . $this->getState('filter.name');
return parent::getStoreId($id);
}
/**
* Method to get the styles that have to be included on the view
*
* @return array styles files
* @since 4.3
*/
public function getStyles(): array
{
return $this->styles;
}
/**
* Method to set the styles that have to be included on the view
*
* @return void
* @since 4.3
*/
public function setStyles(string $path): void
{
$this->styles[] = $path;
}
/**
* Method to get the script that have to be included on the view
*
* @return array script files
* @since 4.3
*/
public function getScripts(): array
{
return $this->scripts;
}
/**
* Method to set the script that have to be included on the view
*
* @return void
* @since 4.3
*/
public function setScript(string $path): void
{
$this->scripts[] = $path;
}
/**
* Build an SQL query to checkin all items left checked out longer then a set time.
*
* @return bool
* @since 3.2.0
*/
protected function checkInNow(): bool
{
// Get set check in time
$time = ComponentHelper::getParams('com_componentbuilder')->get('check_in');
if ($time)
{
// Get a db connection.
$db = $this->getDatabase();
// Reset query.
$query = $db->getQuery(true);
$query->select('*');
$query->from($db->quoteName('#__componentbuilder_class_method'));
// Only select items that are checked out.
$query->where($db->quoteName('checked_out') . '!=0');
$db->setQuery($query, 0, 1);
$db->execute();
if ($db->getNumRows())
{
// Get Yesterdays date.
$date = Factory::getDate()->modify($time)->toSql();
// Reset query.
$query = $db->getQuery(true);
// Fields to update.
$fields = array(
$db->quoteName('checked_out_time') . '=\'0000-00-00 00:00:00\'',
$db->quoteName('checked_out') . '=0'
);
// Conditions for which records should be updated.
$conditions = array(
$db->quoteName('checked_out') . '!=0',
$db->quoteName('checked_out_time') . '<\''.$date.'\''
);
// Check table.
$query->update($db->quoteName('#__componentbuilder_class_method'))->set($fields)->where($conditions);
$db->setQuery($query);
return $db->execute();
}
}
return false;
}
}