%PDF- %PDF-
| Direktori : /home1/lightco1/www/administrator/components/com_jmap/models/ |
| Current File : //home1/lightco1/www/administrator/components/com_jmap/models/wizard.php |
<?php
// namespace administrator\components\com_jmap\models;
/**
* @package JMAP::WIZARD::administrator::components::com_jmap
* @subpackage models
* @author Joomla! Extensions Store
* @copyright (C) 2015 - Joomla! Extensions Store
* @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html
*/
defined('_JEXEC') or die('Restricted access');
jimport('joomla.filesystem.file');
/**
* Wizard model responsibilities
*
* @package JMAP::WIZARD::administrator::components::com_jmap
* @subpackage models
* @since 2.0
*/
interface IJMapModelWizard {
/**
* Main get data method
*
* @access public
* @return Object[]
*/
public function getData($path = null);
/**
* Creational method for extensions data source
*
* @access public
* @return Void It doesn't require a return value because called by ajax and manage exceptions app queue
*/
public function createEntityProcess();
/**
* Try to evaluate if any substitutions to perform is available for extension and data source
* chosen, if any perform it calling doSubstitutions, otherwise original string untouched is returned
*
* @access public
* @param string $sqlString
* @return array
*/
public function getSubstitutionsOnDemand($sqlString);
}
/**
* Wizard business logic to auto-create extensions data source <<testable_behavior>>
*
* @package JMAP::WIZARD::administrator::components::com_jmap
* @subpackage models
* @since 2.0
*/
class JMapModelWizard extends JMapModel implements IJMapModelWizard {
/**
* JSON manifest file path for target extension data source to create
*
* @access private
* @var string
*/
private $manifestFilePath;
/**
* Language tag code used for replacement of placeholders
*
* @access private
* @var string
*/
private $language;
/**
* Langtag code used for replacement of placeholders
*
* @access private
* @var string
*/
private $langtag;
/**
* Deserialized manifest object for specific extension wizard informations
*
* @access protected
* @var Object
*/
protected $manifestObject;
/**
* Name of detected extension to create data source for
*
* @access protected
* @var string
*/
protected $extension;
/**
* User array sorting service function
*
* @access private
* @param array $a
* @param array $b
* @return boolean
*/
private function cmp($a, $b) {
if ($a['dataSourceName'] == $b['dataSourceName']) {
return 0;
}
return ($a['dataSourceName'] < $b['dataSourceName']) ? -1 : 1;
}
/**
* Do replacement for placeholders on JSON manifest chunks for fields to inject into REQUEST
*
* @access protected
* @param Object $manifest
* @return void
*/
protected function doReplacement($manifest) {
// Check if substitutions are set on manifest object
if(property_exists($manifest, 'placeholders')) {
// Get manifest object source and detect if any placeholders to replace exists
if(!empty($manifest->placeholders)) {
// Iterate on object properties
foreach ($manifest->placeholders as $postfield=>$toReplace) {
// Do replacement in $manifest referenced object
if(!property_exists($manifest->postfields, $postfield)) {
throw new JMapException(JText::_('COM_JMAP_ERROR_NOPROPERTY_EXISTS_POSTFIELDS'), 'error');
}
// Do evaluate
if(!property_exists($this, $toReplace[1])) {
throw new JMapException(JText::_('COM_JMAP_ERROR_NOPROPERTY_EXISTS_MODELOBJECT'), 'error');
}
$evaluatedValue = $this->{$toReplace[1]};
// Do replace
$manifest->postfields->{$postfield} = str_ireplace($toReplace[0], $evaluatedValue, $manifest->postfields->{$postfield});
}
}
}
}
/**
* Do substitution for auto generated raw SQL query string placed in DB table field after creation process
* After substitute chunks in SQL query string for the table field perform an ORM table update
*
* @access protected
* @param string $sqlString
* @param Object $manifest
* @return string
*/
protected function doSubstitution($sqlString, $manifest) {
// Check if substitutions are set on manifest object
if(property_exists($manifest, 'substitutions')) {
// Check if is array and not empty
if(!empty($manifest->substitutions)) {
foreach ($manifest->substitutions as $substitution) {
$sqlString = str_ireplace($substitution[0], $substitution[1], $sqlString);
}
}
}
return $sqlString;
}
/**
* Load the JSON format manifest file from file system based on extension wizard configuration folder
* Once deserialized contents of manifest file it assigns object to $manifestObject local member property
*
* @access protected
* @param string $fileName
* @return Object
*/
protected function loadManifestFile($fileName) {
// Check if file exists and is valid manifest
if(!$fileName || !file_exists($fileName)) {
throw new JMapException(JText::_('COM_JMAP_ERROR_NOMANIFEST_FOUND'), 'error');
}
// Load the manifest serialized file and assign to local variable
$manifestContents = file_get_contents($fileName);
// Unserialize data and assign object data to local manifestObject property
$this->manifestObject = json_decode($manifestContents);
if(!$this->manifestObject) {
throw new JMapException(JText::_('COM_JMAP_ERROR_MANIFEST_FORMAT'), 'error');
}
// Return unserialized manifest object
return $this->manifestObject;
}
/**
* Inject from manifest file object array containing sqlquery_managed/postfields and params/querystringlinkparams properties
* into the global REQUEST array to imitate a standard POST to sources model from a user compiled form
*
* @access protected
* @param Object $manifest
* @return void
*/
protected function injectRequestField($manifest) {
// Inject fields into POST HTTP request
/**
* Mapping is:
* postfields = $this->requestArray[$this->requestName]['sqlquery_managed'][]
* querystringlinkparams = $this->requestArray[$this->requestName]['params'][]
*/
//Inject data source name first
$dataSourceUserfriendlyName = ucfirst(str_replace('_', ' ', $this->extension));
$this->requestArray[$this->requestName]['name'] = $dataSourceUserfriendlyName;
$this->requestArray[$this->requestName]['params']['datasource_extension'] = $this->extension;
// Missing required data to construct data source creation
if(!property_exists($manifest, 'postfields')) {
throw new JMapException(JText::_('COM_JMAP_ERROR_INVALID_MANIFEST_MISSING_POSTFIELDS'), 'error');
}
// Error in object syntax or not valid object syntax
if(!is_object($manifest->postfields)) {
throw new JMapException(JText::_('COM_JMAP_ERROR_INVALID_MANIFEST_OBJECT_POSTFIELDS'), 'error');
}
//Cycle and store postfields REQUIRED
foreach ($manifest->postfields as $fieldName=>$fieldValue) {
// Store in superglobal POST array
$this->requestArray[$this->requestName]['sqlquery_managed'][$fieldName] = $fieldValue;
}
//Cycle and store querystringlinkparams OPTIONAL
if(property_exists($manifest, 'querystringlinkparams')) {
// Error in object syntax or not valid object syntax
if(!is_object($manifest->querystringlinkparams)) {
throw new JMapException(JText::_('COM_JMAP_ERROR_INVALID_MANIFEST_OBJECT_QSLINKPARAMS'), 'error');
}
foreach ($manifest->querystringlinkparams as $fieldName=>$fieldValue) {
// Store in superglobal POST array
$this->requestArray[$this->requestName]['params'][$fieldName] = $fieldValue;
}
}
}
/**
* Try to evaluate if any substitutions to perform is available for extension and data source
* chosen, if any perform it calling doSubstitutions, otherwise original string untouched is returned
*
* @access public
* @param string $sqlString
* @return array
*/
public function getSubstitutionsOnDemand($sqlString) {
// Load manifest file
$this->manifestFilePath = JPATH_COMPONENT . '/images/wizard/' . $this->extension . '/manifest.json';
// Manifest object could exists or not for specified data source extension
if(file_exists($this->manifestFilePath)) {
// Load the manifest serialized file and assign to local variable
$manifestContents = file_get_contents($this->manifestFilePath);
// Unserialize data and assign object data to local manifestObject property
$this->manifestObject = json_decode($manifestContents);
$sqlString = $this->doSubstitution($sqlString, $this->manifestObject);
}
return $sqlString;
}
/**
* Main get data method that retrieve and array containing informations to build up a graphic interface
* for supported extensions data source creational types both with extension name and icon
* It makes a directory listings for supported extensions returning array for data source entity name
* and data source entity icon found
*
* @access public
* @param string $path Inject the path where are placed subfolders for supported data source entities
* @return array
*/
public function getData($path = null) {
// Init extensions discovery array
$discoveredExtensions = array();
try {
if(!$path || !is_dir($path)) {
throw new JMapException(JText::_('COM_JMAP_EMPTY_ERROR_PATH'), 'error');
}
if(!class_exists('DirectoryIterator')) {
throw new JMapException(JText::_('COM_JMAP_SPL_LIBRARY_NOTFOUND_OLDPHPVERSION'), 'error');
}
// Discover supported extensions data sources, get available subfolders and assigned names primary key
$iterator = new DirectoryIterator($path);
foreach ($iterator as $subfolder) {
// get only directory and not dotted
if($subfolder->isDir() && !$subfolder->isDot()) {
$folderName = $subfolder->getFilename();
$innerPath = $path . '/' . $folderName . '/';
// Check if valid folder name, not to contains spaces or extra characters
if(!preg_match('/[^0-9A-Za-z_]/', $folderName)) {
$innerPath = $path . '/' . $folderName . '/';
// Try first method that relies on glob if not disabled by safe mode
if(function_exists('glob')) {
$extensionFileName = @array_pop(glob($innerPath . "*.txt"));
$extensionEffectiveName = str_replace($innerPath, '', $extensionFileName);
$extensionEffectiveName = str_replace('.txt', '', $extensionEffectiveName);
$discoveredExtensions[] = array('dataSourceName'=>$folderName, 'extensionName'=>$extensionEffectiveName);
} else {
// Do all scan with SPL libraries
$subIterator = new DirectoryIterator($innerPath);
foreach ($subIterator as $file) {
$subFileName = $file->getFilename();
if(preg_match('/.*\.txt/i', $subFileName)) {
$extensionFileName = $subFileName;
$extensionEffectiveName = str_replace($innerPath, '', $extensionFileName);
$extensionEffectiveName = str_replace('.txt', '', $extensionEffectiveName);
$discoveredExtensions[] = array('dataSourceName'=>$folderName, 'extensionName'=>$extensionEffectiveName);
}
}
}
}
}
}
// Natural sorting array
if(!empty($discoveredExtensions)) {
uasort($discoveredExtensions, array($this, 'cmp'));
}
} catch (JMapException $e) {
$this->app->enqueueMessage($e->getMessage(), $e->getErrorLevel());
}
// Return discovered extensions array
return $discoveredExtensions;
}
/**
* Main get data method that retrieve and array containing informations to build up a graphic interface
* for supported extensions data source creational types both with extension name and icon
*
* @access public
* @return boolean
*/
public function createEntityProcess() {
// Start creating process for data source
try {
// Load manifest file
$this->manifestFilePath = JPATH_COMPONENT . '/images/wizard/' . $this->extension . '/manifest.json';
$this->loadManifestFile($this->manifestFilePath);
// Do replacement if any
$this->doReplacement($this->manifestObject);
// Inject request field into REQUEST
$this->injectRequestField($this->manifestObject);
// Call data source creation model
$createdDataSourceTable = $this->sourcesModel->storeEntity(true, true);
// Do substitutions on generated raw query if any....
$sqlString = $createdDataSourceTable->sqlquery;
$createdDataSourceTable->sqlquery = $this->doSubstitution($sqlString, $this->manifestObject);
// ....finally update $createdDataSourceTable with new sqlquery if changed by substitutions
if($sqlString != $createdDataSourceTable->sqlquery) {
if (! $createdDataSourceTable->store (false)) {
throw new JMapException($createdDataSourceTable->getError (), 'error');
}
}
} catch (JMapException $e) {
$this->setError($e);
return false;
} catch(Exception $e) {
$jmapException = new JMapException($e->getMessage(), 'error');
$this->setError($jmapException);
return false;
}
return true;
}
/**
/* Class constructor
*
* @access public
* @param $config array
* @return Object&
*/
public function __construct(array $config = array()) {
parent::__construct($config);
$langParams = JComponentHelper::getParams('com_languages');
$this->langtag = $langParams->get('site');
// Setup predefined site language for placeholders replacement according to RFC 3066 and Virtuemart tables
$this->language = str_replace('-', '_', strtolower($this->langtag));
if(!empty($config)) {
$this->extension = $config['extension'];
$this->sourcesModel = $config['sourcesModel'];
}
}
}