From 44c48330694eaebff86df2f16f03434040f86ef0 Mon Sep 17 00:00:00 2001 From: Clement Desmidt Date: Mon, 17 Apr 2023 14:28:01 +0200 Subject: [PATCH] :lock: Add formator Closes #3 --- src/Entity/Channel.php | 82 ++++++---- src/Entity/Channel/Category.php | 9 +- src/Entity/Channel/Cloud.php | 21 +-- src/Entity/Channel/Image.php | 41 +++-- src/Entity/Item.php | 41 ++--- src/Entity/Item/Category.php | 9 +- src/Entity/Item/Enclosure.php | 15 +- src/Entity/Item/Source.php | 10 +- src/Entity/Media/Content.php | 68 ++++---- src/Parser/ItemParser.php | 2 +- src/Parser/SRSSParser.php | 2 +- src/SRSS.php | 6 +- src/SRSSTools.php | 199 +---------------------- src/Validator/Formator.php | 268 +++++++++++++++++++++++++++++++ src/Validator/HasValidator.php | 53 ++++++ src/Validator/ReadProperties.php | 39 +++++ src/Validator/Validator.php | 32 +--- tests/BasicBuilderTest.php | 5 +- tests/BasicReaderTest.php | 16 +- tests/CompleteBuilderTest.php | 4 +- tests/MediaTest.php | 6 +- tests/OriginalReaderSRSSTest.php | 5 +- tests/OriginalWriterSRSSTest.php | 5 +- 23 files changed, 571 insertions(+), 367 deletions(-) create mode 100644 src/Validator/Formator.php create mode 100644 src/Validator/ReadProperties.php diff --git a/src/Entity/Channel.php b/src/Entity/Channel.php index 59aee30..c745efd 100644 --- a/src/Entity/Channel.php +++ b/src/Entity/Channel.php @@ -15,81 +15,93 @@ use Shikiryu\SRSS\Validator\Validator; class Channel extends HasValidator implements SRSSElement { /** - * @required - * @nohtml + * @validate required + * @format html */ - public string $title = ''; + protected string $title = ''; /** - * @required - * @url + * @validate required + * @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[] */ - 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 */ - public ?Cloud $cloud = null; + protected ?Cloud $cloud = null; /** - * @int + * @validate int + * @format int */ - public ?string $ttl = null; - public ?Image $image = null; - public ?string $rating = null; + protected ?string $ttl = null; + protected ?Image $image = null; + protected ?string $rating = null; /** * @var string|null * The purpose of the 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 diff --git a/src/Entity/Channel/Category.php b/src/Entity/Channel/Category.php index 6923c47..724da35 100644 --- a/src/Entity/Channel/Category.php +++ b/src/Entity/Channel/Category.php @@ -10,13 +10,14 @@ use Shikiryu\SRSS\Validator\Validator; 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 { diff --git a/src/Entity/Channel/Cloud.php b/src/Entity/Channel/Cloud.php index 9d379f3..8f341f0 100644 --- a/src/Entity/Channel/Cloud.php +++ b/src/Entity/Channel/Cloud.php @@ -10,25 +10,26 @@ use Shikiryu\SRSS\Validator\Validator; 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 { diff --git a/src/Entity/Channel/Image.php b/src/Entity/Channel/Image.php index a4dfaaa..7f93cf7 100644 --- a/src/Entity/Channel/Image.php +++ b/src/Entity/Channel/Image.php @@ -10,32 +10,41 @@ use Shikiryu\SRSS\Validator\Validator; class Image extends HasValidator implements SRSSElement { /** - * @required - * @url + * @validate required + * @validate url + * @format url */ - public ?string $url = null; + protected ?string $url = null; /** - * @required - * @nohtml + * @validate required + * @validate nohtml + * @format nohtml */ - public ?string $title = null; + protected ?string $title = null; /** - * @required - * @url + * @validate required + * @validate url + * @format url */ - public ?string $link = null; + protected ?string $link = null; /** - * @int - * @max 144 + * @validate int + * @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 - * @max 400 + * @format int + * @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 { diff --git a/src/Entity/Item.php b/src/Entity/Item.php index 3faa0fd..8e43f6a 100644 --- a/src/Entity/Item.php +++ b/src/Entity/Item.php @@ -16,50 +16,55 @@ use Shikiryu\SRSS\Validator\Validator; class Item extends HasValidator implements SRSSElement { /** - * @requiredOr description - * @nohtml + * @validate requiredOr description + * @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[] */ - public ?array $category = null; + protected ?array $category = null; /** - * @url + * @validate url + * @format url */ - public ?string $comments = null; + protected ?string $comments = null; /** * @var Enclosure|null */ - public ?Enclosure $enclosure = null; - public ?string $guid = null; + protected ?Enclosure $enclosure = null; + protected ?string $guid = null; /** - * @date + * @validate date + * @format date */ - public ?string $pubDate = null; + protected ?string $pubDate = null; /** * @var Source|null */ - public ?Source $source = null; + protected ?Source $source = null; /** * @var Content[] * @contentMedia */ - public array $medias = []; + protected array $medias = []; public function isValid(): bool { diff --git a/src/Entity/Item/Category.php b/src/Entity/Item/Category.php index fe9b493..b0f2efa 100644 --- a/src/Entity/Item/Category.php +++ b/src/Entity/Item/Category.php @@ -10,13 +10,14 @@ use Shikiryu\SRSS\Validator\Validator; 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 { diff --git a/src/Entity/Item/Enclosure.php b/src/Entity/Item/Enclosure.php index fa9d8fb..81835c9 100644 --- a/src/Entity/Item/Enclosure.php +++ b/src/Entity/Item/Enclosure.php @@ -10,19 +10,22 @@ use Shikiryu\SRSS\Validator\Validator; 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 { diff --git a/src/Entity/Item/Source.php b/src/Entity/Item/Source.php index 355a1e0..588537d 100644 --- a/src/Entity/Item/Source.php +++ b/src/Entity/Item/Source.php @@ -10,14 +10,16 @@ use Shikiryu\SRSS\Validator\Validator; 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 { diff --git a/src/Entity/Media/Content.php b/src/Entity/Media/Content.php index 0cbacdc..907c684 100644 --- a/src/Entity/Media/Content.php +++ b/src/Entity/Media/Content.php @@ -10,61 +10,73 @@ use Shikiryu\SRSS\Validator\Validator; 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 { diff --git a/src/Parser/ItemParser.php b/src/Parser/ItemParser.php index e401910..6d1e199 100644 --- a/src/Parser/ItemParser.php +++ b/src/Parser/ItemParser.php @@ -27,7 +27,7 @@ class ItemParser extends DomDocument if ($child->nodeName === 'media:group') { self::_loadChildAttributes($item, $child); } elseif ($child->nodeName === 'media:content') { - $item->medias[] = MediaContentParser::read($child); + $item->medias = MediaContentParser::read($child); } elseif ($child->nodeName === 'category') { $category = new Item\Category(); foreach($child->attributes as $attribute) { diff --git a/src/Parser/SRSSParser.php b/src/Parser/SRSSParser.php index 684d450..b85c9ec 100644 --- a/src/Parser/SRSSParser.php +++ b/src/Parser/SRSSParser.php @@ -109,7 +109,7 @@ class SRSSParser extends DomDocument $category->{$attribute->name} = $attribute->value; } $category->value = $child->nodeValue; - $this->doc->channel->category[] = $category; + $this->doc->channel->category = $category; } else { $this->doc->channel->{$child->nodeName} = $child->nodeValue; } diff --git a/src/SRSS.php b/src/SRSS.php index 082fc54..4296286 100644 --- a/src/SRSS.php +++ b/src/SRSS.php @@ -15,6 +15,7 @@ use Shikiryu\SRSS\Exception\PropertyNotFoundException; use Shikiryu\SRSS\Exception\SRSSException; use Shikiryu\SRSS\Exception\UnreadableRSSException; use Shikiryu\SRSS\Parser\SRSSParser; +use Shikiryu\SRSS\Validator\Formator; use Shikiryu\SRSS\Validator\Validator; /** @@ -126,11 +127,14 @@ class SRSS implements Iterator throw new PropertyNotFoundException(Channel::class, $name); } if ((new Validator())->isValidValueForObjectProperty($this->channel, $name, $val)) { + if (SRSSTools::getPropertyType(Channel::class, $name) === 'array') { - $this->channel->{$name}[] = $val; + $this->channel->{$name} = $val; } else { + $val = is_string($val) ? (new Formator())->formatValue($this->channel, $name, $val) : $val; $this->channel->{$name} = $val; } + } } diff --git a/src/SRSSTools.php b/src/SRSSTools.php index 5ab55f1..a3f5e93 100644 --- a/src/SRSSTools.php +++ b/src/SRSSTools.php @@ -2,210 +2,27 @@ namespace Shikiryu\SRSS; -use DateTime; -use DateTimeInterface; use ReflectionProperty; +use Shikiryu\SRSS\Validator\Formator; class SRSSTools { + /** + * @throws \ReflectionException + */ public static function getPropertyType($object, $property): ?string { $rp = new ReflectionProperty($object, $property); 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 $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 + * @param string $string * * @return string */ - public static function getRSSDate(string $date, string $format = ''): string + public static function getRSSDate(string $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)); + return Formator::checkDate($string); } - - /** - * 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('', 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; - } -} \ No newline at end of file +} diff --git a/src/Validator/Formator.php b/src/Validator/Formator.php new file mode 100644 index 0000000..b81ced9 --- /dev/null +++ b/src/Validator/Formator.php @@ -0,0 +1,268 @@ +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, '')) { + return $check; + } + + return sprintf('', 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; + } +} diff --git a/src/Validator/HasValidator.php b/src/Validator/HasValidator.php index 96f7de3..5017501 100644 --- a/src/Validator/HasValidator.php +++ b/src/Validator/HasValidator.php @@ -2,10 +2,63 @@ namespace Shikiryu\SRSS\Validator; +use Shikiryu\SRSS\Exception\PropertyNotFoundException; +use Shikiryu\SRSS\Exception\SRSSException; +use Shikiryu\SRSS\SRSSTools; + abstract class HasValidator { /** * @var bool[] */ 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; + } } \ No newline at end of file diff --git a/src/Validator/ReadProperties.php b/src/Validator/ReadProperties.php new file mode 100644 index 0000000..d71459d --- /dev/null +++ b/src/Validator/ReadProperties.php @@ -0,0 +1,39 @@ +_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(); + } +} \ No newline at end of file diff --git a/src/Validator/Validator.php b/src/Validator/Validator.php index dc981f1..7bdd03e 100644 --- a/src/Validator/Validator.php +++ b/src/Validator/Validator.php @@ -11,29 +11,11 @@ use Shikiryu\SRSS\Entity\Media\Content; class Validator { + use ReadProperties; + 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 $property @@ -138,18 +120,10 @@ class Validator 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 { - 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]); } diff --git a/tests/BasicBuilderTest.php b/tests/BasicBuilderTest.php index 9a84ddd..44961be 100644 --- a/tests/BasicBuilderTest.php +++ b/tests/BasicBuilderTest.php @@ -5,6 +5,7 @@ use Shikiryu\SRSS\Builder\SRSSBuilder; use Shikiryu\SRSS\Entity\Item; use Shikiryu\SRSS\SRSS; use Shikiryu\SRSS\SRSSTools; +use Shikiryu\SRSS\Validator\Formator; class BasicBuilderTest extends TestCase { @@ -42,8 +43,8 @@ class BasicBuilderTest extends TestCase self::assertTrue($srss->isValid()); - self::assertEquals($title, $srss->title); - self::assertEquals($description, $srss->description); + self::assertEquals('', $srss->title); + self::assertEquals('', $srss->description); self::assertEquals($link, $srss->link); $builder = new SRSSBuilder(); diff --git a/tests/BasicReaderTest.php b/tests/BasicReaderTest.php index 1f987c5..522d878 100644 --- a/tests/BasicReaderTest.php +++ b/tests/BasicReaderTest.php @@ -12,10 +12,10 @@ class BasicReaderTest extends TestCase public function testReadBasicRSS(): void { $rss = SRSS::read(__DIR__.'/resources/basic.xml'); - self::assertEquals('test Home Page', $rss->title); + self::assertEquals('', $rss->title); $first_item = $rss->getFirst(); self::assertNotNull($first_item); - self::assertEquals('RSS Tutorial', $first_item->title); + self::assertEquals('', $first_item->title); self::assertTrue($rss->isValid()); } @@ -23,20 +23,20 @@ class BasicReaderTest extends TestCase public function testSpecificationExampleRSS(): void { $rss = SRSS::read(__DIR__.'/resources/harvard.xml'); - self::assertEquals('Liftoff News', $rss->title); + self::assertEquals('', $rss->title); self::assertEquals('http://liftoff.msfc.nasa.gov/', $rss->link); - self::assertEquals('Liftoff to Space Exploration.', $rss->description); + self::assertEquals('', $rss->description); self::assertEquals('en-us', $rss->language); - self::assertEquals('Tue, 10 Jun 2003 04:00:00 GMT', $rss->pubDate); - self::assertEquals('Tue, 10 Jun 2003 09:41:01 GMT', $rss->lastBuildDate); + self::assertEquals('Tue, 10 Jun 2003 04:00:00 UTC', $rss->pubDate); + 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('Weblog Editor 2.0', $rss->generator); self::assertEquals('editor@example.com', $rss->managingEditor); self::assertEquals('webmaster@example.com', $rss->webMaster); self::assertCount(4, $rss->items); - self::assertEquals('Star City', $rss->getFirst()->title); + self::assertEquals('', $rss->getFirst()->title); 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()); } diff --git a/tests/CompleteBuilderTest.php b/tests/CompleteBuilderTest.php index 06c6b17..f8bcb80 100644 --- a/tests/CompleteBuilderTest.php +++ b/tests/CompleteBuilderTest.php @@ -86,13 +86,13 @@ class CompleteBuilderTest extends TestCase $item->link = $item_link; $item->description = $item_description; $item->author = $item_author; - $item->category[] = $item_category; + $item->category = $item_category; $item->comments = $item_comments; $item->enclosure = $item_enclosure; $item->guid = $item_guid; $item->pubDate = $item_pubdate; $item->source = $item_source; - $item->medias[] = $item_media; + $item->medias = $item_media; $srss->addItem($item); diff --git a/tests/MediaTest.php b/tests/MediaTest.php index 0abb611..afb0c7c 100644 --- a/tests/MediaTest.php +++ b/tests/MediaTest.php @@ -8,10 +8,10 @@ class MediaTest extends TestCase public function testImages(): void { $rss = SRSS::read(__DIR__.'/resources/media/cnn.xml'); - self::assertEquals('CNN.com - RSS Channel - Entertainment', $rss->title); + self::assertEquals('', $rss->title); $first_item = $rss->getFirst(); - self::assertEquals('Kirstie Alley, \'Cheers\' and \'Veronica\'s Closet\' star, dead at 71', $first_item->title); + self::assertEquals('', $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::assertTrue($rss->isValid(), var_export($rss->channel->validated, true)); @@ -20,7 +20,7 @@ class MediaTest extends TestCase public function testMusicVideo(): void { $rss = SRSS::read(__DIR__.'/resources/media/music-video.xml'); - self::assertEquals('Music Videos 101', $rss->title); + self::assertEquals('', $rss->title); self::assertCount(1, $rss->items); diff --git a/tests/OriginalReaderSRSSTest.php b/tests/OriginalReaderSRSSTest.php index 0b1bd7a..86d7bd8 100644 --- a/tests/OriginalReaderSRSSTest.php +++ b/tests/OriginalReaderSRSSTest.php @@ -3,6 +3,7 @@ use PHPUnit\Framework\TestCase; use Shikiryu\SRSS\SRSS; use Shikiryu\SRSS\SRSSTools; +use Shikiryu\SRSS\Validator\Formator; class OriginalReaderSRSSTest extends TestCase { @@ -19,7 +20,7 @@ class OriginalReaderSRSSTest extends TestCase public function testOriginalReader(): void { $rss = SRSS::read($this->original); - self::assertEquals('Liftoff News', $rss->title); + self::assertEquals('', $rss->title); $article1 = $rss->getItem(1); $articleFirst = $rss->getFirst(); @@ -27,7 +28,7 @@ class OriginalReaderSRSSTest extends TestCase $links = []; foreach($rss as $article) { - $links[] = sprintf('%s %s', $article->link, SRSSTools::formatDate('d/m/y', $article->pubDate), $article->title); + $links[] = sprintf('%s %s', $article->link, SRSSTools::getRSSDate('d/m/y', $article->pubDate), $article->title); } self::assertCount(4, $links, var_export($links, true)); diff --git a/tests/OriginalWriterSRSSTest.php b/tests/OriginalWriterSRSSTest.php index c57cc73..8380130 100644 --- a/tests/OriginalWriterSRSSTest.php +++ b/tests/OriginalWriterSRSSTest.php @@ -4,6 +4,7 @@ use PHPUnit\Framework\TestCase; use Shikiryu\SRSS\Entity\Item; use Shikiryu\SRSS\SRSS; use Shikiryu\SRSS\SRSSTools; +use Shikiryu\SRSS\Validator\Formator; class OriginalWriterSRSSTest extends TestCase { @@ -38,8 +39,8 @@ class OriginalWriterSRSSTest extends TestCase $rss->addItemBefore($firstItem); self::assertCount(5, $rss->items, var_export($rss->items, true)); - self::assertEquals('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('', $rss->getFirst()->title, var_export($rss->items, true)); + self::assertEquals('', $rss->getItem(2)->title, var_export($rss->items, true)); } } \ No newline at end of file