1
0
mirror of https://github.com/Chouchen/ShikiryuRSS.git synced 2024-11-22 19:58:51 +01:00

🔒 Add formator

Closes #3
This commit is contained in:
Clement Desmidt 2023-04-17 14:28:01 +02:00
parent 6fcf240f72
commit 44c4833069
23 changed files with 571 additions and 367 deletions

View File

@ -15,81 +15,93 @@ use Shikiryu\SRSS\Validator\Validator;
class Channel extends HasValidator implements SRSSElement class Channel extends HasValidator implements SRSSElement
{ {
/** /**
* @required * @validate required
* @nohtml * @format html
*/ */
public string $title = ''; protected string $title = '';
/** /**
* @required * @validate required
* @url * @validate url
* @format url
*/ */
public string $link = ''; protected string $link = '';
/** /**
* @required * @validate required
* @format html
*/ */
public string $description = ''; protected string $description = '';
/** /**
* @lang * @validate lang
*/ */
public ?string $language = null; protected ?string $language = null;
/** /**
* @nohtml * @validate nohtml
* @format nohtml
*/ */
public ?string $copyright = null; protected ?string $copyright = null;
/** /**
* @nohtml * @validate nohtml
* @format nohtml
*/ */
public ?string $managingEditor = null; protected ?string $managingEditor = null;
/** /**
* @nohtml * @validate nohtml
* @format nohtml
*/ */
public ?string $webMaster = null; protected ?string $webMaster = null;
/** /**
* @date * @validate date
* @format date
*/ */
public ?string $pubDate = null; protected ?string $pubDate = null;
/** /**
* @date * @validate date
* @format date
*/ */
public ?string $lastBuildDate = null; protected ?string $lastBuildDate = null;
/** /**
* @var Category[] * @var Category[]
*/ */
public ?array $category = null; protected ?array $category = null;
/** /**
* @nohtml * @validate nohtml
* @format nohtml
*/ */
public ?string $generator = null; protected ?string $generator = null;
/** /**
* @url * @validate url
* @format url
*/ */
public ?string $docs = null; protected ?string $docs = null;
/** /**
* @var Cloud|null * @var Cloud|null
*/ */
public ?Cloud $cloud = null; protected ?Cloud $cloud = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?string $ttl = null; protected ?string $ttl = null;
public ?Image $image = null; protected ?Image $image = null;
public ?string $rating = null; protected ?string $rating = null;
/** /**
* @var string|null * @var string|null
* The purpose of the <textInput> element is something of a mystery. You can use it to specify a search engine box. Or to allow a reader to provide feedback. Most aggregators ignore it. * The purpose of the <textInput> element is something of a mystery. You can use it to specify a search engine box. Or to allow a reader to provide feedback. Most aggregators ignore it.
*/ */
public ?string $textInput = null; protected ?string $textInput = null;
/** /**
* @hour * @validate hour
* @format hour
*/ */
public ?string $skipHours = null; protected ?string $skipHours = null;
/** /**
* @day * @validate day
* @format day
*/ */
public ?string $skipDays = null; protected ?string $skipDays = null;
/** /**
* @return bool * @return bool

View File

@ -10,13 +10,14 @@ use Shikiryu\SRSS\Validator\Validator;
class Category extends HasValidator implements SRSSElement class Category extends HasValidator implements SRSSElement
{ {
/** /**
* @string * @validate url
* @format url
*/ */
public ?string $domain = null; protected ?string $domain = null;
/** /**
* @string * @validate string
*/ */
public ?string $value = null; protected ?string $value = null;
public function isValid(): bool public function isValid(): bool
{ {

View File

@ -10,25 +10,26 @@ use Shikiryu\SRSS\Validator\Validator;
class Cloud extends HasValidator implements SRSSElement class Cloud extends HasValidator implements SRSSElement
{ {
/** /**
* @string * @validate string
*/ */
public ?string $domain = null; protected ?string $domain = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?int $port = null; protected ?int $port = null;
/** /**
* @string * @validate string
*/ */
public ?string $path = null; protected ?string $path = null;
/** /**
* @string * @validate string
*/ */
public ?string $registerProcedure = null; protected ?string $registerProcedure = null;
/** /**
* @string * @validate string
*/ */
public ?string $protocol = null; protected ?string $protocol = null;
public function isValid(): bool public function isValid(): bool
{ {

View File

@ -10,32 +10,41 @@ use Shikiryu\SRSS\Validator\Validator;
class Image extends HasValidator implements SRSSElement class Image extends HasValidator implements SRSSElement
{ {
/** /**
* @required * @validate required
* @url * @validate url
* @format url
*/ */
public ?string $url = null; protected ?string $url = null;
/** /**
* @required * @validate required
* @nohtml * @validate nohtml
* @format nohtml
*/ */
public ?string $title = null; protected ?string $title = null;
/** /**
* @required * @validate required
* @url * @validate url
* @format url
*/ */
public ?string $link = null; protected ?string $link = null;
/** /**
* @int * @validate int
* @max 144 * @format int
* @validate max 144
*/ */
public int $width = 88; // Maximum value for width is 144, default value is 88. protected int $width = 88; // Maximum value for width is 144, default value is 88.
/** /**
* @int * @format int
* @max 400 * @validate int
* @validate max 400
*/ */
public int $height = 31; //Maximum value for height is 400, default value is 31. protected int $height = 31; //Maximum value for height is 400, default value is 31.
public string $description; /**
* @var string
* @format html
*/
protected string $description;
public function isValid(): bool public function isValid(): bool
{ {

View File

@ -16,50 +16,55 @@ use Shikiryu\SRSS\Validator\Validator;
class Item extends HasValidator implements SRSSElement class Item extends HasValidator implements SRSSElement
{ {
/** /**
* @requiredOr description * @validate requiredOr description
* @nohtml * @format html
*/ */
public ?string $title = null; protected ?string $title = null;
/** /**
* @url * @validate url
* @format url
*/ */
public ?string $link = null; protected ?string $link = null;
/** /**
* @requiredOr title * @validate requiredOr title
* @format html
*/ */
public ?string $description = null; protected ?string $description = null;
/** /**
* @email * @validate email
* @format email
*/ */
public ?string $author = null; protected ?string $author = null;
/** /**
* @var Category[] * @var Category[]
*/ */
public ?array $category = null; protected ?array $category = null;
/** /**
* @url * @validate url
* @format url
*/ */
public ?string $comments = null; protected ?string $comments = null;
/** /**
* @var Enclosure|null * @var Enclosure|null
*/ */
public ?Enclosure $enclosure = null; protected ?Enclosure $enclosure = null;
public ?string $guid = null; protected ?string $guid = null;
/** /**
* @date * @validate date
* @format date
*/ */
public ?string $pubDate = null; protected ?string $pubDate = null;
/** /**
* @var Source|null * @var Source|null
*/ */
public ?Source $source = null; protected ?Source $source = null;
/** /**
* @var Content[] * @var Content[]
* @contentMedia * @contentMedia
*/ */
public array $medias = []; protected array $medias = [];
public function isValid(): bool public function isValid(): bool
{ {

View File

@ -10,13 +10,14 @@ use Shikiryu\SRSS\Validator\Validator;
class Category extends HasValidator implements SRSSElement class Category extends HasValidator implements SRSSElement
{ {
/** /**
* @string * @validate string
*/ */
public string $domain; protected string $domain;
/** /**
* @string * @validate string
*/ */
public string $value; protected string $value;
public function isValid(): bool public function isValid(): bool
{ {

View File

@ -10,19 +10,22 @@ use Shikiryu\SRSS\Validator\Validator;
class Enclosure extends HasValidator implements SRSSElement class Enclosure extends HasValidator implements SRSSElement
{ {
/** /**
* @url * @validate url
* @format url
*/ */
public ?string $url = null; protected ?string $url = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?int $length = null; protected ?int $length = null;
/** /**
* @mediaType * @validate mediaType
* @format mediaType
*/ */
public ?string $type = null; protected ?string $type = null;
public function isValid(): bool public function isValid(): bool
{ {

View File

@ -10,14 +10,16 @@ use Shikiryu\SRSS\Validator\Validator;
class Source extends HasValidator implements SRSSElement class Source extends HasValidator implements SRSSElement
{ {
/** /**
* @url * @validate url
* @format url
*/ */
public ?string $url = null; protected ?string $url = null;
/** /**
* @nohtml * @validate nohtml
* @format nohtml
*/ */
public ?string $value = null; protected ?string $value = null;
public function isValid(): bool public function isValid(): bool
{ {

View File

@ -10,61 +10,73 @@ use Shikiryu\SRSS\Validator\Validator;
class Content extends HasValidator implements SRSSElement class Content extends HasValidator implements SRSSElement
{ {
/** /**
* @url * @validate url
* @format url
*/ */
public ?string $url = null; protected ?string $url = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?int $filesize = null; protected ?int $filesize = null;
/** /**
* @mediaType * @validate mediaType
*/ */
public ?string $type = null; protected ?string $type = null;
/** /**
* @mediaMedium * @validate mediaMedium
* @format mediaMedium
*/ */
public ?string $medium = null; protected ?string $medium = null;
/** /**
* @bool * @validate bool
* @format bool
*/ */
public ?bool $isDefault = null; protected ?bool $isDefault = null;
/** /**
* @mediaExpression * @validate mediaExpression
* @format mediaExpression
*/ */
public ?string $expression = null; protected ?string $expression = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?int $bitrate = null; protected ?int $bitrate = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?int $framerate = null; protected ?int $framerate = null;
/** /**
* @float * @validate float
* @format float
*/ */
public ?float $samplerate = null; protected ?float $samplerate = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?int $channels = null; protected ?int $channels = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?int $duration = null; protected ?int $duration = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?int $height = null; protected ?int $height = null;
/** /**
* @int * @validate int
* @format int
*/ */
public ?int $width = null; protected ?int $width = null;
/** /**
* @lang * @validate lang
*/ */
public ?string $lang = null; protected ?string $lang = null;
public function isValid(): bool public function isValid(): bool
{ {

View File

@ -27,7 +27,7 @@ class ItemParser extends DomDocument
if ($child->nodeName === 'media:group') { if ($child->nodeName === 'media:group') {
self::_loadChildAttributes($item, $child); self::_loadChildAttributes($item, $child);
} elseif ($child->nodeName === 'media:content') { } elseif ($child->nodeName === 'media:content') {
$item->medias[] = MediaContentParser::read($child); $item->medias = MediaContentParser::read($child);
} elseif ($child->nodeName === 'category') { } elseif ($child->nodeName === 'category') {
$category = new Item\Category(); $category = new Item\Category();
foreach($child->attributes as $attribute) { foreach($child->attributes as $attribute) {

View File

@ -109,7 +109,7 @@ class SRSSParser extends DomDocument
$category->{$attribute->name} = $attribute->value; $category->{$attribute->name} = $attribute->value;
} }
$category->value = $child->nodeValue; $category->value = $child->nodeValue;
$this->doc->channel->category[] = $category; $this->doc->channel->category = $category;
} else { } else {
$this->doc->channel->{$child->nodeName} = $child->nodeValue; $this->doc->channel->{$child->nodeName} = $child->nodeValue;
} }

View File

@ -15,6 +15,7 @@ use Shikiryu\SRSS\Exception\PropertyNotFoundException;
use Shikiryu\SRSS\Exception\SRSSException; use Shikiryu\SRSS\Exception\SRSSException;
use Shikiryu\SRSS\Exception\UnreadableRSSException; use Shikiryu\SRSS\Exception\UnreadableRSSException;
use Shikiryu\SRSS\Parser\SRSSParser; use Shikiryu\SRSS\Parser\SRSSParser;
use Shikiryu\SRSS\Validator\Formator;
use Shikiryu\SRSS\Validator\Validator; use Shikiryu\SRSS\Validator\Validator;
/** /**
@ -126,11 +127,14 @@ class SRSS implements Iterator
throw new PropertyNotFoundException(Channel::class, $name); throw new PropertyNotFoundException(Channel::class, $name);
} }
if ((new Validator())->isValidValueForObjectProperty($this->channel, $name, $val)) { if ((new Validator())->isValidValueForObjectProperty($this->channel, $name, $val)) {
if (SRSSTools::getPropertyType(Channel::class, $name) === 'array') { if (SRSSTools::getPropertyType(Channel::class, $name) === 'array') {
$this->channel->{$name}[] = $val; $this->channel->{$name} = $val;
} else { } else {
$val = is_string($val) ? (new Formator())->formatValue($this->channel, $name, $val) : $val;
$this->channel->{$name} = $val; $this->channel->{$name} = $val;
} }
} }
} }

View File

@ -2,210 +2,27 @@
namespace Shikiryu\SRSS; namespace Shikiryu\SRSS;
use DateTime;
use DateTimeInterface;
use ReflectionProperty; use ReflectionProperty;
use Shikiryu\SRSS\Validator\Formator;
class SRSSTools class SRSSTools
{ {
/**
* @throws \ReflectionException
*/
public static function getPropertyType($object, $property): ?string public static function getPropertyType($object, $property): ?string
{ {
$rp = new ReflectionProperty($object, $property); $rp = new ReflectionProperty($object, $property);
return $rp->getType()?->getName(); return $rp->getType()?->getName();
} }
public static function check($check, $flag)
{
return match ($flag) {
'nohtml' => self::noHTML($check),
'link' => self::checkLink($check),
'html' => self::HTML4XML($check),
'date' => self::getRSSDate($check),
'email' => self::checkEmail($check),
'int' => self::checkInt($check),
'hour' => self::checkHour($check),
'day' => self::checkDay($check),
'media_type' => self::checkMediaType($check),
'media_medium' => self::checkMediaMedium($check),
'bool' => self::checkBool($check),
'medium_expression' => self::checkMediumExpression($check)
};
}
/** /**
* format the RSS to the wanted format * @param string $string
*
* @param $format string wanted format
* @param $date string RSS date
*
* @return string date
*/
public static function formatDate(string $format, string $date): string
{
return date($format, strtotime($date));
}
/**
* format a date for RSS format
*
* @param string $date date to format
* @param string $format
* *
* @return string * @return string
*/ */
public static function getRSSDate(string $date, string $format = ''): string public static function getRSSDate(string $string)
{ {
$date_position = 'dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU'; return Formator::checkDate($string);
if($format !== '' && preg_match('~^(['.$date_position.']{1})([-/])(['.$date_position.']{1})([-/])(['.$date_position.']{1})$~', $format)){
$datetime = DateTime::createFromFormat($format, $date);
if ($datetime === false) {
return '';
}
return $datetime->format(DATE_RSS);
}
if (strtotime($date) !==false ) {
return date("D, d M Y H:i:s T", strtotime($date));
}
if (count(explode(' ', $date)) === 2) {
return DateTime::createFromFormat('Y-m-d H:i:s', $date)->format(DateTimeInterface::RSS);
}
[$j, $m, $a] = explode('/', $date);
return date("D, d M Y H:i:s T", strtotime($a.'-'.$m.'-'.$j));
}
/**
* check if it's an url
*
* @param $check string to check
*
* @return string|boolean the filtered data, or FALSE if the filter fails.
*/
public static function checkLink(string $check): bool|string
{
return filter_var($check, FILTER_VALIDATE_URL);
}
/**
* make a string XML-compatible
*
* @param $check string to format
*
* @return string formatted string
*/
public static function HTML4XML(string $check): string
{
return sprintf('<![CDATA[ %s ]]>', htmlspecialchars($check));
}
/**
* delete html tags
*
* @param $check string to format
*
* @return string formatted string
*/
public static function noHTML(string $check): string
{
return strip_tags($check);
}
/**
* check if it's a day (in RSS terms)
*
* @param $check string to check
*
* @return string the day, or empty string
*/
public static function checkDay(string $check): string
{
$possibleDay = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
return in_array(strtolower($check), $possibleDay) ? $check : '';
}
/**
* check if it's an email
*
* @param $check string to check
*
* @return string|boolean the filtered data, or FALSE if the filter fails.
*/
public static function checkEmail(string $check): bool|string
{
return filter_var($check, FILTER_VALIDATE_EMAIL);
}
/**
* check if it's an hour (in RSS terms)
*
* @param $check string to check
*
* @return string|boolean the filtered data, or FALSE if the filter fails.
*/
public static function checkHour(string $check): bool|string
{
$options = [
'options' => [
'default' => 0,
'min_range' => 0,
'max_range' => 23
]
];
return filter_var($check, FILTER_VALIDATE_INT, $options);
}
/**
* check if it's an int
*
* @param $check int to check
*
* @return int|boolean the filtered data, or FALSE if the filter fails.
*/
public static function checkInt(int $check): bool|int
{
return filter_var($check, FILTER_VALIDATE_INT);
}
/**
* @param $check
*
* @return mixed
*/
public static function checkMediaType($check): mixed
{
return $check;
}
/**
* @param $check
*
* @return mixed|null
*/
public static function checkMediaMedium($check): ?string
{
return in_array($check, ['image', 'audio', 'video', 'document', 'executable']) ? $check : null;
}
/**
* @param $check
*
* @return mixed|null
*/
public static function checkBool($check): ?string
{
return in_array($check, ['true', 'false']) ? $check : null;
}
/**
* @param $check
*
* @return mixed|null
*/
public static function checkMediumExpression($check): ?string
{
return in_array($check, ['sample', 'full', 'nonstop']) ? $check : null;
} }
} }

268
src/Validator/Formator.php Normal file
View File

@ -0,0 +1,268 @@
<?php
namespace Shikiryu\SRSS\Validator;
use DateTime;
use DateTimeInterface;
use ReflectionException;
use ReflectionProperty;
class Formator
{
use ReadProperties;
/**
* @param $object
* @param $property
* @param $value
*
* @return false|string
*/
public function formatValue($object, $property, $value): bool|string
{
try {
$property = $this->getReflectedProperty($object, $property);
} catch (ReflectionException) {
return false;
}
$propertyAnnotations = $this->_getPropertyAnnotations($property);
foreach ($propertyAnnotations as $propertyAnnotation) {
$value = $this->_formatValue($propertyAnnotation, $value);
}
return $value;
}
/**
* @param ReflectionProperty $property
*
* @return array
*/
private function _getPropertyAnnotations(ReflectionProperty $property): array
{
preg_match_all('#@format (.*?)\n#s', $property->getDocComment(), $annotations);
return array_map(static fn($annotation) => trim($annotation), $annotations[1]);
}
/**
* @param string $annotation
* @param string $value
*
* @return void
*/
private function _formatValue(string $annotation, string $value)
{
return match ($annotation) {
'nohtml' => self::noHTML($value),
'url' => self::checkLink($value),
'html' => self::HTML4XML($value),
'date' => self::checkDate($value),
'email' => self::checkEmail($value),
'int' => self::checkInt($value),
'float' => self::checkFloat($value),
'hour' => self::checkHour($value),
'day' => self::checkDay($value),
'mediaType' => self::checkMediaType($value),
'mediaMedium' => self::checkMediaMedium($value),
'bool' => self::checkBool($value),
'mediaExpression' => self::checkMediumExpression($value),
};
}
/**
* format a date for RSS format
*
* @param string $date date to format
* @param string $format
*
* @return string
*/
public static function checkDate(string $date, string $format = ''): string
{
$date_position = 'dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU';
if($format !== '' && preg_match('~^(['.$date_position.']{1})([-/])(['.$date_position.']{1})([-/])(['.$date_position.']{1})$~', $format)){
$datetime = DateTime::createFromFormat($format, $date);
if ($datetime === false) {
return '';
}
return $datetime->format(DATE_RSS);
}
if (strtotime($date) !==false ) {
return date("D, d M Y H:i:s T", strtotime($date));
}
if (count(explode(' ', $date)) === 2) {
return DateTime::createFromFormat('Y-m-d H:i:s', $date)->format(DateTimeInterface::RSS);
}
[$j, $m, $a] = explode('/', $date);
return date("D, d M Y H:i:s T", strtotime($a.'-'.$m.'-'.$j));
}
/**
* format the RSS to the wanted format
*
* @param $format string wanted format
* @param $date string RSS date
*
* @return string date
*/
public static function formatDate(string $format, string $date): string
{
return date($format, strtotime($date));
}
/**
* check if it's an url
*
* @param $check string to check
*
* @return string|boolean the filtered data, or FALSE if the filter fails.
*/
public static function checkLink(string $check): bool|string
{
return filter_var($check, FILTER_VALIDATE_URL);
}
/**
* make a string XML-compatible
*
* @param $check string to format
*
* @return string formatted string
*/
public static function HTML4XML(string $check): string
{
if (str_starts_with($check, '<![CDATA[ ') && str_ends_with($check, ' ]]>')) {
return $check;
}
return sprintf('<![CDATA[ %s ]]>', htmlspecialchars($check));
}
/**
* delete html tags
*
* @param $check string to format
*
* @return string formatted string
*/
public static function noHTML(string $check): string
{
return strip_tags($check);
}
/**
* check if it's a day (in RSS terms)
*
* @param $check string to check
*
* @return string the day, or empty string
*/
public static function checkDay(string $check): string
{
$possibleDay = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
return in_array(strtolower($check), $possibleDay) ? $check : '';
}
/**
* check if it's an email
*
* @param $check string to check
*
* @return string|boolean the filtered data, or FALSE if the filter fails.
*/
public static function checkEmail(string $check): bool|string
{
return filter_var($check, FILTER_VALIDATE_EMAIL);
}
/**
* check if it's an hour (in RSS terms)
*
* @param $check string to check
*
* @return string|boolean the filtered data, or FALSE if the filter fails.
*/
public static function checkHour(string $check): bool|string
{
$options = [
'options' => [
'default' => 0,
'min_range' => 0,
'max_range' => 23
]
];
return filter_var($check, FILTER_VALIDATE_INT, $options);
}
/**
* check if it's an int
*
* @param $check int to check
*
* @return int|boolean the filtered data, or FALSE if the filter fails.
*/
public static function checkInt(int $check): bool|int
{
return filter_var($check, FILTER_VALIDATE_INT);
}
/**
* check if it's a float
*
* @param float $check to check
*
* @return float|boolean the filtered data, or FALSE if the filter fails.
*/
public static function checkFloat(float $check): bool|float
{
return filter_var($check, FILTER_VALIDATE_FLOAT);
}
/**
* @param $check
*
* @return mixed
*/
public static function checkMediaType($check): mixed
{
return $check;
}
/**
* @param $check
*
* @return mixed|null
*/
public static function checkMediaMedium($check): ?string
{
return in_array($check, ['image', 'audio', 'video', 'document', 'executable']) ? $check : null;
}
/**
* @param $check
*
* @return mixed|null
*/
public static function checkBool($check): ?string
{
return in_array($check, ['true', 'false']) ? $check : null;
}
/**
* @param $check
*
* @return mixed|null
*/
public static function checkMediumExpression($check): ?string
{
return in_array($check, ['sample', 'full', 'nonstop']) ? $check : null;
}
}

View File

@ -2,10 +2,63 @@
namespace Shikiryu\SRSS\Validator; namespace Shikiryu\SRSS\Validator;
use Shikiryu\SRSS\Exception\PropertyNotFoundException;
use Shikiryu\SRSS\Exception\SRSSException;
use Shikiryu\SRSS\SRSSTools;
abstract class HasValidator abstract class HasValidator
{ {
/** /**
* @var bool[] * @var bool[]
*/ */
public array $validated = []; public array $validated = [];
/**
* setter of others attributes
*
* @param $name
* @param $val
*
* @throws SRSSException
* @throws \ReflectionException
*/
public function __set($name, $val)
{
if (!property_exists(static::class, $name)) {
throw new PropertyNotFoundException(static::class, $name);
}
if ((new Validator())->isValidValueForObjectProperty($this, $name, $val)) {
if (SRSSTools::getPropertyType(static::class, $name) === 'array') {
/** @var array $this->{$name} */
$this->{$name}[] = $val;
} else {
$val = is_string($val) ? (new Formator())->formatValue($this, $name, $val) : $val;
$this->{$name} = $val;
}
}
}
/**
* @param $name
*
* @return bool
*/
public function __isset($name)
{
return isset($this->{$name});
}
/**
* getter of others attributes
*
* @param $name
*
* @return null|string
*/
public function __get($name)
{
return $this->{$name} ?? null;
}
} }

View File

@ -0,0 +1,39 @@
<?php
namespace Shikiryu\SRSS\Validator;
use ReflectionClass;
use ReflectionException;
use ReflectionProperty;
trait ReadProperties
{
/**
* @param $object
* @param $property
* @return ReflectionProperty|null
* @throws ReflectionException
*/
private function getReflectedProperty($object, $property): ?ReflectionProperty
{
$properties = array_filter(
$this->_getClassProperties(get_class($object)),
static fn($p) => $p->getName() === $property
);
if (count($properties) !== 1) {
return null;
}
return current($properties);
}
/**
* @return ReflectionProperty[]
* @throws ReflectionException
*/
private function _getClassProperties($class): array
{
return (new ReflectionClass($class))->getProperties();
}
}

View File

@ -11,29 +11,11 @@ use Shikiryu\SRSS\Entity\Media\Content;
class Validator class Validator
{ {
use ReadProperties;
protected ?object $object = null; protected ?object $object = null;
/**
* @param $object
* @param $property
* @return ReflectionProperty|null
* @throws ReflectionException
*/
private function getReflectedProperty($object, $property): ?ReflectionProperty
{
$properties = array_filter(
$this->_getClassProperties(get_class($object)),
static fn($p) => $p->getName() === $property
);
if (count($properties) !== 1) {
return null;
}
return current($properties);
}
/** /**
* @param $object * @param $object
* @param $property * @param $property
@ -138,18 +120,10 @@ class Validator
return $this->{sprintf('_validate%s', ucfirst($annotation[0]))}($property, ...$args_annotation); return $this->{sprintf('_validate%s', ucfirst($annotation[0]))}($property, ...$args_annotation);
} }
/**
* @return ReflectionProperty[]
* @throws ReflectionException
*/
private function _getClassProperties($class): array
{
return (new ReflectionClass($class))->getProperties();
}
private function _getPropertyAnnotations(ReflectionProperty $property): array private function _getPropertyAnnotations(ReflectionProperty $property): array
{ {
preg_match_all('#@(.*?)\n#s', $property->getDocComment(), $annotations); preg_match_all('#@validate (.*?)\n#s', $property->getDocComment(), $annotations);
return array_map(static fn($annotation) => trim($annotation), $annotations[1]); return array_map(static fn($annotation) => trim($annotation), $annotations[1]);
} }

View File

@ -5,6 +5,7 @@ use Shikiryu\SRSS\Builder\SRSSBuilder;
use Shikiryu\SRSS\Entity\Item; use Shikiryu\SRSS\Entity\Item;
use Shikiryu\SRSS\SRSS; use Shikiryu\SRSS\SRSS;
use Shikiryu\SRSS\SRSSTools; use Shikiryu\SRSS\SRSSTools;
use Shikiryu\SRSS\Validator\Formator;
class BasicBuilderTest extends TestCase class BasicBuilderTest extends TestCase
{ {
@ -42,8 +43,8 @@ class BasicBuilderTest extends TestCase
self::assertTrue($srss->isValid()); self::assertTrue($srss->isValid());
self::assertEquals($title, $srss->title); self::assertEquals('<![CDATA[ '.$title.' ]]>', $srss->title);
self::assertEquals($description, $srss->description); self::assertEquals('<![CDATA[ '.$description.' ]]>', $srss->description);
self::assertEquals($link, $srss->link); self::assertEquals($link, $srss->link);
$builder = new SRSSBuilder(); $builder = new SRSSBuilder();

View File

@ -12,10 +12,10 @@ class BasicReaderTest extends TestCase
public function testReadBasicRSS(): void public function testReadBasicRSS(): void
{ {
$rss = SRSS::read(__DIR__.'/resources/basic.xml'); $rss = SRSS::read(__DIR__.'/resources/basic.xml');
self::assertEquals('test Home Page', $rss->title); self::assertEquals('<![CDATA[ test Home Page ]]>', $rss->title);
$first_item = $rss->getFirst(); $first_item = $rss->getFirst();
self::assertNotNull($first_item); self::assertNotNull($first_item);
self::assertEquals('RSS Tutorial', $first_item->title); self::assertEquals('<![CDATA[ RSS Tutorial ]]>', $first_item->title);
self::assertTrue($rss->isValid()); self::assertTrue($rss->isValid());
} }
@ -23,20 +23,20 @@ class BasicReaderTest extends TestCase
public function testSpecificationExampleRSS(): void public function testSpecificationExampleRSS(): void
{ {
$rss = SRSS::read(__DIR__.'/resources/harvard.xml'); $rss = SRSS::read(__DIR__.'/resources/harvard.xml');
self::assertEquals('Liftoff News', $rss->title); self::assertEquals('<![CDATA[ Liftoff News ]]>', $rss->title);
self::assertEquals('http://liftoff.msfc.nasa.gov/', $rss->link); self::assertEquals('http://liftoff.msfc.nasa.gov/', $rss->link);
self::assertEquals('Liftoff to Space Exploration.', $rss->description); self::assertEquals('<![CDATA[ Liftoff to Space Exploration. ]]>', $rss->description);
self::assertEquals('en-us', $rss->language); self::assertEquals('en-us', $rss->language);
self::assertEquals('Tue, 10 Jun 2003 04:00:00 GMT', $rss->pubDate); self::assertEquals('Tue, 10 Jun 2003 04:00:00 UTC', $rss->pubDate);
self::assertEquals('Tue, 10 Jun 2003 09:41:01 GMT', $rss->lastBuildDate); self::assertEquals('Tue, 10 Jun 2003 09:41:01 UTC', $rss->lastBuildDate);
self::assertEquals('http://blogs.law.harvard.edu/tech/rss', $rss->docs); self::assertEquals('http://blogs.law.harvard.edu/tech/rss', $rss->docs);
self::assertEquals('Weblog Editor 2.0', $rss->generator); self::assertEquals('Weblog Editor 2.0', $rss->generator);
self::assertEquals('editor@example.com', $rss->managingEditor); self::assertEquals('editor@example.com', $rss->managingEditor);
self::assertEquals('webmaster@example.com', $rss->webMaster); self::assertEquals('webmaster@example.com', $rss->webMaster);
self::assertCount(4, $rss->items); self::assertCount(4, $rss->items);
self::assertEquals('Star City', $rss->getFirst()->title); self::assertEquals('<![CDATA[ Star City ]]>', $rss->getFirst()->title);
self::assertEquals('http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp', $rss->getLast()->link); self::assertEquals('http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp', $rss->getLast()->link);
self::assertEquals('Fri, 30 May 2003 11:06:42 GMT', $rss->getItem(2)->pubDate); self::assertEquals('Fri, 30 May 2003 11:06:42 UTC', $rss->getItem(2)->pubDate);
self::assertTrue($rss->isValid()); self::assertTrue($rss->isValid());
} }

View File

@ -86,13 +86,13 @@ class CompleteBuilderTest extends TestCase
$item->link = $item_link; $item->link = $item_link;
$item->description = $item_description; $item->description = $item_description;
$item->author = $item_author; $item->author = $item_author;
$item->category[] = $item_category; $item->category = $item_category;
$item->comments = $item_comments; $item->comments = $item_comments;
$item->enclosure = $item_enclosure; $item->enclosure = $item_enclosure;
$item->guid = $item_guid; $item->guid = $item_guid;
$item->pubDate = $item_pubdate; $item->pubDate = $item_pubdate;
$item->source = $item_source; $item->source = $item_source;
$item->medias[] = $item_media; $item->medias = $item_media;
$srss->addItem($item); $srss->addItem($item);

View File

@ -8,10 +8,10 @@ class MediaTest extends TestCase
public function testImages(): void public function testImages(): void
{ {
$rss = SRSS::read(__DIR__.'/resources/media/cnn.xml'); $rss = SRSS::read(__DIR__.'/resources/media/cnn.xml');
self::assertEquals('CNN.com - RSS Channel - Entertainment', $rss->title); self::assertEquals('<![CDATA[ CNN.com - RSS Channel - Entertainment ]]>', $rss->title);
$first_item = $rss->getFirst(); $first_item = $rss->getFirst();
self::assertEquals('Kirstie Alley, \'Cheers\' and \'Veronica\'s Closet\' star, dead at 71', $first_item->title); self::assertEquals('<![CDATA[ Kirstie Alley, \'Cheers\' and \'Veronica\'s Closet\' star, dead at 71 ]]>', $first_item->title);
self::assertEquals('https://cdn.cnn.com/cnnnext/dam/assets/221205172141-kirstie-alley-2005-super-169.jpg', $first_item->medias[0]->url); self::assertEquals('https://cdn.cnn.com/cnnnext/dam/assets/221205172141-kirstie-alley-2005-super-169.jpg', $first_item->medias[0]->url);
self::assertTrue($rss->isValid(), var_export($rss->channel->validated, true)); self::assertTrue($rss->isValid(), var_export($rss->channel->validated, true));
@ -20,7 +20,7 @@ class MediaTest extends TestCase
public function testMusicVideo(): void public function testMusicVideo(): void
{ {
$rss = SRSS::read(__DIR__.'/resources/media/music-video.xml'); $rss = SRSS::read(__DIR__.'/resources/media/music-video.xml');
self::assertEquals('Music Videos 101', $rss->title); self::assertEquals('<![CDATA[ Music Videos 101 ]]>', $rss->title);
self::assertCount(1, $rss->items); self::assertCount(1, $rss->items);

View File

@ -3,6 +3,7 @@
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use Shikiryu\SRSS\SRSS; use Shikiryu\SRSS\SRSS;
use Shikiryu\SRSS\SRSSTools; use Shikiryu\SRSS\SRSSTools;
use Shikiryu\SRSS\Validator\Formator;
class OriginalReaderSRSSTest extends TestCase class OriginalReaderSRSSTest extends TestCase
{ {
@ -19,7 +20,7 @@ class OriginalReaderSRSSTest extends TestCase
public function testOriginalReader(): void public function testOriginalReader(): void
{ {
$rss = SRSS::read($this->original); $rss = SRSS::read($this->original);
self::assertEquals('Liftoff News', $rss->title); self::assertEquals('<![CDATA[ Liftoff News ]]>', $rss->title);
$article1 = $rss->getItem(1); $article1 = $rss->getItem(1);
$articleFirst = $rss->getFirst(); $articleFirst = $rss->getFirst();
@ -27,7 +28,7 @@ class OriginalReaderSRSSTest extends TestCase
$links = []; $links = [];
foreach($rss as $article) { foreach($rss as $article) {
$links[] = sprintf('<a href="%s">%s %s</a>', $article->link, SRSSTools::formatDate('d/m/y', $article->pubDate), $article->title); $links[] = sprintf('<a href="%s">%s %s</a>', $article->link, SRSSTools::getRSSDate('d/m/y', $article->pubDate), $article->title);
} }
self::assertCount(4, $links, var_export($links, true)); self::assertCount(4, $links, var_export($links, true));

View File

@ -4,6 +4,7 @@ use PHPUnit\Framework\TestCase;
use Shikiryu\SRSS\Entity\Item; use Shikiryu\SRSS\Entity\Item;
use Shikiryu\SRSS\SRSS; use Shikiryu\SRSS\SRSS;
use Shikiryu\SRSS\SRSSTools; use Shikiryu\SRSS\SRSSTools;
use Shikiryu\SRSS\Validator\Formator;
class OriginalWriterSRSSTest extends TestCase class OriginalWriterSRSSTest extends TestCase
{ {
@ -38,8 +39,8 @@ class OriginalWriterSRSSTest extends TestCase
$rss->addItemBefore($firstItem); $rss->addItemBefore($firstItem);
self::assertCount(5, $rss->items, var_export($rss->items, true)); self::assertCount(5, $rss->items, var_export($rss->items, true));
self::assertEquals('title 0', $rss->getFirst()->title, var_export($rss->items, true)); self::assertEquals('<![CDATA[ title 0 ]]>', $rss->getFirst()->title, var_export($rss->items, true));
self::assertEquals('title 1', $rss->getItem(2)->title, var_export($rss->items, true)); self::assertEquals('<![CDATA[ title 1 ]]>', $rss->getItem(2)->title, var_export($rss->items, true));
} }
} }