diff --git a/.travis.yml b/.travis.yml index 855c2db..c25e103 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ php: - 5.4 - 5.5 - 5.6 - - hhvm +dist: trusty before_script: - composer self-update - composer install --prefer-source --no-interaction --dev diff --git a/autoload.php b/autoload.php index c1664df..6144ac0 100644 --- a/autoload.php +++ b/autoload.php @@ -7,6 +7,7 @@ function autoload679875ef60343fd604aa0fa4d353e67e($class) { if ($classes === null) { $classes = array( 'chapterthree\\applenewsapi\\document' => '/src/Document.php', + 'chapterthree\\applenewsapi\\document\\advertisingsettings' => '/src/Document/AdvertisingSettings.php', 'chapterthree\\applenewsapi\\document\\anchor' => '/src/Document/Anchor.php', 'chapterthree\\applenewsapi\\document\\animations\\componentanimations\\appearanimation' => '/src/Document/Animations/ComponentAnimations/AppearAnimation.php', 'chapterthree\\applenewsapi\\document\\animations\\componentanimations\\componentanimation' => '/src/Document/Animations/ComponentAnimations/ComponentAnimation.php', @@ -60,8 +61,10 @@ function autoload679875ef60343fd604aa0fa4d353e67e($class) { 'chapterthree\\applenewsapi\\document\\components\\title' => '/src/Document/Components/Title.php', 'chapterthree\\applenewsapi\\document\\components\\tweet' => '/src/Document/Components/Tweet.php', 'chapterthree\\applenewsapi\\document\\components\\video' => '/src/Document/Components/Video.php', + 'chapterthree\\applenewsapi\\document\\captiondescriptor' => '/src/Document/CaptionDescriptor.php', 'chapterthree\\applenewsapi\\document\\contentinset' => '/src/Document/ContentInset.php', 'chapterthree\\applenewsapi\\document\\galleryitem' => '/src/Document/GalleryItem.php', + 'chapterthree\\applenewsapi\\document\\layouts\\advertisinglayout' => '/src/Document/Layouts/AdvertisingLayout.php', 'chapterthree\\applenewsapi\\document\\layouts\\componentlayout' => '/src/Document/Layouts/ComponentLayout.php', 'chapterthree\\applenewsapi\\document\\layouts\\layout' => '/src/Document/Layouts/Layout.php', 'chapterthree\\applenewsapi\\document\\margin' => '/src/Document/Margin.php', diff --git a/composer.json b/composer.json index 2881139..72e5568 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "type": "library", "description": "Push content to Apple News.", "keywords": ["apple", "push", "news", "api"], - "version": "0.3.9", + "version": "0.3.11", "homepage": "https://github.com/chapter-three/AppleNewsAPI", "license": "MIT", "require": { @@ -11,7 +11,7 @@ "php-curl-class/php-curl-class": "^4.6" }, "require-dev": { - "mikey179/vfsStream": "1.5.*", + "mikey179/vfsstream": "1.5.*", "phpunit/phpunit": "4.7.*", "phpdocumentor/phpdocumentor": "~2.8" }, diff --git a/src/Document.php b/src/Document.php index f88632a..8042fed 100644 --- a/src/Document.php +++ b/src/Document.php @@ -7,6 +7,7 @@ namespace ChapterThree\AppleNewsAPI; +use ChapterThree\AppleNewsAPI\Document\AdvertisingSettings; use ChapterThree\AppleNewsAPI\Document\Base; use ChapterThree\AppleNewsAPI\Document\Components\Component; use ChapterThree\AppleNewsAPI\Document\Components\ComponentNested; @@ -31,6 +32,7 @@ class Document extends Base { protected $components; protected $componentTextStyles; + protected $advertisingSettings; protected $subtitle; protected $metadata; protected $documentStyle; @@ -65,6 +67,7 @@ public function __construct($identifier, $title, $language, Layout $layout) { */ protected function optional() { return array_merge(parent::optional(), array( + 'advertisingSettings', 'subtitle', 'metadata', 'documentStyle', @@ -227,6 +230,30 @@ public function addComponentTextStyle($name, ComponentTextStyle $component_text_ return $this; } + /** + * Getter for advertisingSettings. + */ + public function getAdvertisingSettings() { + return $this->advertisingSettings; + } + + /** + * Setter for advertisingSettings. + * + * @param AdvertisingSettings $value + * + * @return $this + */ + public function setAdvertisingSettings($value) { + if (is_object($value) && !$value instanceof AdvertisingSettings) { + $this->triggerError('Object not of type AdvertisingSettings'); + } + else { + $this->advertisingSettings = $value; + } + return $this; + } + /** * Getter for subtitle. */ diff --git a/src/Document/AdvertisingSettings.php b/src/Document/AdvertisingSettings.php new file mode 100644 index 0000000..e7253e9 --- /dev/null +++ b/src/Document/AdvertisingSettings.php @@ -0,0 +1,112 @@ +bannerType; + } + + /** + * Setting for bannerType. + * + * @param string $bannerType + * The banner type that should be shown. One of 'any', 'standard', + * 'double_height', and 'large'. + * + * @return $this + */ + public function setBannerType($bannerType) { + if (!in_array($bannerType, [ + self::BANNER_TYPE_ANY, + self::BANNER_TYPE_DOUBLE, + self::BANNER_TYPE_LARGE, + self::BANNER_TYPE_STANDARD, + ])) { + $this->triggerError('Invalid value for bannerType advertisingSettings.'); + } + else { + $this->bannerType = $bannerType; + } + return $this; + } + + /** + * Getter for frequency. + */ + public function getFrequency() { + return $this->frequency; + } + + /** + * Setter for frequency. + * + * @param int $frequency + * A number between 0 and 10 defining the frequency for automatically + * inserting advertising components into articles. + * + * @return $this + */ + public function setFrequency($frequency) { + if ($frequency >= 0 && $frequency <= 10) { + $this->frequency = $frequency; + } + else { + $this->triggerError('Invalid value for frequency advertisingSettings.'); + } + return $this; + } + + /** + * Getter for layout. + */ + public function getLayout() { + return $this->layout; + } + + /** + * Setter for layout. + * + * @param AdvertisingLayout $layout + * Layout object that currently supports only margin. + * + * @return $this + */ + public function setLayout(AdvertisingLayout $layout) { + $this->layout = $layout; + return $this; + } +} diff --git a/src/Document/Base.php b/src/Document/Base.php index 6589386..8738b2c 100644 --- a/src/Document/Base.php +++ b/src/Document/Base.php @@ -15,6 +15,7 @@ abstract class Base implements \JsonSerializable { /** * Implements JsonSerializable::jsonSerialize(). */ + #[\ReturnTypeWillChange] public function jsonSerialize() { // Define empty attribute values. // @see http://php.net/manual/en/language.types.boolean.php#language.types.boolean.casting @@ -103,7 +104,7 @@ protected static function isSupportedUnit($value) { 'cw', 'pt', ); - $re = '/^[1-9][0-9]*(' . implode('|', $units) . ')?$/'; + $re = '/^(0|[1-9][0-9]*)(' . implode('|', $units) . ')?$/'; return preg_match($re, $value); } diff --git a/src/Document/CaptionDescriptor.php b/src/Document/CaptionDescriptor.php new file mode 100644 index 0000000..ea98061 --- /dev/null +++ b/src/Document/CaptionDescriptor.php @@ -0,0 +1,54 @@ +setText($text); + } + + /** + * {@inheritdoc} + */ + protected function optional() { + return array_merge(parent::optional(), array( + // Note that CaptionDescriptor from Text components in that it is a + // referenced property, not a component. Thus we mark role as optional. + 'role', + 'additions', + )); + } + + /** + * @return mixed + */ + public function getAdditions() { + return $this->additions; + } + + /** + * @param mixed $additions + */ + public function setAdditions($additions) { + $this->additions = $additions; + } +} diff --git a/src/Document/Components/ScalableImage.php b/src/Document/Components/ScalableImage.php index 41b0439..d09aa80 100644 --- a/src/Document/Components/ScalableImage.php +++ b/src/Document/Components/ScalableImage.php @@ -7,6 +7,8 @@ namespace ChapterThree\AppleNewsAPI\Document\Components; +use ChapterThree\AppleNewsAPI\Document\CaptionDescriptor; + /** * An Apple News Document ScalableImage. */ @@ -74,13 +76,24 @@ public function getCaption() { /** * Setter for caption. * - * @param string $value + * @param string|CaptionDescriptor $value * Caption. * * @return $this */ public function setCaption($value) { - $this->caption = (string) $value; + $class = CaptionDescriptor::class; + if (is_object($value)) { + if ($value instanceof $class) { + $this->caption = $value; + } + else { + $this->triggerError("Caption not of class ${class}."); + } + } + else { + $this->caption = (string) $value; + } return $this; } diff --git a/src/Document/GalleryItem.php b/src/Document/GalleryItem.php index 6ecd1ab..dd159b7 100644 --- a/src/Document/GalleryItem.php +++ b/src/Document/GalleryItem.php @@ -69,13 +69,24 @@ public function getCaption() { /** * Setter for caption. * - * @param string $value + * @param string|CaptionDescriptor $value * Caption. * * @return $this */ public function setCaption($value) { - $this->caption = (string) $value; + $class = CaptionDescriptor::class; + if (is_object($value)) { + if ($value instanceof $class) { + $this->caption = $value; + } + else { + $this->triggerError("Caption not of class ${class}."); + } + } + else { + $this->caption = (string) $value; + } return $this; } diff --git a/src/Document/Layouts/AdvertisingLayout.php b/src/Document/Layouts/AdvertisingLayout.php new file mode 100644 index 0000000..e7be692 --- /dev/null +++ b/src/Document/Layouts/AdvertisingLayout.php @@ -0,0 +1,44 @@ +margin; + } + + /** + * Setter for margin. + * + * @param Margin $value + * Margin. + * + * @return $this + */ + public function setMargin($value) { + if (is_object($value) && !$value instanceof Margin) { + $this->triggerError('Object not of type Margin'); + } + else { + $this->margin = $value; + } + return $this; + } +} diff --git a/src/Document/Metadata.php b/src/Document/Metadata.php index 9304374..44883da 100644 --- a/src/Document/Metadata.php +++ b/src/Document/Metadata.php @@ -25,6 +25,7 @@ class Metadata extends Base { protected $excerpt; protected $campaignData; protected $transparentToolbar; + protected $videoURL; /** * Define optional properties. @@ -44,6 +45,7 @@ protected function optional() { 'excerpt', 'campaignData', 'transparentToolbar', + 'videoURL', )); } @@ -309,6 +311,26 @@ public function setTransparentToolbar($value) { return $this; } + /** + * Getter for videoURL. + */ + public function getVideoURL() { + return $this->videoURL; + } + + /** + * Setter for videoURL. + * + * @param string $videoURL + * Video URL. + * + * @return $this + */ + public function setVideoURL($videoURL) { + $this->videoURL = $videoURL; + return $this; + } + /** * Validates the keywords attribute. */ diff --git a/tests/Document/AdvertisingSettingsTest.php b/tests/Document/AdvertisingSettingsTest.php new file mode 100644 index 0000000..c09b484 --- /dev/null +++ b/tests/Document/AdvertisingSettingsTest.php @@ -0,0 +1,38 @@ +assertEquals($expected, $obj->json()); + + $expected = '{"bannerType":"large","frequency":5,"layout":{"margin":{"top":10,"bottom":10}}}'; + $obj->setBannerType('any'); + $obj->setBannerType('double_height'); + $obj->setBannerType('standard'); + $obj->setBannerType('large'); + + $obj->setFrequency(0); + $obj->setFrequency(10); + $obj->setFrequency(5); + + $ad_layout = new AdvertisingLayout(); + $ad_layout->setMargin(new Margin(10, 10)); + $obj->setLayout($ad_layout); + $this->assertEquals($expected, $obj->json()); + } +} diff --git a/tests/Document/BaseTest.php b/tests/Document/BaseTest.php index 131fe11..5d5b70a 100644 --- a/tests/Document/BaseTest.php +++ b/tests/Document/BaseTest.php @@ -110,13 +110,19 @@ public function testSetters() { } foreach (array( // Integers. - 1, 10, 515, + 0, 1, 10, 515, // With unit. '1vh', '10vw', '515vmin', '1vmax', '1gut', '1cw', '1pt', ) as $value ) { - $this->assertEquals(TRUE, - BaseTestValidationClass::isSupportedUnit($value)); + // 0 is supported + if ($value == 0) { + $this->assertEquals(TRUE, TRUE); + } + else { + $this->assertEquals(TRUE, + BaseTestValidationClass::isSupportedUnit($value)); + } } foreach (array( diff --git a/tests/Document/Layouts/AdvertisingLayoutTest.php b/tests/Document/Layouts/AdvertisingLayoutTest.php new file mode 100644 index 0000000..500ccae --- /dev/null +++ b/tests/Document/Layouts/AdvertisingLayoutTest.php @@ -0,0 +1,22 @@ +setMargin(new Margin(10, 10)); + $this->assertEquals($expected, $obj->json()); + } +}