first commit
This commit is contained in:
39
plugins/system/nrframework/NRFramework/Helpers/CSS.php
Normal file
39
plugins/system/nrframework/NRFramework/Helpers/CSS.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2022 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class CSS
|
||||
{
|
||||
/**
|
||||
* Transforms an array of CSS variables (key, value) to
|
||||
* a CSS output.
|
||||
*
|
||||
* @param array $cssVars
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function cssVarsToString($cssVars, $namespace)
|
||||
{
|
||||
$output = '';
|
||||
|
||||
foreach (array_filter($cssVars) as $key => $value)
|
||||
{
|
||||
$output .= '--' . $key . ': ' . $value . ';' . "\n";
|
||||
}
|
||||
|
||||
return $namespace . ' {
|
||||
' . $output . '
|
||||
}
|
||||
';
|
||||
}
|
||||
}
|
||||
29
plugins/system/nrframework/NRFramework/Helpers/CURL.php
Normal file
29
plugins/system/nrframework/NRFramework/Helpers/CURL.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2022 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class CURL
|
||||
{
|
||||
/**
|
||||
* Executes a GET cURL request.
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function exec($url)
|
||||
{
|
||||
$response = \JHttpFactory::getHttp()->get($url);
|
||||
|
||||
return $response->body;
|
||||
}
|
||||
}
|
||||
173
plugins/system/nrframework/NRFramework/Helpers/ChainedFields.php
Normal file
173
plugins/system/nrframework/NRFramework/Helpers/ChainedFields.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2021 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class ChainedFields
|
||||
{
|
||||
/**
|
||||
* Loads a combined array of the inputs and choices of the CSV file.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $data_source
|
||||
* @param string $separator
|
||||
* @param string $id_prefix
|
||||
* @param string $name_prefix
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function loadCSV($input, $data_source = 'custom', $separator = ',', $id_prefix = '', $name_prefix = '')
|
||||
{
|
||||
if (!$separator)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($data_source === 'csv_file')
|
||||
{
|
||||
if (!file_exists($input))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!$input = file_get_contents($input))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
if (!$data = self::getData($input, $separator, $id_prefix, $name_prefix))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the given data and returns the inputs and choices.
|
||||
*
|
||||
* @param string $data
|
||||
* @param string $separator
|
||||
* @param string $id_prefix
|
||||
* @param string $name_prefix
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getData($data = '', $separator = ',', $id_prefix = '', $name_prefix = '')
|
||||
{
|
||||
if (!$data || !is_string($data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$rows = explode(PHP_EOL, $data))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$choices = [];
|
||||
$inputs = [];
|
||||
|
||||
foreach ($rows as $row)
|
||||
{
|
||||
$row = explode($separator, $row);
|
||||
|
||||
$row = array_filter($row, 'strlen');
|
||||
|
||||
// if an empty row was found, skip it
|
||||
if (empty($row))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (empty($inputs))
|
||||
{
|
||||
$i = 1;
|
||||
|
||||
foreach ($row as $index => $item)
|
||||
{
|
||||
if ($i % 10 == 0)
|
||||
{
|
||||
$i++;
|
||||
}
|
||||
|
||||
$inputs[] = [
|
||||
'id' => $id_prefix . $i,
|
||||
'name' => $name_prefix . '[' . $i . ']',
|
||||
'label' => $item,
|
||||
];
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$parent = null;
|
||||
|
||||
foreach($row as $item)
|
||||
{
|
||||
if ($parent === null)
|
||||
{
|
||||
$parent = &$choices;
|
||||
}
|
||||
|
||||
if (!isset($parent[$item]))
|
||||
{
|
||||
$item = trim($item);
|
||||
|
||||
$parent[$item] = [
|
||||
'text' => $item,
|
||||
'value' => $item,
|
||||
'isSelected' => false,
|
||||
'choices' => []
|
||||
];
|
||||
}
|
||||
|
||||
$parent = &$parent[$item]['choices'];
|
||||
}
|
||||
}
|
||||
|
||||
self::array_values_recursive($choices);
|
||||
|
||||
if (!isset($inputs) || !isset($choices))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return compact('inputs', 'choices');
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array to using as key an index value instead of a alphanumeric.
|
||||
*
|
||||
* @param array $choices
|
||||
* @param string $property
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function array_values_recursive(&$choices, $property = 'choices')
|
||||
{
|
||||
$choices = array_values($choices);
|
||||
|
||||
for($i = 0; $i <= count($choices); $i++)
|
||||
{
|
||||
if(empty($choices[$i][$property]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$choices[$i][$property] = self::array_values_recursive($choices[$i][$property], $property);
|
||||
}
|
||||
|
||||
return $choices;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2022 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers\Controls;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class BorderRadius extends Spacing
|
||||
{
|
||||
/**
|
||||
* Border Radius Spacing Control Positions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $spacing_positions = ['top_left', 'top_right', 'bottom_right', 'bottom_left'];
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2022 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers\Controls;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class Responsive
|
||||
{
|
||||
/**
|
||||
* Responsive breakpoints
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $breakpoints = [
|
||||
'desktop',
|
||||
'tablet',
|
||||
'mobile'
|
||||
];
|
||||
|
||||
/**
|
||||
* Given a responsive value, we prepare its CSS for each breakpoint.
|
||||
*
|
||||
* @param array $value
|
||||
* @param string $prefix
|
||||
* @param string $unit
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getResponsiveControlValue($value, $prefix = '', $unit = '')
|
||||
{
|
||||
if (!is_string($unit))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_string($prefix) || empty($prefix))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($value) && $value === '')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($value))
|
||||
{
|
||||
$value = self::prepareResponsiveControlValue($value);
|
||||
}
|
||||
|
||||
$css = [];
|
||||
|
||||
foreach ($value as $breakpoint => $_value)
|
||||
{
|
||||
if ($_value === '' || is_null($_value))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$css[$breakpoint] = $_value;
|
||||
}
|
||||
|
||||
if (empty($css))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* All values are duplicates, return the current breakpoint value.
|
||||
*
|
||||
* if given [5, 5, 5, 5] to print the margin in pixels, do not return `margin: 5px 5px 5px 5px`.
|
||||
* Rather return `margin: 5px`
|
||||
*/
|
||||
if (count(array_unique($css)) === 1)
|
||||
{
|
||||
$first_element = reset($css);
|
||||
|
||||
if (is_array($first_element) || is_object($first_element))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return [key($css) => $prefix . ': ' . $first_element . $unit . ';'];
|
||||
}
|
||||
|
||||
// add unit suffix
|
||||
$css = preg_filter('/^/', $prefix . ': ', $css);
|
||||
$css = preg_filter('/$/', $unit . ';', $css);
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the value
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function prepareResponsiveControlValue($value)
|
||||
{
|
||||
if (!$value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($value))
|
||||
{
|
||||
return [
|
||||
'desktop' => $value
|
||||
];
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2022 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers\Controls;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class Spacing
|
||||
{
|
||||
/**
|
||||
* Default Spacing Control Positions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $spacing_positions = ['top', 'right', 'bottom', 'left'];
|
||||
|
||||
/**
|
||||
* Returns the CSS of the spacing control.
|
||||
*
|
||||
* @param array $value
|
||||
* @param string $prefix
|
||||
* @param string $breakpoint
|
||||
* @param string $unit
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getResponsiveSpacingControlValue($value, $prefix = '', $unit = '', $breakpoint = '')
|
||||
{
|
||||
$value = self::prepareSpacingControlValue($value, 'desktop');
|
||||
|
||||
if (is_null($value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Return the value for a specific breakpoint
|
||||
if (!empty($breakpoint) && is_string($breakpoint))
|
||||
{
|
||||
if (!isset($value[$breakpoint]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($value[$breakpoint]) && (string) $value[$breakpoint] !== '0')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return $prefix . ': ' . self::getSpacingValue($value[$breakpoint], $unit) . ';';
|
||||
}
|
||||
|
||||
// Return the value for all breakpoints
|
||||
$css = [];
|
||||
|
||||
foreach ($value as $_breakpoint => $values)
|
||||
{
|
||||
// remove linked property
|
||||
if (isset($values['linked']))
|
||||
{
|
||||
unset($values['linked']);
|
||||
}
|
||||
|
||||
if (!$value = self::getSpacingValue($values, $unit))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$css[$_breakpoint] = $prefix . ': ' . $value . ';';
|
||||
}
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the value
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string $breakpoint
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function prepareSpacingControlValue($value, $breakpoint = 'desktop')
|
||||
{
|
||||
if (is_null($value))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_array($value))
|
||||
{
|
||||
$new_value = [];
|
||||
foreach (static::$spacing_positions as $pos)
|
||||
{
|
||||
$new_value[$pos] = $value;
|
||||
}
|
||||
|
||||
if (!empty($breakpoint) && is_string($breakpoint))
|
||||
{
|
||||
return [
|
||||
$breakpoint => $new_value
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
return $new_value;
|
||||
}
|
||||
}
|
||||
|
||||
// If no breakpoint exists in the given value, set it to the given $breakpoint.
|
||||
if ((!isset($value['desktop']) && !isset($value['tablet']) && !isset($value['mobile'])) && ($breakpoint && !isset($value[$breakpoint])))
|
||||
{
|
||||
return [$breakpoint => $value];
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a spacing control (margin, padding).
|
||||
*
|
||||
* @param array $value
|
||||
* @param string $unit
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getSpacingValue($value, $unit = '')
|
||||
{
|
||||
if (!is_string($unit))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_string($value) && $value === '')
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$value || !is_array($value))
|
||||
{
|
||||
$value = self::prepareSpacingControlValue($value, false);
|
||||
}
|
||||
|
||||
// If its a multi-dimensional array, return
|
||||
if (count($value) !== count($value, COUNT_RECURSIVE))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// If all values are empty, return
|
||||
if (empty(array_filter($value, 'strlen')))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (\Exception $ex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$return = [];
|
||||
|
||||
foreach (static::$spacing_positions as $pos)
|
||||
{
|
||||
$return[$pos] = isset($value[$pos]) && $value[$pos] !== '' ? $value[$pos] : 0;
|
||||
}
|
||||
|
||||
if (empty($return))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* All values are duplicates, return only 1 number with their unit.
|
||||
*
|
||||
* Example: Given [5, 5, 5, 5] to print the margin in pixels, do not return `margin: 5px 5px 5px 5px`.
|
||||
* Rather return `margin: 5px`
|
||||
*/
|
||||
if (count(array_unique($return)) === 1)
|
||||
{
|
||||
$value = reset($return);
|
||||
$suffix = \NRFramework\Functions::endsWith($value, $unit) ? '' : $unit;
|
||||
return $value . $suffix;
|
||||
}
|
||||
|
||||
// add unit suffix if needed
|
||||
$data = [];
|
||||
foreach ($return as $key => $value)
|
||||
{
|
||||
$suffix = \NRFramework\Functions::endsWith($value, $unit) ? '' : $unit;
|
||||
$data[] = $value . $suffix;
|
||||
}
|
||||
|
||||
return implode(' ', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the spacing value is empty.
|
||||
*
|
||||
* @param array $value
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function isEmpty($value)
|
||||
{
|
||||
if (!is_array($value))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (static::$spacing_positions as $pos)
|
||||
{
|
||||
if (!isset($value[$pos]) || (empty($value[$pos]) && (string) $value[$pos] !== '0'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2022 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class CustomField
|
||||
{
|
||||
/**
|
||||
* Get a custom field's data.
|
||||
*
|
||||
* @param integer $value
|
||||
* @param string $selector
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public static function getData($value, $selector = 'id')
|
||||
{
|
||||
if (!$value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$db = \JFactory::getDbo();
|
||||
|
||||
$query = $db->getQuery(true);
|
||||
|
||||
$query
|
||||
->select($db->quoteName(['fieldparams']))
|
||||
->from($db->quoteName('#__fields'))
|
||||
->where($db->quoteName($selector) . ' = ' . $db->quote($value))
|
||||
->where($db->quoteName('state') . ' = 1');
|
||||
|
||||
$db->setQuery($query);
|
||||
|
||||
if (!$result = $db->loadResult())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return new \Joomla\Registry\Registry($result);
|
||||
}
|
||||
}
|
||||
41
plugins/system/nrframework/NRFramework/Helpers/License.php
Normal file
41
plugins/system/nrframework/NRFramework/Helpers/License.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2022 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class License
|
||||
{
|
||||
/**
|
||||
* Returns the remote license data from the server for the given download key.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getRemoteLicenseData($download_key = null)
|
||||
{
|
||||
if (!$download_key)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// License Check Endpoint
|
||||
$url = TF_CHECK_LICENSE;
|
||||
// Set Download Key
|
||||
$url = str_replace('{{DOWNLOAD_KEY}}', $download_key, $url);
|
||||
|
||||
// No response, abort
|
||||
if (!$response = CURL::exec($url))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return json_decode($response, true);
|
||||
}
|
||||
}
|
||||
132
plugins/system/nrframework/NRFramework/Helpers/Responsive.php
Normal file
132
plugins/system/nrframework/NRFramework/Helpers/Responsive.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2022 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
class Responsive
|
||||
{
|
||||
/**
|
||||
* Renders the given CSS.
|
||||
*
|
||||
* @param array $css
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function renderResponsiveCSS($css, $namespace = '')
|
||||
{
|
||||
$output = '';
|
||||
|
||||
foreach (Controls\Responsive::$breakpoints as $breakpoint)
|
||||
{
|
||||
if (!isset($css[$breakpoint]) || empty($css[$breakpoint]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we were given an array of strings of CSS, transform them to a string so we can output it.
|
||||
*
|
||||
* i.e. transform
|
||||
* [
|
||||
* 'color: #fff;',
|
||||
* 'background: #000;'
|
||||
* ]
|
||||
*
|
||||
* to:
|
||||
*
|
||||
* 'color: #fff;background: #000;'
|
||||
*/
|
||||
if (!is_string($css[$breakpoint]))
|
||||
{
|
||||
$css[$breakpoint] = implode(' ', $css[$breakpoint]);
|
||||
}
|
||||
|
||||
$function = 'get' . ucfirst($breakpoint) . 'Output';
|
||||
$output .= self::$function($css[$breakpoint], $namespace);
|
||||
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the desktop CSS.
|
||||
*
|
||||
* @param string $css
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getDesktopOutput($css, $namespace)
|
||||
{
|
||||
return self::getGenericTemplate($css, '', $namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tablet CSS.
|
||||
*
|
||||
* @param string $css
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getTabletOutput($css, $namespace)
|
||||
{
|
||||
return self::getGenericTemplate($css, '(max-width: 991px)', $namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mobile CSS.
|
||||
*
|
||||
* @param string $css
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getMobileOutput($css, $namespace)
|
||||
{
|
||||
return self::getGenericTemplate($css, '(max-width: 575px)', $namespace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the responsive output of a specific media query size.
|
||||
*
|
||||
* @param string $css
|
||||
* @param string $size
|
||||
* @param string $namespace
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getGenericTemplate($css, $size = '', $namespace = '')
|
||||
{
|
||||
if (!is_string($css) || !is_string($size) || !is_string($namespace))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
$namespace_prefix = $namespace_suffix = $size_prefix = $size_suffix = '';
|
||||
|
||||
if (!empty($size))
|
||||
{
|
||||
$size_prefix = '@media screen and ' . $size . ' { ';
|
||||
$size_suffix = ' }';
|
||||
}
|
||||
|
||||
if (!empty($namespace))
|
||||
{
|
||||
$namespace_prefix = $namespace . ' { ';
|
||||
$namespace_suffix = ' }';
|
||||
}
|
||||
|
||||
return $size_prefix . $namespace_prefix . $css . $namespace_suffix . $size_suffix;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,572 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2021 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers\Widgets;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use NRFramework\Mimes;
|
||||
|
||||
class Gallery
|
||||
{
|
||||
/**
|
||||
* Stores all gallery parsed directories info txt file `*.gallery_info.txt` data in format:
|
||||
* GALLERY DIRECTORY => ARRAY OF `*.gallery_info.txt` file data
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static $gallery_directories_info_file = [];
|
||||
|
||||
/**
|
||||
* Stores all galleries info file names in format:
|
||||
*
|
||||
* GALLERY DIRECTORY => INFO FILE NAME
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
static $gallery_directories_info_file_names = [];
|
||||
|
||||
/**
|
||||
* The directory information file holding all gallery item details.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const directory_gallery_info_file = 'gallery_info.txt';
|
||||
|
||||
/**
|
||||
* Parses the given gallery items.
|
||||
*
|
||||
* @param mixed $input A string to a directory/path/URL or an array of a URL item containing its information.
|
||||
* @param array $allowed_file_types The allowed file types.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function parseGalleryItems($input, $allowed_file_types = [])
|
||||
{
|
||||
if (is_string($input))
|
||||
{
|
||||
$fullpath_input = JPATH_ROOT . DIRECTORY_SEPARATOR . ltrim($input, DIRECTORY_SEPARATOR);
|
||||
|
||||
// Parse Directory
|
||||
if (is_dir($fullpath_input))
|
||||
{
|
||||
return self::parseDirectory($fullpath_input, $allowed_file_types);
|
||||
}
|
||||
|
||||
// Skip invalid URLs
|
||||
if ($url = self::parseURL($input))
|
||||
{
|
||||
return [$url];
|
||||
}
|
||||
|
||||
// Parse Image
|
||||
if ($image_data = self::parseImage($fullpath_input, $allowed_file_types))
|
||||
{
|
||||
return [$image_data];
|
||||
}
|
||||
}
|
||||
|
||||
return [self::parseURL($input)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the directory by finding all of its images and their information.
|
||||
*
|
||||
* @param string $dir
|
||||
* @param array $allowed_file_types
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function parseDirectory($dir, $allowed_file_types = [])
|
||||
{
|
||||
if (!is_string($dir) || !is_dir($dir) || empty($allowed_file_types))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
// Get images
|
||||
$files = array_diff(scandir($dir), ['.', '..', '.DS_Store']);
|
||||
|
||||
foreach ($files as $key => $filename)
|
||||
{
|
||||
// Skip directories
|
||||
if (is_dir($dir . DIRECTORY_SEPARATOR . $filename))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$image_path = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $filename;
|
||||
|
||||
if (!$image_data = self::parseImage($image_path, $allowed_file_types))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$items[] = $image_data;
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the directory image and return its information.
|
||||
*
|
||||
* @param string $image_path
|
||||
* @param string $allowed_file_types
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function parseImage($image_path, $allowed_file_types = null)
|
||||
{
|
||||
if (!is_string($image_path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$data = [
|
||||
'path' => $image_path,
|
||||
'url' => self::directoryImageToURL($image_path)
|
||||
];
|
||||
|
||||
if (!is_file($image_path))
|
||||
{
|
||||
return array_merge($data, [
|
||||
'invalid' => true
|
||||
]);
|
||||
}
|
||||
|
||||
// Skip not allowed file types
|
||||
if (!is_null($allowed_file_types) && !Mimes::check($allowed_file_types, Mimes::detectFileType($image_path)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there is a `*.gallery_info.txt` helper file and get any information about the image
|
||||
$gallery_info_file_data = self::getGalleryInfoFileData(dirname($image_path));
|
||||
if (!$gallery_info_file_data)
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
$image_filename = pathinfo($image_path, PATHINFO_BASENAME);
|
||||
|
||||
// If no information from the text field about this image was found, stop
|
||||
if (!isset($gallery_info_file_data[$image_filename]))
|
||||
{
|
||||
return $data;
|
||||
}
|
||||
|
||||
$image_data = $gallery_info_file_data[$image_filename];
|
||||
|
||||
return array_merge($data, [
|
||||
'caption' => isset($image_data['caption']) ? $image_data['caption'] : ''
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a single URL either as a String or as an Array.
|
||||
*
|
||||
* @param mixed $item
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function parseURL($item)
|
||||
{
|
||||
// URL is a string
|
||||
if (is_string($item))
|
||||
{
|
||||
if (!filter_var($item, FILTER_VALIDATE_URL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return [
|
||||
'url' => $item
|
||||
];
|
||||
}
|
||||
|
||||
// URL is an array
|
||||
if (!is_array($item) || !count($item))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If a thumbnail URL is given but no URL, use it as the full image URL
|
||||
if (isset($item['thumbnail_url']) && !isset($item['url']))
|
||||
{
|
||||
$item['url'] = $item['thumbnail_url'];
|
||||
}
|
||||
|
||||
if (!isset($item['url']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!filter_var($item['url'], FILTER_VALIDATE_URL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a module by its ID.
|
||||
*
|
||||
* @param string $id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function loadModule($id)
|
||||
{
|
||||
$module = \JModuleHelper::getModuleById($id);
|
||||
$params = ['style' => 'none'];
|
||||
|
||||
return $module->id > 0 ? \JFactory::getDocument()->loadRenderer('module')->render($module, $params) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the `*.gallery_info.txt` file for the given directory.
|
||||
*
|
||||
* @param string $dir
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function getGalleryInfoFileData($dir)
|
||||
{
|
||||
if (isset(self::$gallery_directories_info_file[$dir]) && !empty(self::$gallery_directories_info_file[$dir]))
|
||||
{
|
||||
return self::$gallery_directories_info_file[$dir];
|
||||
}
|
||||
|
||||
if (!$file = self::findGalleryInfoFile($dir))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
// Read file
|
||||
if (!$handle = fopen($file, 'r'))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = [];
|
||||
|
||||
$line_defaults = ['', '', ''];
|
||||
|
||||
// Loop each line
|
||||
while (($line = fgets($handle)) !== false)
|
||||
{
|
||||
list($filename, $caption, $hash) = explode('|', $line) + $line_defaults;
|
||||
|
||||
// If no filename is given, continue
|
||||
if (!$filename)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$data[$filename] = [
|
||||
'filename' => $filename,
|
||||
'caption' => trim($caption),
|
||||
'hash' => trim($hash)
|
||||
];
|
||||
}
|
||||
|
||||
// Close file
|
||||
fclose($handle);
|
||||
|
||||
self::$gallery_directories_info_file[$dir] = $data;
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the source image and whether it has been edited.
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $destination_folder
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function findSourceImageDetails($source, $destination_folder)
|
||||
{
|
||||
$source_filename = pathinfo($source, PATHINFO_BASENAME);
|
||||
|
||||
$data = self::getGalleryInfoFileData(dirname($source));
|
||||
|
||||
$image_data = isset($data[$source_filename]) ? $data[$source_filename] : false;
|
||||
|
||||
if (!$image_data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($image_data['hash']))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$sourceHash = self::calculateFileHash($source);
|
||||
|
||||
return [
|
||||
'path' => $destination_folder . $image_data['filename'],
|
||||
'edited' => $image_data['hash'] !== $sourceHash
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates or Inserts the given image information from the gallery info file.
|
||||
*
|
||||
* @param string $source
|
||||
* @param array $image_data
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function updateImageDataInGalleryInfoFile($source, $image_data)
|
||||
{
|
||||
// Source directory
|
||||
$source_directory = dirname($source);
|
||||
|
||||
// Check whether the gallery info file exists, if not, create it
|
||||
if (!$file = self::findGalleryInfoFile($source_directory))
|
||||
{
|
||||
$file = self::createGalleryInfoFile($source_directory);
|
||||
}
|
||||
|
||||
// Open files
|
||||
$reading = fopen($file, 'r');
|
||||
$writing = fopen($file . '.tmp', 'w');
|
||||
|
||||
$replaced = false;
|
||||
|
||||
while (!feof($reading))
|
||||
{
|
||||
// Get each file line
|
||||
$line = fgets($reading);
|
||||
|
||||
// Remove new line at the end
|
||||
$line = trim(preg_replace('/\s\s+/', ' ', $line));
|
||||
|
||||
// Skip empty lines
|
||||
if (empty($line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
list($filename, $caption, $hash) = explode('|', $line) + ['', '', ''];
|
||||
|
||||
// We need to manipulate current file
|
||||
if (strtolower($filename) !== strtolower(basename($image_data['path'])))
|
||||
{
|
||||
fputs($writing, $line . "\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
$replaced = true;
|
||||
|
||||
$line = $filename . '|' . $caption . '|' . self::calculateFileHash($source) . "\n";;
|
||||
|
||||
// Write changed line
|
||||
fputs($writing, $line);
|
||||
}
|
||||
|
||||
// Close files
|
||||
fclose($reading);
|
||||
fclose($writing);
|
||||
|
||||
// If we replaced a line, update the text file
|
||||
if ($replaced)
|
||||
{
|
||||
rename($file . '.tmp', $file);
|
||||
}
|
||||
// No line was replaced, append image details
|
||||
else
|
||||
{
|
||||
unlink($file . '.tmp');
|
||||
|
||||
self::appendImageDataToGalleryInfoFile($file, $source, $image_data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the image from the gallery info file.
|
||||
*
|
||||
* @param string $source
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function removeImageFromGalleryInfoFile($source)
|
||||
{
|
||||
// Get the gallery info file from destination folder
|
||||
if (!$file = self::findGalleryInfoFile(dirname($source)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open files
|
||||
$reading = fopen($file, 'r');
|
||||
$writing = fopen($file . '.tmp', 'w');
|
||||
|
||||
$found = false;
|
||||
|
||||
while (!feof($reading))
|
||||
{
|
||||
// Get each file line
|
||||
$line = fgets($reading);
|
||||
|
||||
// Remove new line at the end
|
||||
$line = trim(preg_replace('/\s\s+/', ' ', $line));
|
||||
|
||||
// Skip empty lines
|
||||
if (empty($line))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
list($filename, $caption, $hash) = explode('|', $line) + ['', '', ''];
|
||||
|
||||
// We need to manipulate current file
|
||||
if ($filename !== pathinfo($source, PATHINFO_BASENAME))
|
||||
{
|
||||
$found = true;
|
||||
fputs($writing, $line . "\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Close files
|
||||
fclose($reading);
|
||||
fclose($writing);
|
||||
|
||||
if (!$found)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the changes
|
||||
rename($file . '.tmp', $file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the image data into the info file.
|
||||
*
|
||||
* @param string $dir
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function createGalleryInfoFile($dir)
|
||||
{
|
||||
$file = self::getLanguageInfoFileName($dir);
|
||||
|
||||
file_put_contents($file, '');
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the image data into the info file.
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $source
|
||||
* @param object $image_data
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function appendImageDataToGalleryInfoFile($file, $source, $image_data)
|
||||
{
|
||||
$caption = isset($image_data['caption']) ? $image_data['caption'] : '';
|
||||
|
||||
$hash = self::calculateFileHash($source);
|
||||
|
||||
$line = pathinfo($source, PATHINFO_BASENAME) . '|' . $caption . '|' . $hash . "\n";
|
||||
|
||||
file_put_contents($file, $line, FILE_APPEND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the `*.gallery_info.txt` file if it exists in the given directory.
|
||||
*
|
||||
* @param string $dir
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function findGalleryInfoFile($dir)
|
||||
{
|
||||
if (isset(self::$gallery_directories_info_file_names[$dir]))
|
||||
{
|
||||
return self::$gallery_directories_info_file_names[$dir];
|
||||
}
|
||||
|
||||
// Method 1: With language prefix
|
||||
$file = self::getLanguageInfoFileName($dir);
|
||||
|
||||
// Check if the file exists
|
||||
if (file_exists($file))
|
||||
{
|
||||
self::$gallery_directories_info_file_names[$dir] = $file;
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
// Method 2: Without the language prefix
|
||||
$file = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . self::directory_gallery_info_file;
|
||||
|
||||
// Check if the file exists
|
||||
if (file_exists($file))
|
||||
{
|
||||
self::$gallery_directories_info_file_names[$dir] = $file;
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the info file with the language prefix.
|
||||
*
|
||||
* @param string $dir
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getLanguageInfoFileName($dir)
|
||||
{
|
||||
return rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . \JFactory::getLanguage()->getTag() . '.' . self::directory_gallery_info_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the file hash of a file.
|
||||
*
|
||||
* Hash = md5(file path + last modified date of file)
|
||||
*
|
||||
* @param string $file_path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function calculateFileHash($file_path)
|
||||
{
|
||||
return md5($file_path . filemtime($file_path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an image path to a URL.
|
||||
*
|
||||
* @param string $image_path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function directoryImageToURL($image_path)
|
||||
{
|
||||
return rtrim(\JURI::root(), DIRECTORY_SEPARATOR) . mb_substr($image_path, strlen(JPATH_BASE), null);;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,349 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos Marinos <info@tassos.gr>
|
||||
* @link http://www.tassos.gr
|
||||
* @copyright Copyright © 2021 Tassos Marinos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Helpers\Widgets;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
jimport('joomla.filesystem.file');
|
||||
jimport('joomla.filesystem.folder');
|
||||
jimport('joomla.filesystem.path');
|
||||
|
||||
use NRFramework\File;
|
||||
use NRFramework\Image;
|
||||
|
||||
class GalleryManager
|
||||
{
|
||||
/**
|
||||
* Temp folder where images are uploaded
|
||||
* prior to them being saved in the final directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private static $temp_folder = 'media/acfgallery/tmp';
|
||||
|
||||
/**
|
||||
* How long the files can stay in the temp folder.
|
||||
*
|
||||
* After each save a clean up is run and all files older
|
||||
* than this value in days are removed.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $temp_files_cleanup_days = 1;
|
||||
|
||||
/**
|
||||
* Upload file
|
||||
*
|
||||
* @param array $file The request file as posted by form
|
||||
* @param string $upload_settings The upload settings
|
||||
* @param array $media_uploader_file_data Media uploader related file settings
|
||||
* @param array $resizeSettings The resize settings
|
||||
*
|
||||
* @return mixed String on success, Null on failure
|
||||
*/
|
||||
public static function upload($file, $upload_settings, $media_uploader_file_data, $resizeSettings)
|
||||
{
|
||||
$ds = DIRECTORY_SEPARATOR;
|
||||
|
||||
// The source file name
|
||||
$source = '';
|
||||
|
||||
// Move the image to the tmp folder
|
||||
try {
|
||||
$source = File::upload($file, self::getFullTempFolder(), $upload_settings['allowed_types'], $upload_settings['allow_unsafe']);
|
||||
} catch (\Throwable $th)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the file came from the Media Manager file and we are copying it, fix its filename
|
||||
if ($media_uploader_file_data['is_media_uploader_file'])
|
||||
{
|
||||
$media_uploader_file_data['media_uploader_filename'] = self::getFilePathFromMediaUploaderFile($media_uploader_file_data['media_uploader_filename']);
|
||||
}
|
||||
|
||||
// If we are copying the base image, copy it to the temp folder.
|
||||
if (!$source = File::move($source, $source, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check whether to copy and resize the original image
|
||||
if ($resizeSettings['original_image_resize'])
|
||||
{
|
||||
$source = Image::resizeAndKeepAspectRatio($source, $resizeSettings['original_image_resize_width'], $resizeSettings['original_image_resize_quality']);
|
||||
}
|
||||
|
||||
// Generate thumbnails
|
||||
if (!$thumb_data = self::generateThumbnail($source, $resizeSettings))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return [
|
||||
'filename' => implode($ds, [self::$temp_folder, $thumb_data['filename']]),
|
||||
'thumbnail' => implode($ds, [self::$temp_folder, $thumb_data['resized_filename']])
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves all given `tmp` items over to the destination folder.
|
||||
*
|
||||
* @param array $items
|
||||
* @param string $destination_folder
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function moveTempItemsToDestination(&$items, $destination_folder)
|
||||
{
|
||||
if (!$destination_folder)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Create destination folder if missing
|
||||
if (!File::createDirs($destination_folder))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$ds = DIRECTORY_SEPARATOR;
|
||||
|
||||
// Move all files from `tmp` folder over to the `upload folder`
|
||||
foreach ($items as $key => &$item)
|
||||
{
|
||||
/**
|
||||
* Skip invalid files.
|
||||
*
|
||||
* These "files" can appear when we try to move files
|
||||
* over to the destination folder when the gallery manager
|
||||
* is still working to upload queueed files.
|
||||
*
|
||||
* Also skip any items that have no value.
|
||||
*/
|
||||
if ($key === 'ITEM_ID' || empty($item['thumbnail']))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$moved = false;
|
||||
|
||||
// Ensure thumbnail in temp folder file exists
|
||||
$thumbnail_clean = pathinfo($item['thumbnail'], PATHINFO_BASENAME);
|
||||
$thumbnail_path = implode($ds, [JPATH_ROOT, $item['thumbnail']]);
|
||||
if (\NRFramework\Functions::startsWith($item['thumbnail'], self::$temp_folder) && file_exists($thumbnail_path))
|
||||
{
|
||||
// Move thumbnail
|
||||
$thumb = File::move($thumbnail_path, $destination_folder . $thumbnail_clean);
|
||||
|
||||
// Update thumbnail file name
|
||||
$item['thumbnail'] = pathinfo($thumb, PATHINFO_BASENAME);
|
||||
|
||||
$moved = true;
|
||||
}
|
||||
|
||||
// Check if we have uploaded the full image as well and set it
|
||||
$image_clean = pathinfo($item['image'], PATHINFO_BASENAME);
|
||||
$image_path = implode($ds, [JPATH_ROOT, $item['image']]);
|
||||
if (\NRFramework\Functions::startsWith($item['image'], self::$temp_folder) && file_exists($image_path))
|
||||
{
|
||||
// Move image
|
||||
$image = File::move($image_path, $destination_folder . $image_clean);
|
||||
|
||||
// Update image file name
|
||||
$item['image'] = pathinfo($image, PATHINFO_BASENAME);
|
||||
|
||||
$moved = true;
|
||||
}
|
||||
|
||||
if ($moved)
|
||||
{
|
||||
// Update destination path
|
||||
self::updateDestinationPath($item, $destination_folder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the destination path for the image and its thumbnail to the final destination folder.
|
||||
*
|
||||
* @param array $item
|
||||
* @param string $destination_folder
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function updateDestinationPath(&$item, $destination_folder)
|
||||
{
|
||||
$ds = DIRECTORY_SEPARATOR;
|
||||
|
||||
// Ensure destination folder is a relative path
|
||||
$destination_folder = ltrim(rtrim(str_replace(JPATH_ROOT, '', $destination_folder), $ds), $ds);
|
||||
|
||||
$item = array_merge($item, [
|
||||
'thumbnail' => implode($ds, [$destination_folder, $item['thumbnail']]),
|
||||
'image' => implode($ds, [$destination_folder, $item['image']])
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Media Uploader files look like: https://example.com/images/sampledata/parks/banner_cradle.png
|
||||
* We remove the first part (https://example.com/images/) and keep the other part (relative path to image).
|
||||
*
|
||||
* @param string $filename
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function getFilePathFromMediaUploaderFile($filename)
|
||||
{
|
||||
$filenameArray = explode('images/', $filename, 2);
|
||||
unset($filenameArray[0]);
|
||||
$new_filepath = join($filenameArray);
|
||||
return 'images/' . $new_filepath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates thumbnail
|
||||
*
|
||||
* @param string $source Source image path.
|
||||
* @param array $resizeSettings Resize Settings.
|
||||
* @param string $destination_folder Destination folder.
|
||||
* @param boolean $unique_filename Whether the thumbnails will have a unique filename.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function generateThumbnail($source, $resizeSettings, $destination_folder = null, $unique_filename = true)
|
||||
{
|
||||
$parts = pathinfo($source);
|
||||
$destination_folder = !is_null($destination_folder) ? $destination_folder : $parts['dirname'] . DIRECTORY_SEPARATOR;
|
||||
$destination = $destination_folder . $parts['filename'] . '_thumb.' . $parts['extension'];
|
||||
|
||||
/**
|
||||
* If height is zero, then we suppose we want to keep aspect ratio.
|
||||
*
|
||||
* Resize with width & height: If thumbnail height is not set
|
||||
* Resize and keep aspect ratio: If thumbnail height is set
|
||||
*/
|
||||
$resized_image = !is_null($resizeSettings['thumb_height']) && $resizeSettings['thumb_height'] !== '0'
|
||||
?
|
||||
Image::resize($source, $resizeSettings['thumb_width'], $resizeSettings['thumb_height'], $resizeSettings['thumb_resize_quality'], $resizeSettings['thumb_resize_method'], $destination, $unique_filename)
|
||||
:
|
||||
Image::resizeAndKeepAspectRatio($source, $resizeSettings['thumb_width'], $resizeSettings['thumb_resize_quality'], $destination, $unique_filename);
|
||||
|
||||
if (!$resized_image)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
return [
|
||||
'filename' => basename($source),
|
||||
'resized_filename' => basename($resized_image)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an uploaded file (resized original image and thumbnail).
|
||||
*
|
||||
* @param string $filepath The filepath
|
||||
* @param string $thumbnail The thumbnail filepath
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function deleteFile($filepath, $thumbnail)
|
||||
{
|
||||
if (empty($filepath))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return [
|
||||
'deleted_original_image' => self::findAndDeleteFile($filepath),
|
||||
'deleted_thumbnail' => self::findAndDeleteFile($thumbnail)
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the file.
|
||||
*
|
||||
* @param string $filepath
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function findAndDeleteFile($filepath)
|
||||
{
|
||||
$file = \JPath::clean(implode(DIRECTORY_SEPARATOR, [JPATH_ROOT, $filepath]));
|
||||
|
||||
return \JFile::exists($file) ? \JFile::delete($file) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans the temp folder.
|
||||
*
|
||||
* Removes any image that is 1 day or older.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clean()
|
||||
{
|
||||
$temp_folder = self::getFullTempFolder();
|
||||
|
||||
if (!is_dir($temp_folder))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get images
|
||||
$files = array_diff(scandir($temp_folder), ['.', '..', '.DS_Store', 'index.html']);
|
||||
|
||||
$found = [];
|
||||
|
||||
foreach ($files as $key => $filename)
|
||||
{
|
||||
$file_path = implode(DIRECTORY_SEPARATOR, [$temp_folder, $filename]);
|
||||
|
||||
// Skip directories
|
||||
if (is_dir($file_path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$diff_in_miliseconds = time() - filemtime($file_path);
|
||||
|
||||
// Skip the file if it's not old enough
|
||||
if ($diff_in_miliseconds < (60 * 60 * 24 * self::$temp_files_cleanup_days))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$found[] = $file_path;
|
||||
}
|
||||
|
||||
if (!$found)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete found old files
|
||||
foreach ($found as $file)
|
||||
{
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Full temp directory where images are uploaded
|
||||
* prior to them being saved in the final directory.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function getFullTempFolder()
|
||||
{
|
||||
return implode(DIRECTORY_SEPARATOR, [JPATH_ROOT, self::$temp_folder]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user