diff --git a/src/ContextTypes/AbstractContext.php b/src/ContextTypes/AbstractContext.php index 5d1d474..e958c5c 100644 --- a/src/ContextTypes/AbstractContext.php +++ b/src/ContextTypes/AbstractContext.php @@ -168,7 +168,7 @@ protected function setProperty($key, $property, $value = null) } // Map properties to object - if (is_array($value)) { + if ($property !== null && is_array($property) && is_array($value)) { return $this->properties[$key] = $this->mapProperty($property, $value); } diff --git a/src/ContextTypes/Article.php b/src/ContextTypes/Article.php index 4114379..b25a276 100644 --- a/src/ContextTypes/Article.php +++ b/src/ContextTypes/Article.php @@ -2,41 +2,35 @@ namespace JsonLd\ContextTypes; -class Article extends AbstractContext +class Article extends CreativeWork { /** * Property structure + * reference: https://schema.org/Article (alphabetical order) * * @var array */ - protected $structure = [ - 'name' => null, - 'url' => null, - 'description' => null, - - 'image' => ImageObject::class, - 'video' => VideoObject::class, - 'thumbnailUrl' => null, - 'text' => null, - 'review' => Review::class, - 'publisher' => Organization::class, - 'keywords' => null, - 'inLanguage' => null, - 'dateCreated' => null, - 'dateModified' => null, - 'datePublished' => null, - 'author' => Person::class, - 'aggregateRating' => AggregateRating::class, - + private $extendedStructure = [ 'articleBody' => null, 'articleSection' => null, 'pageEnd' => null, 'pageStart' => null, 'pagination' => null, + 'wordCount' => null, 'mainEntityOfPage' => WebPage::class, - 'headline' => null, ]; + /** + * Constructor. Merges extendedStructure up + * + * @param array $attributes + * @param array $extendedStructure + */ + public function __construct(array $attributes, array $extendedStructure = []) + { + parent::__construct($attributes, array_merge($this->structure, $this->extendedStructure, $extendedStructure)); + } + /** * Set the description attribute. * diff --git a/src/ContextTypes/Comment.php b/src/ContextTypes/Comment.php new file mode 100644 index 0000000..51565ff --- /dev/null +++ b/src/ContextTypes/Comment.php @@ -0,0 +1,30 @@ + null, + 'upvoteCount' => null, + ]; + + /** + * Constructor. Merges extendedStructure up + * + * @param array $attributes + * @param array $extendedStructure + */ + public function __construct(array $attributes, array $extendedStructure = []) + { + parent::__construct( + $attributes, array_merge($this->structure, $this->extendedStructure, $extendedStructure) + ); + } +} diff --git a/src/ContextTypes/CreativeWork.php b/src/ContextTypes/CreativeWork.php index 338a0e2..660ce1a 100644 --- a/src/ContextTypes/CreativeWork.php +++ b/src/ContextTypes/CreativeWork.php @@ -2,25 +2,29 @@ namespace JsonLd\ContextTypes; -class CreativeWork extends AbstractContext +class CreativeWork extends Thing { /** * Property structure + * reference: https://schema.org/CreativeWork (alphabetical order) * * @var array */ - protected $structure = [ - 'name' => null, - 'url' => null, + private $extendedStructure = [ + 'about' => Thing::class, 'aggregateRating' => AggregateRating::class, + 'alternativeHeadline' => null, 'author' => Person::class, + 'comment' => Comment::class, + 'commentCount' => null, 'creator' => Person::class, 'dateCreated' => null, 'dateModified' => null, 'datePublished' => null, 'headline' => null, - 'image' => ImageObject::class, 'inLanguage' => null, + 'keywords' => null, + 'mainEntity' => Thing::class, 'publisher' => Organization::class, 'review' => Review::class, 'text' => null, @@ -28,6 +32,19 @@ class CreativeWork extends AbstractContext 'video' => VideoObject::class, ]; + /** + * Constructor. Merges extendedStructure up + * + * @param array $attributes + * @param array $extendedStructure + */ + public function __construct(array $attributes, array $extendedStructure = []) + { + parent::__construct( + $attributes, array_merge($this->structure, $this->extendedStructure, $extendedStructure) + ); + } + /** * Set the article body attribute. * @@ -38,4 +55,21 @@ protected function setTextAttribute($txt) { return $this->truncate($txt, 260); } -} \ No newline at end of file + + /** + * Set the comments + * + * @param array $items + * @return array + */ + protected function setCommentAttribute($items) + { + if (is_array($items) === false) { + return $items; + } + + return array_map(function ($item) { + return $this->getNestedContext(Comment::class, $item); + }, $items); + } +} diff --git a/src/ContextTypes/Person.php b/src/ContextTypes/Person.php index b663042..76b0858 100644 --- a/src/ContextTypes/Person.php +++ b/src/ContextTypes/Person.php @@ -2,14 +2,64 @@ namespace JsonLd\ContextTypes; -class Person extends AbstractContext +class Person extends Thing { /** * Property structure + * reference: https://schema.org/Person (alphabetical order) * * @var array */ - protected $structure = [ - 'name' => null, + protected $extendedStructure = [ + 'additionalName' => null, + 'address' => null, // PostalAddress or Text + 'affiliation' => null, + 'alumniOf' => null, + 'award' => null, + 'birthDate' => null, + 'birthPlace' => Place::class, + 'brand' => null, + 'children' => Person::class, + 'colleague' => null, + 'contactPoint' => null, + 'deathDate' => null, + 'deathPlace' => Place::class, + 'duns' => null, + 'email' => null, + 'familyName' => null, + 'faxNumber' => null, + 'follows' => Person::class, + 'homeLocation' => Place::class, + 'givenName' => null, + 'jobTitle' => null, + 'parent' => Person::class, + 'telephone' => null, + 'workLocation' => Place::class, ]; -} \ No newline at end of file + + /** + * Constructor. Merges extendedStructure up + * + * @param array $attributes + * @param array $extendedStructure + */ + public function __construct(array $attributes, array $extendedStructure = []) + { + parent::__construct($attributes, array_merge($this->structure, $this->extendedStructure, $extendedStructure)); + } + + /** + * Set the address + * + * @param array $items + * @return array + */ + protected function setAddressAttribute($items) + { + if (is_array($items) === false) { + return $items; + } + + return $this->getNestedContext(PostalAddress::class, $items); + } +} diff --git a/src/ContextTypes/Place.php b/src/ContextTypes/Place.php index 37e568e..e22865a 100644 --- a/src/ContextTypes/Place.php +++ b/src/ContextTypes/Place.php @@ -2,17 +2,29 @@ namespace JsonLd\ContextTypes; -class Place extends AbstractContext +class Place extends Thing { /** * Property structure * * @var array */ - protected $structure = [ - 'name' => null, + protected $extendedStructure = [ 'address' => PostalAddress::class, 'review' => Review::class, 'aggregateRating' => AggregateRating::class, ]; + + + /** + * Constructor. Merges extendedStructure up + * + * @param array $attributes + * @param array $extendedStructure + */ + public function __construct(array $attributes, array $extendedStructure = []) + { + parent::__construct($attributes, array_merge($this->structure, $this->extendedStructure, $extendedStructure)); + } + } diff --git a/src/ContextTypes/Sculpture.php b/src/ContextTypes/Sculpture.php new file mode 100644 index 0000000..49dc38f --- /dev/null +++ b/src/ContextTypes/Sculpture.php @@ -0,0 +1,26 @@ +structure, $this->extendedStructure, $extendedStructure) + ); + } +} diff --git a/src/ContextTypes/Thing.php b/src/ContextTypes/Thing.php index e241537..3e8935b 100644 --- a/src/ContextTypes/Thing.php +++ b/src/ContextTypes/Thing.php @@ -6,14 +6,17 @@ class Thing extends AbstractContext { /** * Property structure + * reference: https://schema.org/Thing (alphabetical order) * * @var array */ protected $structure = [ - 'name' => null, 'alternateName' => null, 'description' => null, - 'image' => null, + 'image' => ImageObject::class, + 'mainEntityOfPage' => WebPage::class, + 'name' => null, + 'sameAs' => null, 'url' => null, ]; @@ -40,4 +43,4 @@ protected function setTypeAttribute($type) // TODO: Add type validation return $type; } -} \ No newline at end of file +} diff --git a/tests/ContextTypes/ArticleTest.php b/tests/ContextTypes/ArticleTest.php index f990aa9..83d05f1 100644 --- a/tests/ContextTypes/ArticleTest.php +++ b/tests/ContextTypes/ArticleTest.php @@ -9,7 +9,7 @@ class ArticleTest extends TestCase protected $class = \JsonLd\ContextTypes\Article::class; protected $attributes = [ - 'name' => 'More than That', + 'name' => 'articleNComments', 'url' => 'https://google.com/1-article', 'description' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.', 'image' => [ @@ -38,6 +38,17 @@ class ArticleTest extends TestCase ], 'keywords' => 'Lorem,ipsum,dolor', 'inLanguage' => 'en', + 'commentCount' => 2, + 'comment' => [ + ['@type' => 'Comment', + 'author' => ['@type' => 'Person', 'name' => 'Joe Joe'], + 'text' => 'first comment', + 'dateCreated' => '2018-06-14T21:40:00+02:00'], + ['@type' => 'Comment', + 'author' => ['@type' => 'Person', 'name' => 'Joe Bis'], + 'text' => 'second comment', + 'dateCreated' => '2018-06-14T23:23:00+02:00'] + ], 'dateCreated' => '2013-10-04T00:00', 'dateModified' => '2013-10-04T00:00', 'datePublished' => '2013-10-04T00:00', @@ -50,6 +61,52 @@ class ArticleTest extends TestCase 'headline' => 'eiusmod tempor incididunt ut labore et dolore magna aliqua.', ]; + /** + * @test + */ + public function shouldHaveThingName() + { + $context = $this->make(); + + $this->assertEquals('articleNComments', $context->getProperty('name')); + } + + /** + * @test + */ + public function shouldHaveThingMainEntityOfPageObject() + { + $context = $this->make(); + + $this->assertEquals([ + '@type' => 'WebPage', + '@id' => 'https://blogspot.com/100-article', + ], $context->getProperty('mainEntityOfPage')); + } + + /** + * @test + */ + public function shouldHaveCreativeWorkInLanguage() + { + $context = $this->make(); + + $this->assertEquals('en', $context->getProperty('inLanguage')); + } + + /** + * @test + */ + public function shouldHaveCreativeWorkAuthorObject() + { + $context = $this->make(); + + $this->assertEquals([ + '@type' => 'Person', + 'name' => 'Joe Joe', + ], $context->getProperty('author')); + } + /** * @test */ @@ -145,36 +202,22 @@ public function shouldHaveKeywords() /** * @test */ - public function shouldHaveInLanguage() - { - $context = $this->make(); - - $this->assertEquals('en', $context->getProperty('inLanguage')); - } - - /** - * @test - */ - public function shouldHaveAuthorObject() + public function shouldHave2CommentsArray() { $context = $this->make(); $this->assertEquals([ - '@type' => 'Person', - 'name' => 'Joe Joe', - ], $context->getProperty('author')); - } - - /** - * @test - */ - public function shouldHaveMainEntityOfPageObject() - { - $context = $this->make(); - + '@type' => 'Comment', + 'text' => 'first comment', + 'author' => ['@type' => 'Person', 'name' => 'Joe Joe'], + 'dateCreated' => '2018-06-14T21:40:00+02:00', + ], $context->getProperty('comment')[0]); $this->assertEquals([ - '@type' => 'WebPage', - '@id' => 'https://blogspot.com/100-article', - ], $context->getProperty('mainEntityOfPage')); + '@type' => 'Comment', + 'text' => 'second comment', + 'author' => ['@type' => 'Person', 'name' => 'Joe Bis'], + 'dateCreated' => '2018-06-14T23:23:00+02:00', + ], $context->getProperty('comment')[1]); } + } diff --git a/tests/ContextTypes/PersonSimpleAddressTest.php b/tests/ContextTypes/PersonSimpleAddressTest.php new file mode 100644 index 0000000..90bfd58 --- /dev/null +++ b/tests/ContextTypes/PersonSimpleAddressTest.php @@ -0,0 +1,65 @@ + 'Anonymous tester', + 'mainEntityOfPage' => [ + 'url' => 'https://example.com/anonymous.html' + ], + 'additionalName' => 'phpUnit hacker', + 'address' => 'rue de gauche' + + ]; + + /** + * @test + */ + public function shouldHaveThingName() + { + $context = $this->make(); + + $this->assertEquals('Anonymous tester', $context->getProperty('name')); + } + + /** + * @test + */ + public function shouldHaveThingMainEntityOfPageObject() + { + $context = $this->make(); + + $this->assertEquals([ + '@type' => 'WebPage', + '@id' => 'https://example.com/anonymous.html', + ], $context->getProperty('mainEntityOfPage')); + } + + /** + * @test + */ + public function shouldHaveAdditionalName() + { + $context = $this->make(); + + $this->assertEquals('phpUnit hacker', $context->getProperty('additionalName')); + } + + /** + * @test + */ + public function shouldHaveAddress() + { + $context = $this->make(); + + $this->assertEquals('rue de gauche', $context->getProperty('address')); + } + + +} diff --git a/tests/ContextTypes/PersonTest.php b/tests/ContextTypes/PersonTest.php new file mode 100644 index 0000000..5551e4f --- /dev/null +++ b/tests/ContextTypes/PersonTest.php @@ -0,0 +1,138 @@ + 'Anonymous tester', + 'description' => 'a man in the middle', + 'mainEntityOfPage' => [ + 'url' => 'https://example.com/anonymous.html' + ], + 'image' => [ + 'url' => 'https://google.com/Doctor.jpg', + 'height' => 800, + 'width' => 800 + ], + 'additionalName' => 'phpUnit hacker', + 'address' => [ + 'addressLocality' => 'Paris', + 'addressCountry' => 'France' + ], + 'award' => 'phpUnit Excellence', + 'birthDate' => '1943-10-04T00:00', + 'birthPlace' => ['name' => 'Paris'], + 'deathDate' => '2013-10-04T00:00', + 'deathPlace' => ['name' => 'London'], + 'email' => 'toto@yoyo.fr', + 'familyName' => 'Dupondt', + 'faxNumber' => '0000000000', + 'follows' => [ 'name' => 'strange follower' ], + 'givenName' => 'Doctor', + 'homeLocation' => [ + 'name' => 'Fluff Hut', + 'address' => [ + 'streetAddress' => '112 Apple St.', + 'addressLocality' => 'Hamden', + 'addressRegion' => 'CT', + 'postalCode' => '06514', + ], + ], + 'jobTitle' => 'tester', + 'parent' => [ 'name' => 'daddy' ], + 'telephone' => '+330102030405' + + ]; + + public function test_should_have_properties() { + + $this->assertPropertyEquals('name', 'Anonymous tester'); + + $this->assertPropertyEquals('description', 'a man in the middle'); + + $this->assertPropertyEquals('mainEntityOfPage', + [ + '@type' => 'WebPage', + '@id' => 'https://example.com/anonymous.html', + ]); + + $this->assertPropertyEquals('image', + [ + '@type' => 'ImageObject', + 'url' => 'https://google.com/Doctor.jpg', + 'height' => 800, + 'width' => 800, + ]); + + $this->assertPropertyEquals('additionalName', 'phpUnit hacker'); + + $this->assertPropertyEquals('address', + [ + '@type' => 'PostalAddress', + 'addressLocality' => 'Paris', + 'addressCountry' => 'France' + ]); + + $this->assertPropertyEquals('award', 'phpUnit Excellence'); + + $this->assertPropertyEquals('birthDate', '1943-10-04T00:00'); + + $this->assertPropertyEquals('birthPlace', + [ + '@type' => 'Place', + 'name' => 'Paris', + ]); + + $this->assertPropertyEquals('deathDate', '2013-10-04T00:00'); + + $this->assertPropertyEquals('deathPlace', + [ + '@type' => 'Place', + 'name' => 'London', + ]); + + $this->assertPropertyEquals('email', 'toto@yoyo.fr'); + + $this->assertPropertyEquals('familyName', 'Dupondt'); + + $this->assertPropertyEquals('faxNumber', '0000000000'); + + $this->assertPropertyEquals('follows', + [ + '@type' => 'Person', + 'name' => 'strange follower' + ]); + + $this->assertPropertyEquals('givenName', 'Doctor'); + + $this->assertPropertyEquals('homeLocation', + [ + '@type' => 'Place', + 'name' => 'Fluff Hut', + 'address' => [ + '@type' => 'PostalAddress', + 'streetAddress' => '112 Apple St.', + 'addressLocality' => 'Hamden', + 'addressRegion' => 'CT', + 'postalCode' => '06514', + ], + ] + ); + + $this->assertPropertyEquals('jobTitle', 'tester'); + + $this->assertPropertyEquals('parent', + [ + '@type' => 'Person', + 'name' => 'daddy' + ]); + + $this->assertPropertyEquals('telephone', '+330102030405'); + } + +} \ No newline at end of file diff --git a/tests/ContextTypes/PlaceTest.php b/tests/ContextTypes/PlaceTest.php new file mode 100644 index 0000000..37e5914 --- /dev/null +++ b/tests/ContextTypes/PlaceTest.php @@ -0,0 +1,46 @@ + 'Fluff Hut', + 'address' => [ + 'streetAddress' => '112 Apple St.', + 'addressLocality' => 'Hamden', + 'addressRegion' => 'CT', + 'postalCode' => '06514', + ], + 'review' => [ + 'reviewBody' => 'beautifull place', + 'reviewRating' => 10, + ], + ]; + + public function test_should_have_properties() { + + $this->assertPropertyEquals('name', 'Fluff Hut'); + + $this->assertPropertyEquals('address', + [ + '@type' => 'PostalAddress', + 'streetAddress' => '112 Apple St.', + 'addressLocality' => 'Hamden', + 'addressRegion' => 'CT', + 'postalCode' => '06514', + ]); + + $this->assertPropertyEquals('review', + [ + '@type' => 'Review', + 'reviewBody' => 'beautifull place', + 'reviewRating' => 10, + ]); + } + +} \ No newline at end of file diff --git a/tests/ContextTypes/SculptureTest.php b/tests/ContextTypes/SculptureTest.php new file mode 100644 index 0000000..78fd79a --- /dev/null +++ b/tests/ContextTypes/SculptureTest.php @@ -0,0 +1,89 @@ + 'https://exemple.com/sclpture?id=1234', + 'author' => [ + '@type' => 'Person', + 'name' => 'Rodin', + ], + 'text' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco.', + 'commentCount' => 2, + 'comment' => [ + ['@type' => 'Comment', + 'author' => ['@type' => 'Person', 'name' => 'Joe Joe'], + 'text' => 'first comment', + 'dateCreated' => '2018-06-14T21:40:00+02:00'], + ['@type' => 'Comment', + 'author' => ['@type' => 'Person', 'name' => 'Joe Bis'], + 'text' => 'second comment', + 'dateCreated' => '2018-06-14T23:23:00+02:00'] + ], + 'inLanguage' => 'jp', + 'dateCreated' => '2013-10-04T00:00', + 'name' => 'sculptureNComments' + + ]; + + + /** + * @test + */ + public function shouldHaveThingName() + { + $context = $this->make(); + + $this->assertEquals('sculptureNComments', $context->getProperty('name')); + } + + /** + * @test + */ + public function shouldHaveCreativeWorkInLanguage() + { + $context = $this->make(); + + $this->assertEquals('jp', $context->getProperty('inLanguage')); + } + + /** + * @test + */ + public function shouldHaveCreativeWorkAuthorObject() + { + $context = $this->make(); + + $this->assertEquals([ + '@type' => 'Person', + 'name' => 'Rodin', + ], $context->getProperty('author')); + } + + /** + * @test + */ + public function shouldHave2CommentsArray() + { + $context = $this->make(); + + $this->assertEquals([ + '@type' => 'Comment', + 'text' => 'first comment', + 'author' => ['@type' => 'Person', 'name' => 'Joe Joe'], + 'dateCreated' => '2018-06-14T21:40:00+02:00', + ], $context->getProperty('comment')[0]); + $this->assertEquals([ + '@type' => 'Comment', + 'text' => 'second comment', + 'author' => ['@type' => 'Person', 'name' => 'Joe Bis'], + 'dateCreated' => '2018-06-14T23:23:00+02:00', + ], $context->getProperty('comment')[1]); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index ad3a8e8..b1ce5af 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -20,4 +20,35 @@ protected function make() { return new $this->class($this->attributes); } + + protected function assertPropertyEquals($property, $expectedValue) + { + $context = $this->make(); + + $assertMessage = 'asserting \''.$this->class.'\' property \''.$property.'\''; + $this->assertEquals($expectedValue, $context->getProperty($property), $assertMessage); + } + + + protected function makeJsonLdContext() + { + return \JsonLd\Context::create($this->class, $this->attributes); + } + + public function testGenerateLdJson() + { + $context = $this->make(); + $jsonLdContext = $this->makeJsonLdContext(); + + $html = $jsonLdContext->generate(); + $properties = $context->getProperties(); + + $this->assertNotNull($html); + foreach ($properties as $k => $v) { + if ($v != null) { + $this->assertContains(json_encode($k), $html); + $this->assertContains(json_encode($v), $html); + } + } + } } \ No newline at end of file