first commit
This commit is contained in:
@@ -0,0 +1,430 @@
|
||||
<?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 !== []);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user