Files
idpan.poznan.pl/administrator/components/com_akeebabackup/webpush/NotificationOptions.php
2026-02-08 21:16:11 +01:00

430 lines
12 KiB
PHP

<?php
/**
* Akeeba WebPush
*
* An abstraction layer for easier implementation of WebPush in Joomla components.
*
* @copyright (c) 2022 Akeeba Ltd
* @license GNU GPL v3 or later; see LICENSE.txt
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
namespace Akeeba\WebPush;
use Joomla\Utilities\ArrayHelper;
/**
* Abstraction of the notification options recognised by browsers.
*
* IMPORTANT! Items marked as `experimental` may NOT work correctly, or at all, on some browsers.
*
* @since 1.0.0
* @see https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification
* @package Akeeba\WebPush
*
* @property array|null $actions An array of actions to display in the notification.
* @property string|null $badge URL to a badge icon.
* @property string|null $body A string representing an extra content to display within the notification.
* @property mixed $data Arbitrary data that you want to be associated with the notification.
* @property string|null $dir The direction of the notification; it can be auto, ltr or rtl.
* @property string|null $icon URL of an image to be used as an icon by the notification.
* @property string|null $image URL of an image to be displayed in the notification.
* @property string|null $lang Specify the language used within the notification.
* @property bool $renotify Whether to suppress vibrations and audible alerts when reusing a tag value.
* @property bool $requireInteraction Should the notification remain on screen until dismissed?
* @property bool $silent When set indicates that no sounds or vibrations should be made.
* @property string|null $tag A tag to group related notifications.
* @property int|null $timestamp UNIX timestamp IN MILLISECONDS of the date and time applicable to a notification.
* @property array|null $vibrate A vibration pattern to run with the display of the notification.
*/
class NotificationOptions implements \JsonSerializable, \ArrayAccess, \Countable
{
/**
* An array of actions to display in the notification.
*
* Do note that this also needs support to be added to your Web Push service worker JavaScript file for each
* individual action. Actions are more prominent on Android than on desktop; in the latter case you need to click on
* the notification to see the actions and that's only if the browser supports actions.
*
* @since 1.0.0
* @var array|null
* @see https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration/showNotification
* @experimental
*/
private $actions = null;
/**
* URL to a badge icon.
*
* This is a string containing the URL of an image to represent the notification when there is not enough space to
* display the notification itself such as for example, the Android Notification Bar. On Android devices, the badge
* should accommodate devices up to 4x resolution, about 96 by 96 px, and the image will be automatically masked.
*
* @since 1.0.0
* @var string|null
* @experimental
*/
private $badge = null;
/**
* A string representing an extra content to display within the notification.
*
* @since 1.0.0
* @var string|null
*/
private $body = null;
/**
* Arbitrary data that you want to be associated with the notification.
*
* @since 1.0.0
* @var string|int|float|array|\stdClass|\JsonSerializable|null
* @experimental
*/
private $data = null;
/**
* The direction of the notification; it can be auto, ltr or rtl.
*
* @since 1.0.0
* @var string|null
*/
private $dir = null;
/**
* URL of an image to be used as an icon by the notification.
*
* @since 1.0.0
* @var string|null
*/
private $icon = null;
/**
* URL of an image to be displayed in the notification.
*
* @since 1.0.0
* @var string|null
* @experimental
*/
private $image = null;
/**
* Specify the language used within the notification.
*
* This string must be a valid language tag according to RFC 5646: Tags for Identifying Languages (also known as
* BCP 47).
*
* @since 1.0.0
* @var string|null
*/
private $lang = null;
/**
* Whether to suppress vibrations and audible alerts when reusing a tag value.
*
* If options' renotify is true and optionss tag is the empty string a TypeError will be thrown by the JavaScript.
* The default is false.
*
* @since 1.0.0
* @var bool
* @experimental
*/
private $renotify = false;
/**
* Should the notification remain on screen until dismissed?
*
* Indicates that on devices with sufficiently large screens, a notification should remain active until the user
* clicks or dismisses it. If this value is absent or false, the desktop version of Chrome will auto-minimize
* notifications after approximately twenty seconds. The default value is false.
*
* @since 1.0.0
* @var bool
* @experimental
*/
private $requireInteraction = false;
/**
* When set indicates that no sounds or vibrations should be made.
*
* If options' silent is true and options' vibrate is present the JavaScript will throw a TypeError exception. The
* default value is false.
*
* @since 1.0.0
* @var bool
*/
private $silent = false;
/**
* A tag to group related notifications.
*
* An ID for a given notification that allows you to find, replace, or remove the notification using a script if
* necessary.
*
* @since 1.0.0
* @var string|null
*/
private $tag = null;
/**
* UNIX timestamp IN MILLISECONDS of the date and time applicable to a notification.
*
* Represents the time when the notification was created. It can be used to indicate the time at which a
* notification is actual. For example, this could be in the past when a notification is used for a message that
* couldn't immediately be delivered because the device was offline, or in the future for a meeting that is about to
* start.
*
* @since 1.0.0
* @var int|null
*/
private $timestamp = null;
/**
* A vibration pattern to run with the display of the notification.
*
* A vibration pattern can be an array with as few as one member. The values are times in milliseconds where the
* even indices (0, 2, 4, etc.) indicate how long to vibrate and the odd indices indicate how long to pause. For
* example, [300, 100, 400] would vibrate 300ms, pause 100ms, then vibrate 400ms.
*
* @since 1.0.0
* @var array|null
* @experimental
*/
private $vibrate = null;
/**
* Magic getter
*
* @param string $name The property to get
*
* @return mixed The property value
* @since 1.0.0
*/
public function __get($name)
{
return $this->offsetGet($name);
}
/**
* Magic setter
*
* @param string $name The property to set
* @param mixed $value The value to set
*
* @since 1.0.0
*/
public function __set($name, $value)
{
$this->offsetSet($name, $value);
}
/**
* Is a property set?
*
* @param string $name The name of the property to check
*
* @return bool True if it exists
*
* @since 1.0.0
*/
#[\ReturnTypeWillChange]
public function __isset($name)
{
return $this->offsetExists($name);
}
/**
* Converts the object to string
*
* @return string The JSON-serialised form of this object
*
* @since 1.0.0
*/
#[\ReturnTypeWillChange]
public function __toString()
{
return json_encode($this);
}
/**
* Count elements of an object.
*
* This method only returns the number of top-level elements which will end up in the JSON-serialised format of this
* object.
*
* @return int The custom count as an integer.
* @since 1.0.0
*/
#[\ReturnTypeWillChange]
public function count()
{
return count($this->toArray());
}
/**
* Specify data which should be serialized to JSON
*
* @return mixed Data which can be serialized by <b>json_encode</b>.
* @since 1.0.0
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
{
return $this->toArray();
}
/**
* Whether an offset exists
*
* @param mixed $offset An offset to check for.
*
* @return bool True on success
* @since 1.0.0
*/
#[\ReturnTypeWillChange]
public function offsetExists($offset)
{
return property_exists($this, $offset);
}
/**
* Offset to retrieve
*
* @param mixed $offset The offset to retrieve.
*
* @return mixed
* @since 1.0.0
*/
#[\ReturnTypeWillChange]
public function offsetGet($offset)
{
if (!$this->offsetExists($offset))
{
throw new \InvalidArgumentException(
sprintf(
'Class %s does not support array offset %s',
__CLASS__,
$offset
)
);
}
return $this->{$offset};
}
/**
* Offset to set
*
* @param string $offset The offset to assign the value to.
* @param mixed $value The value to set.
*
* @return void
* @since 1.0.0
*/
#[\ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
switch ($offset)
{
case 'actions':
if ($value !== null && !is_array($value))
{
throw new \InvalidArgumentException(sprintf('%s[\'%s\'] must be an array or null', __CLASS__, $offset));
}
break;
case 'body':
case 'lang':
case 'tag':
if ($value !== null && !is_string($value))
{
throw new \InvalidArgumentException(sprintf('%s[\'%s\'] must be null or string', __CLASS__, $offset));
}
break;
case 'dir':
if (($value !== null && !is_string($value)) || !in_array($value, ['auto', 'ltr', 'rtl']))
{
throw new \InvalidArgumentException(sprintf('%s[\'%s\'] must be one of "auto", "ltr", "rtl" or null', __CLASS__, $offset));
}
break;
case 'badge':
case 'icon':
case 'image':
$var = filter_var($value, FILTER_VALIDATE_URL, FILTER_NULL_ON_FAILURE);
if (($value !== null && !is_string($value)) || ($var !== $value))
{
throw new \InvalidArgumentException(sprintf('%s[\'%s\'] must be null or a URL', __CLASS__, $offset));
}
break;
case 'renotify':
case 'requireInteraction':
case 'silent':
$value = filter_var($value, FILTER_VALIDATE_BOOL);
break;
case 'timestamp':
$value = filter_var($value, FILTER_VALIDATE_INT, FILTER_NULL_ON_FAILURE);
break;
case 'vibrate':
$value = ArrayHelper::toInteger($value);
break;
}
$this->{$offset} = $value;
}
/**
* Unsupported
*
* @param string $offset Ignored.
*
* @throws \BadMethodCallException
* @since 1.0.0
*/
#[\ReturnTypeWillChange]
public function offsetUnset($offset)
{
throw new \BadFunctionCallException(
sprintf(
'Class %s does not allow unsetting virtual array elements (you tried to unset %s)',
__CLASS__,
$offset
)
);
}
/**
* Returns an array with the non-null, non-empty-array arguments.
*
* @return array
* @since 1.0.0
*/
public function toArray(): array
{
return array_filter(
get_object_vars($this),
function ($x) {
return ($x !== null) && ($x !== []);
}
);
}
}