Upgrade to 3.0.2
This commit is contained in:
@@ -422,6 +422,10 @@ class App
|
||||
$id = dirname($path);
|
||||
$filename = basename($path);
|
||||
|
||||
if (is_a($parent, File::class) === true) {
|
||||
$parent = $parent->parent();
|
||||
}
|
||||
|
||||
if ($id === '.') {
|
||||
if ($file = $parent->file($filename)) {
|
||||
return $file;
|
||||
|
@@ -4,8 +4,115 @@ namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Toolkit\Properties;
|
||||
|
||||
/**
|
||||
* Anything in your public path can be converted
|
||||
* to an Asset object to use the same handy file
|
||||
* methods and thumbnail generation as for any other
|
||||
* Kirby files. Pass a relative path to the Asset
|
||||
* object to create the asset.
|
||||
*/
|
||||
class Asset
|
||||
{
|
||||
use FileFoundation;
|
||||
use FileModifications;
|
||||
use Properties;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* Creates a new Asset object
|
||||
* for the given path.
|
||||
*/
|
||||
public function __construct(string $path)
|
||||
{
|
||||
$this->setPath(dirname($path));
|
||||
$this->setRoot($this->kirby()->root('index') . '/' . $path);
|
||||
$this->setUrl($this->kirby()->url('index') . '/' . $path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alternative text for the asset
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function alt()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique id for the asset
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function id(): string
|
||||
{
|
||||
return $this->root();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a unique media hash
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mediaHash(): string
|
||||
{
|
||||
return crc32($this->filename()) . '-' . $this->modified();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative path starting at the media folder
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mediaPath(): string
|
||||
{
|
||||
return 'assets/' . $this->path() . '/' . $this->mediaHash() . '/' . $this->filename();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute path to the file in the public media folder
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mediaRoot(): string
|
||||
{
|
||||
return $this->kirby()->root('media') . '/' . $this->mediaPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute Url to the file in the public media folder
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mediaUrl(): string
|
||||
{
|
||||
return $this->kirby()->url('media') . '/' . $this->mediaPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the file from the web root,
|
||||
* excluding the filename
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function path(): string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the path
|
||||
*
|
||||
* @param string $path
|
||||
* @return self
|
||||
*/
|
||||
protected function setPath(string $path)
|
||||
{
|
||||
$this->path = $path === '.' ? '' : $path;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@@ -69,8 +69,8 @@ class Auth
|
||||
throw new InvalidArgumentException('Invalid authorization header');
|
||||
}
|
||||
|
||||
// only allow basic auth when https is enabled
|
||||
if ($request->ssl() === false) {
|
||||
// only allow basic auth when https is enabled or insecure requests permitted
|
||||
if ($request->ssl() === false && $this->kirby->option('api.allowInsecure', false) !== true) {
|
||||
throw new PermissionException('Basic authentication is only allowed over HTTPS');
|
||||
}
|
||||
|
||||
|
@@ -376,6 +376,10 @@ class Blueprint
|
||||
protected function normalizeColumns(string $tabName, array $columns): array
|
||||
{
|
||||
foreach ($columns as $columnKey => $columnProps) {
|
||||
if (is_array($columnProps) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$columnProps = $this->convertFieldsToSections($tabName . '-col-' . $columnKey, $columnProps);
|
||||
|
||||
// inject getting started info, if the sections are empty
|
||||
|
@@ -73,7 +73,7 @@ class Collection extends BaseCollection
|
||||
*/
|
||||
public function __set(string $id, $object)
|
||||
{
|
||||
$this->data[$object->id()] = $object;
|
||||
$this->data[$id] = $object;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,14 +81,16 @@ class Collection extends BaseCollection
|
||||
* an entire second collection to the
|
||||
* current collection
|
||||
*
|
||||
* @param mixed $item
|
||||
* @param mixed $object
|
||||
*/
|
||||
public function add($object)
|
||||
{
|
||||
if (is_a($object, static::class) === true) {
|
||||
$this->data = array_merge($this->data, $object->data);
|
||||
} else {
|
||||
} elseif (method_exists($object, 'id') === true) {
|
||||
$this->__set($object->id(), $object);
|
||||
} else {
|
||||
$this->append($object);
|
||||
}
|
||||
|
||||
return $this;
|
||||
|
@@ -165,6 +165,15 @@ class Field
|
||||
return $this->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Field::parent()
|
||||
* @return Page|File|Site|User
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return $this->parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a fallback if the field value is empty
|
||||
*
|
||||
|
@@ -29,6 +29,7 @@ class File extends ModelWithContent
|
||||
|
||||
use FileActions;
|
||||
use FileFoundation;
|
||||
use FileModifications;
|
||||
use HasMethods;
|
||||
use HasSiblings;
|
||||
|
||||
@@ -179,27 +180,6 @@ class File extends ModelWithContent
|
||||
return $this->blueprint = FileBlueprint::factory('files/' . $this->template(), 'files/default', $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Blurs the image by the given amount of pixels
|
||||
*
|
||||
* @param boolean $pixels
|
||||
* @return self
|
||||
*/
|
||||
public function blur($pixels = true)
|
||||
{
|
||||
return $this->thumb(['blur' => $pixels]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the image to black and white
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function bw()
|
||||
{
|
||||
return $this->thumb(['grayscale' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the template in addition to the
|
||||
* other content.
|
||||
@@ -236,38 +216,6 @@ class File extends ModelWithContent
|
||||
return $this->filename();
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the image by the given width and height
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param string|array $options
|
||||
* @return self
|
||||
*/
|
||||
public function crop(int $width, int $height = null, $options = null)
|
||||
{
|
||||
$quality = null;
|
||||
$crop = 'center';
|
||||
|
||||
if (is_int($options) === true) {
|
||||
$quality = $options;
|
||||
} elseif (is_string($options)) {
|
||||
$crop = $options;
|
||||
} elseif (is_a($options, 'Kirby\Cms\Field') === true) {
|
||||
$crop = $options->value();
|
||||
} elseif (is_array($options)) {
|
||||
$quality = $options['quality'] ?? $quality;
|
||||
$crop = $options['crop'] ?? $crop;
|
||||
}
|
||||
|
||||
return $this->thumb([
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'quality' => $quality,
|
||||
'crop' => $crop
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a kirbytag or markdown
|
||||
* tag for the file, which will be
|
||||
@@ -295,16 +243,6 @@ class File extends ModelWithContent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the file exists on disk
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
return is_file($this->root()) === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filename with extension
|
||||
*
|
||||
@@ -325,21 +263,6 @@ class File extends ModelWithContent
|
||||
return $this->siblingsCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the file to html
|
||||
*
|
||||
* @param array $attr
|
||||
* @return string
|
||||
*/
|
||||
public function html(array $attr = []): string
|
||||
{
|
||||
if ($this->type() === 'image') {
|
||||
return Html::img($this->url(), array_merge(['alt' => $this->alt()], $attr));
|
||||
} else {
|
||||
return Html::a($this->url(), $attr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id
|
||||
*
|
||||
@@ -425,18 +348,6 @@ class File extends ModelWithContent
|
||||
return $this->parent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file's last modification time.
|
||||
*
|
||||
* @param string $format
|
||||
* @param string|null $handler date or strftime
|
||||
* @return mixed
|
||||
*/
|
||||
public function modified(string $format = null, string $handler = null)
|
||||
{
|
||||
return F::modified($this->root(), $format, $handler ?? $this->kirby()->option('date.handler', 'date'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parent Page object
|
||||
*
|
||||
@@ -607,17 +518,6 @@ class File extends ModelWithContent
|
||||
return new FilePermissions($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the JPEG compression quality
|
||||
*
|
||||
* @param integer $quality
|
||||
* @return self
|
||||
*/
|
||||
public function quality(int $quality)
|
||||
{
|
||||
return $this->thumb(['quality' => $quality]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string query, starting from the model
|
||||
*
|
||||
@@ -644,24 +544,6 @@ class File extends ModelWithContent
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the file with the given width and height
|
||||
* while keeping the aspect ratio.
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param integer $quality
|
||||
* @return self
|
||||
*/
|
||||
public function resize(int $width = null, int $height = null, int $quality = null)
|
||||
{
|
||||
return $this->thumb([
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'quality' => $quality
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute root to the file
|
||||
*
|
||||
@@ -799,33 +681,6 @@ class File extends ModelWithContent
|
||||
return $this->siblings($self)->filterBy('template', $this->template());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a modified version of images
|
||||
* The media manager takes care of generating
|
||||
* those modified versions and putting them
|
||||
* in the right place. This is normally the
|
||||
* /media folder of your installation, but
|
||||
* could potentially also be a CDN or any other
|
||||
* place.
|
||||
*
|
||||
* @param array|null $options
|
||||
* @return FileVersion|File
|
||||
*/
|
||||
public function thumb(array $options = null)
|
||||
{
|
||||
if (empty($options) === true) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$result = $this->kirby()->component('file::version')($this->kirby(), $this, $options);
|
||||
|
||||
if (is_a($result, FileVersion::class) === false && is_a($result, File::class) === false) {
|
||||
throw new InvalidArgumentException('The file::version component must return a File or FileVersion object');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extended info for the array export
|
||||
* by injecting the information from
|
||||
|
@@ -157,6 +157,18 @@ trait FileFoundation
|
||||
return App::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file's last modification time.
|
||||
*
|
||||
* @param string $format
|
||||
* @param string|null $handler date or strftime
|
||||
* @return mixed
|
||||
*/
|
||||
public function modified(string $format = null, string $handler = null)
|
||||
{
|
||||
return F::modified($this->root(), $format, $handler ?? $this->kirby()->option('date.handler', 'date'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute path to the file root
|
||||
*
|
||||
|
119
kirby/src/Cms/FileModifications.php
Executable file
119
kirby/src/Cms/FileModifications.php
Executable file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
/**
|
||||
* Resizing, blurring etc
|
||||
*/
|
||||
trait FileModifications
|
||||
{
|
||||
|
||||
/**
|
||||
* Blurs the image by the given amount of pixels
|
||||
*
|
||||
* @param boolean $pixels
|
||||
* @return self
|
||||
*/
|
||||
public function blur($pixels = true)
|
||||
{
|
||||
return $this->thumb(['blur' => $pixels]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the image to black and white
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function bw()
|
||||
{
|
||||
return $this->thumb(['grayscale' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crops the image by the given width and height
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param string|array $options
|
||||
* @return self
|
||||
*/
|
||||
public function crop(int $width, int $height = null, $options = null)
|
||||
{
|
||||
$quality = null;
|
||||
$crop = 'center';
|
||||
|
||||
if (is_int($options) === true) {
|
||||
$quality = $options;
|
||||
} elseif (is_string($options)) {
|
||||
$crop = $options;
|
||||
} elseif (is_a($options, 'Kirby\Cms\Field') === true) {
|
||||
$crop = $options->value();
|
||||
} elseif (is_array($options)) {
|
||||
$quality = $options['quality'] ?? $quality;
|
||||
$crop = $options['crop'] ?? $crop;
|
||||
}
|
||||
|
||||
return $this->thumb([
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'quality' => $quality,
|
||||
'crop' => $crop
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the JPEG compression quality
|
||||
*
|
||||
* @param integer $quality
|
||||
* @return self
|
||||
*/
|
||||
public function quality(int $quality)
|
||||
{
|
||||
return $this->thumb(['quality' => $quality]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the file with the given width and height
|
||||
* while keeping the aspect ratio.
|
||||
*
|
||||
* @param integer $width
|
||||
* @param integer $height
|
||||
* @param integer $quality
|
||||
* @return self
|
||||
*/
|
||||
public function resize(int $width = null, int $height = null, int $quality = null)
|
||||
{
|
||||
return $this->thumb([
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'quality' => $quality
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a modified version of images
|
||||
* The media manager takes care of generating
|
||||
* those modified versions and putting them
|
||||
* in the right place. This is normally the
|
||||
* /media folder of your installation, but
|
||||
* could potentially also be a CDN or any other
|
||||
* place.
|
||||
*
|
||||
* @param array|null $options
|
||||
* @return FileVersion|File
|
||||
*/
|
||||
public function thumb(array $options = null)
|
||||
{
|
||||
if (empty($options) === true) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$result = $this->kirby()->component('file::version')($this->kirby(), $this, $options);
|
||||
|
||||
if (is_a($result, FileVersion::class) === false && is_a($result, File::class) === false) {
|
||||
throw new InvalidArgumentException('The file::version component must return a File or FileVersion object');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
@@ -25,7 +25,7 @@ class FileRules
|
||||
}
|
||||
|
||||
$parent = $file->parent();
|
||||
$duplicate = $parent->files()->not($file)->findBy('name', $name);
|
||||
$duplicate = $parent->files()->not($file)->findBy('filename', $name . '.' . $file->extension());
|
||||
|
||||
if ($duplicate) {
|
||||
throw new DuplicateException([
|
||||
|
@@ -2,8 +2,13 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
class FileVersion extends Asset
|
||||
use Kirby\Toolkit\Properties;
|
||||
|
||||
class FileVersion
|
||||
{
|
||||
use FileFoundation;
|
||||
use Properties;
|
||||
|
||||
protected $modifications;
|
||||
protected $original;
|
||||
|
||||
@@ -23,8 +28,10 @@ class FileVersion extends Asset
|
||||
return $this->asset()->$method(...$arguments);
|
||||
}
|
||||
|
||||
// content fields
|
||||
return $this->original()->content()->get($method, $arguments);
|
||||
if (is_a($this->original(), File::class) === true) {
|
||||
// content fields
|
||||
return $this->original()->content()->get($method, $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
public function id(): string
|
||||
@@ -42,7 +49,7 @@ class FileVersion extends Asset
|
||||
return $this->modifications ?? [];
|
||||
}
|
||||
|
||||
public function original(): File
|
||||
public function original()
|
||||
{
|
||||
return $this->original;
|
||||
}
|
||||
@@ -58,7 +65,7 @@ class FileVersion extends Asset
|
||||
$this->modifications = $modifications;
|
||||
}
|
||||
|
||||
protected function setOriginal(File $original)
|
||||
protected function setOriginal($original)
|
||||
{
|
||||
$this->original = $original;
|
||||
}
|
||||
|
@@ -41,9 +41,17 @@ class Form extends BaseForm
|
||||
{
|
||||
// get the original model data
|
||||
$original = $model->content()->toArray();
|
||||
$values = $props['values'] ?? [];
|
||||
|
||||
// convert closures to values
|
||||
foreach ($values as $key => $value) {
|
||||
if (is_a($value, 'Closure') === true) {
|
||||
$values[$key] = $value($original[$key] ?? null);
|
||||
}
|
||||
}
|
||||
|
||||
// set a few defaults
|
||||
$props['values'] = array_merge($original, $props['values'] ?? []);
|
||||
$props['values'] = array_merge($original, $values);
|
||||
$props['fields'] = $props['fields'] ?? [];
|
||||
$props['model'] = $model;
|
||||
|
||||
|
@@ -25,22 +25,34 @@ class Media
|
||||
* @param string $filename
|
||||
* @return Response|false
|
||||
*/
|
||||
public static function thumb(Model $model, string $hash, string $filename)
|
||||
public static function thumb($model, string $hash, string $filename)
|
||||
{
|
||||
$kirby = App::instance();
|
||||
|
||||
if (is_string($model) === true) {
|
||||
// assets
|
||||
$root = $kirby->root('media') . '/assets/' . $model . '/' . $hash;
|
||||
} else {
|
||||
// model files
|
||||
$root = $model->mediaRoot() . '/' . $hash;
|
||||
}
|
||||
|
||||
try {
|
||||
$kirby = $model->kirby();
|
||||
$url = $model->mediaUrl() . '/' . $hash . '/' . $filename;
|
||||
$root = $model->mediaRoot() . '/' . $hash;
|
||||
$thumb = $root . '/' . $filename;
|
||||
$job = $root . '/.jobs/' . $filename . '.json';
|
||||
$options = Data::read($job);
|
||||
$file = $model->file($options['filename']);
|
||||
|
||||
if (!$file || empty($options) === true) {
|
||||
if (empty($options) === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$kirby->thumb($file->root(), $thumb, $options);
|
||||
if (is_string($model) === true) {
|
||||
$source = $kirby->root('index') . '/' . $model . '/' . $options['filename'];
|
||||
} else {
|
||||
$source = $model->file($options['filename'])->root();
|
||||
}
|
||||
|
||||
$kirby->thumb($source, $thumb, $options);
|
||||
|
||||
F::remove($job);
|
||||
|
||||
|
@@ -608,10 +608,19 @@ class Page extends ModelWithContent
|
||||
/**
|
||||
* Checks if the page is a descendant of the given page
|
||||
*
|
||||
* @param string|Page $parent
|
||||
* @return boolean
|
||||
*/
|
||||
public function isDescendantOf(Page $parent): bool
|
||||
public function isDescendantOf($parent): bool
|
||||
{
|
||||
if (is_string($parent) === true) {
|
||||
$parent = $this->site()->find($parent);
|
||||
}
|
||||
|
||||
if (!$parent) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->parents()->has($parent->id()) === true;
|
||||
}
|
||||
|
||||
@@ -828,7 +837,7 @@ class Page extends ModelWithContent
|
||||
* @param string|null $handler
|
||||
* @return int|string
|
||||
*/
|
||||
public function modified(string $format = 'U', string $handler = null)
|
||||
public function modified(string $format = null, string $handler = null)
|
||||
{
|
||||
return F::modified($this->contentFile(), $format, $handler ?? $this->kirby()->option('date.handler', 'date'));
|
||||
}
|
||||
|
@@ -380,7 +380,7 @@ trait PageActions
|
||||
return 0;
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
$format = 'date' ? 'Ymd' : 'YmdHi';
|
||||
$format = $mode === 'date' ? 'Ymd' : 'YmdHi';
|
||||
$date = $this->content()->get('date')->value();
|
||||
$time = empty($date) === true ? time() : strtotime($date);
|
||||
|
||||
|
@@ -50,6 +50,9 @@ class Txt extends Handler
|
||||
// avoid problems with arrays
|
||||
if (is_array($value) === true) {
|
||||
$value = Yaml::encode($value);
|
||||
// avoid problems with localized floats
|
||||
} elseif (is_float($value) === true) {
|
||||
$value = Str::float($value);
|
||||
}
|
||||
|
||||
// escape accidental dividers within a field
|
||||
|
@@ -25,8 +25,19 @@ class Yaml extends Handler
|
||||
*/
|
||||
public static function encode(array $data): string
|
||||
{
|
||||
// fetch the current locale setting for numbers
|
||||
$locale = setlocale(LC_NUMERIC, 0);
|
||||
|
||||
// change to english numerics to avoid issues with floats
|
||||
setlocale(LC_NUMERIC, 'en_US');
|
||||
|
||||
// $data, $indent, $wordwrap, $no_opening_dashes
|
||||
return Spyc::YAMLDump($data, false, false, true);
|
||||
$yaml = Spyc::YAMLDump($data, false, false, true);
|
||||
|
||||
// restore the previous locale settings
|
||||
setlocale(LC_NUMERIC, $locale);
|
||||
|
||||
return $yaml;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -147,7 +147,7 @@ class Form
|
||||
} elseif (is_array($value) === true) {
|
||||
$strings[$key] = Yaml::encode($value);
|
||||
} else {
|
||||
$strings[$key] = (string)$value;
|
||||
$strings[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -118,7 +118,9 @@ class Html
|
||||
if (isset($value['value']) && isset($value['escape'])) {
|
||||
$value = $value['escape'] === true ? htmlspecialchars($value['value'], ENT_QUOTES, 'UTF-8') : $value['value'];
|
||||
} else {
|
||||
$value = implode(' ', $value);
|
||||
$value = implode(' ', array_filter($value, function ($value) {
|
||||
return !empty($value) || is_numeric($value);
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
$value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
|
||||
|
@@ -336,6 +336,20 @@ class Str
|
||||
return static::substr($string, 0, strrpos(static::substr($string, 0, $chars), ' ')) . ' ' . $rep;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the value to a float with a decimal
|
||||
* point, no matter what the locale setting is
|
||||
*
|
||||
* @param string|int|float $value
|
||||
* @return string
|
||||
*/
|
||||
public static function float($value): string
|
||||
{
|
||||
$value = str_replace(',', '.', $value);
|
||||
$decimal = strlen(substr(strrchr($value, "."), 1));
|
||||
return number_format((float)$value, $decimal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rest of the string starting from the given character
|
||||
*
|
||||
|
Reference in New Issue
Block a user