diff --git a/.editorconfig b/.editorconfig index 47ae637..a3e7803 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,6 +1,6 @@ -# For more information about the properties used in this file, -# please see the EditorConfig documentation: -# http://editorconfig.org +# For more information about the properties used in +# this file, please see the EditorConfig documentation: +# http://editorconfig.org/ [*] charset = utf-8 @@ -10,8 +10,12 @@ indent_style = space insert_final_newline = true trim_trailing_whitespace = true -[{*.yml,package.json}] +[*.md] +trim_trailing_whitespace = false + +[*.{yml,js,json,css,scss,eslintrc,feature}] indent_size = 2 +indent_style = space -# The indent size used in the package.json file cannot be changed: -# https://github.com/npm/npm/pull/3180#issuecomment-16336516 +[composer.json] +indent_size = 4 diff --git a/.scrutinizer.yml b/.scrutinizer.yml index d1ebd80..051ef9a 100644 --- a/.scrutinizer.yml +++ b/.scrutinizer.yml @@ -1,69 +1,15 @@ inherit: true +build: + nodes: + analysis: + tests: + override: [php-scrutinizer-run] + checks: php: - verify_property_names: true - verify_argument_usable_as_reference: true - verify_access_scope_valid: true - useless_calls: true - use_statement_alias_conflict: true - variable_existence: true - unused_variables: true - unused_properties: true - unused_parameters: true - unused_methods: true - unreachable_code: true - too_many_arguments: true - sql_injection_vulnerabilities: true - simplify_boolean_return: true - side_effects_or_types: true - security_vulnerabilities: true - return_doc_comments: true - return_doc_comment_if_not_inferrable: true - require_scope_for_properties: true - require_scope_for_methods: true - require_php_tag_first: true - psr2_switch_declaration: true - psr2_class_declaration: true - property_assignments: true - prefer_while_loop_over_for_loop: true - precedence_mistakes: true - precedence_in_conditions: true - phpunit_assertions: true - php5_style_constructor: true - parse_doc_comments: true - parameter_non_unique: true - parameter_doc_comments: true - param_doc_comment_if_not_inferrable: true - optional_parameters_at_the_end: true - one_class_per_file: true - no_unnecessary_if: true - no_trailing_whitespace: true - no_property_on_interface: true - no_non_implemented_abstract_methods: true - no_error_suppression: true - no_duplicate_arguments: true - no_commented_out_code: true - newline_at_end_of_file: true - missing_arguments: true - method_calls_on_non_object: true - instanceof_class_exists: true - foreach_traversable: true - fix_line_ending: true - fix_doc_comments: true - duplication: true - deprecated_code_usage: true - deadlock_detection_in_loops: true code_rating: true - closure_use_not_conflicting: true - catch_class_exists: true - blank_line_after_namespace_declaration: false - avoid_multiple_statements_on_same_line: true - avoid_duplicate_types: true - avoid_conflicting_incrementers: true - avoid_closing_tag: true - assignment_of_null_return: true - argument_type_checks: true + duplication: true filter: - paths: [code/*, tests/*] + paths: [src/*, tests/*] diff --git a/.upgrade.yml b/.upgrade.yml new file mode 100644 index 0000000..795477c --- /dev/null +++ b/.upgrade.yml @@ -0,0 +1,47 @@ +mappings: + OGDeterminers: TractorCow\OpenGraph\Constants\OGDeterminers + OGGenders: TractorCow\OpenGraph\Constants\OGGenders + OGTypes: TractorCow\OpenGraph\Constants\OGTypes + OpenGraphObjectExtension: TractorCow\OpenGraph\Extensions\OpenGraphObjectExtension + OpenGraphSiteConfigExtension: TractorCow\OpenGraph\Extensions\OpenGraphSiteConfigExtension + IOGApplication: TractorCow\OpenGraph\Interfaces\IOGApplication + IOpenGraphObjectBuilder: TractorCow\OpenGraph\Interfaces\IOpenGraphObjectBuilder + IOGObject: TractorCow\OpenGraph\Interfaces\ObjectTypes\IOGObject + IOGObjectExplicit: TractorCow\OpenGraph\Interfaces\ObjectTypes\IOGObjectExplicit + IOGObjectRequired: TractorCow\OpenGraph\Interfaces\ObjectTypes\IOGObjectRequired + IOGMusic: TractorCow\OpenGraph\Interfaces\Music\IOGMusic + IOGMusicSongList: TractorCow\OpenGraph\Interfaces\Music\IOGMusicSongList + IOGMusicAlbum: TractorCow\OpenGraph\Interfaces\Music\IOGMusicAlbum + IOGMusicPlaylist: TractorCow\OpenGraph\Interfaces\Music\IOGMusicPlaylist + IOGMusicRadioStation: TractorCow\OpenGraph\Interfaces\Music\IOGMusicRadioStation + IOGMusicSong: TractorCow\OpenGraph\Interfaces\Music\IOGMusicSong + IOGSongAlbum: TractorCow\OpenGraph\Interfaces\Music\Relations\IOGSongAlbum + IOGAuthoredTagged: TractorCow\OpenGraph\Interfaces\Other\IOGAuthoredTagged + IOGTagged: TractorCow\OpenGraph\Interfaces\Other\IOGTagged + IOGArticle: TractorCow\OpenGraph\Interfaces\Other\IOGArticle + IOGBook: TractorCow\OpenGraph\Interfaces\Other\IOGBook + IOGProfile: TractorCow\OpenGraph\Interfaces\Other\IOGProfile + IOGWebsite: TractorCow\OpenGraph\Interfaces\Other\IOGWebsite + IMediaFile: TractorCow\OpenGraph\Interfaces\Other\Relations\IMediaFile + IOGVideo: TractorCow\OpenGraph\Interfaces\Video\IOGVideo + IOGVideoEpisode: TractorCow\OpenGraph\Interfaces\Video\IOGVideoEpisode + IOGVideoMovie: TractorCow\OpenGraph\Interfaces\Video\IOGVideoMovie + IOGVideoOther: TractorCow\OpenGraph\Interfaces\Video\IOGVideoOther + IOGVideoTVShow: TractorCow\OpenGraph\Interfaces\Video\IOGVideoTVShow + IOGVideoActor: TractorCow\OpenGraph\Interfaces\Video\Relations\IOGVideoActor + OGMusic: TractorCow\OpenGraph\ObjectBuilders\Music\AbstractOGMusic + OGMusicAlbum: TractorCow\OpenGraph\ObjectBuilders\Music\OGMusicAlbum + OGMusicPlaylist: TractorCow\OpenGraph\ObjectBuilders\Music\OGMusicPlaylist + OGMusicRadioStation: TractorCow\OpenGraph\ObjectBuilders\Music\OGMusicRadioStation + OGMusicSong: TractorCow\OpenGraph\ObjectBuilders\Music\OGMusicSong + OpenGraphBuilder: TractorCow\OpenGraph\ObjectBuilders\OpenGraphBuilder + OGArticle: TractorCow\OpenGraph\ObjectBuilders\Other\OGArticle + OGBook: TractorCow\OpenGraph\ObjectBuilders\Other\OGBook + OGProfile: TractorCow\OpenGraph\ObjectBuilders\Other\OGProfile + OGWebsite: TractorCow\OpenGraph\ObjectBuilders\Other\OGWebsite + OGVideo: TractorCow\OpenGraph\ObjectBuilders\Video\AbstractOGVideo + OGVideoEpisode: TractorCow\OpenGraph\ObjectBuilders\Video\OGVideoEpisode + OGVideoMovie: TractorCow\OpenGraph\ObjectBuilders\Video\OGVideoMovie + OGVideoOther: TractorCow\OpenGraph\ObjectBuilders\Video\OGVideoOther + OGVideoTVShow: TractorCow\OpenGraph\ObjectBuilders\Video\OGVideoTVShow + OpenGraph: TractorCow\OpenGraph\OpenGraph diff --git a/README.md b/README.md index ae9dd9d..8b2e5ea 100644 --- a/README.md +++ b/README.md @@ -16,15 +16,15 @@ with Facebook. ## Requirements - * SilverStripe 3.1 - * PHP 5.3 + * SilverStripe 4+ + * PHP 5.6+ ## Installation Instructions - * Extract all files into the 'opengraph' folder under your Silverstripe root, or install using composer + * Install using composer ```bash -composer require "tractorcow/silverstripe-opengraph" "3.1.*@dev" +composer require "tractorcow/silverstripe-opengraph" "4@dev" ``` * Ensure the namespace is defined in your template with ``` ``` @@ -44,11 +44,11 @@ Override these in your own `mysite/_config/OpenGraph.yml` or `mysite/_config.php Name: myopengraphsettings After: '#opengraphsettings' --- -OpenGraph: +TractorCow\OpenGraph\OpenGraph: application_id: 'SiteConfig' admin_id: 'SiteConfig' default_locale: 'en_US' - default_tagbuilder: 'OpenGraphBuilder' + default_tagbuilder: 'TractorCow\OpenGraph\ObjectBuilders\OpenGraphBuilder' ``` @@ -65,7 +65,7 @@ Any value above can be set to an empty string to disable it completely. E.g. Name: myopengraphsettings After: '#opengraphsettings' --- -OpenGraph: +TractorCow\OpenGraph\OpenGraph: application_id: '' admin_id: '' ``` @@ -75,12 +75,13 @@ OpenGraph: ### Implementing Open Graph object properties To get specific information on each of the fields an opengraph object can have, check -out the various implementations of each in the [interfaces/ObjectTypes](interfaces/ObjectTypes) folder, +out the various implementations of each in the [src/Interfaces/ObjectTypes](src/Interfaces/ObjectTypes) folder, or in the [_config/OpenGraphTypes.yml](_config/OpenGraphTypes.yml) file for the list of types and their respective interfaces. -The basic opengraph object has a set of required properties (as defined by IOGObjectRequired) -and additionally a set of optional properties (as defined by IOGObjectExplicit). +The basic opengraph object has a set of required properties (as defined by +`TractorCow\OpenGraph\Interfaces\ObjectTypes\IOGObjectRequired`) +and additionally a set of optional properties (as defined by `TractorCow\OpenGraph\Interfaces\ObjectTypes\IOGObjectExplicit`). Since most of the field values are generated by the page extension class OpenGraphPageExtension automatically, you don't need to explicitly implement either of these. These should however @@ -113,13 +114,13 @@ If you wish to add a new og:type you will need to: * Register your object type with the following code: ```php -OpenGraph::register_type('type-name', IOGMyObjectInterface, MyObjectTagBuilder); +TractorCow\OpenGraph\OpenGraph::register_type('type-name', IOGMyObjectInterface, MyObjectTagBuilder); ``` Or better still, do this directly in yaml as below ```yaml -OpenGraph: +TractorCow\OpenGraph\OpenGraph: types: 'type-name': interface: IOGMyObjectInterface @@ -164,10 +165,10 @@ You can decorate the OpenGraphBuilder object instead of extending it if you need to add additional tags to all object types. The example below shows how to add extra fields from the Page and SiteConfig -to the set of opengraph tags. +to the set of OpenGraph tags. ```php -OpenGraphBuilder::add_extension('OpengraphBuilderExtension'); +TractorCow\OpenGraph\ObjectBuilders\OpenGraphBuilder::add_extension('OpenGraphBuilderExtension'); class OpengraphBuilderExtension extends Extension { @@ -182,9 +183,9 @@ class OpengraphBuilderExtension extends Extension { } ``` -### Disabling opengraph for a single page (or page type) +### Disabling Open Graph for a single page (or page type) -If you need to disable opengraph for any page then a null value for `getOGType()` +If you need to disable Open Graph for any page then a null value for `getOGType()` will disable tag generation. ```php @@ -200,9 +201,9 @@ NonOGPage extends Page { ### Using DataObjects as pages See [https://github.com/tractorcow/silverstripe-opengraph/wiki/Using-DataObjects-as-Pages](https://github.com/tractorcow/silverstripe-opengraph/wiki/Using-DataObjects-as-Pages) -for how to extend your `DataObject` with `OpenGraphObjectExtension`. +for how to extend your `DataObject` with `TractorCow\OpenGraph\Extensions\OpenGraphObjectExtension`. - * Add the `OpenGraphObjectExtension` extension to your object + * Add the `TractorCow\OpenGraph\Extensions\OpenGraphObjectExtension` extension to your object * Implement `AbsoluteLink` on your object * Implement `MetaTags` on your object, making sure to call `$this->extend('MetaTags', $tags);` * Make sure the actual page type being viewed delegates the meta tag generation to your dataobject diff --git a/_config/Extensions.yml b/_config/Extensions.yml index 65e5608..2c1b91d 100644 --- a/_config/Extensions.yml +++ b/_config/Extensions.yml @@ -3,7 +3,8 @@ name: 'opengraphextensions' --- Page: extensions: - - 'OpenGraphObjectExtension' -SiteConfig: + - TractorCow\OpenGraph\Extensions\OpenGraphObjectExtension + +SilverStripe\SiteConfig\SiteConfig: extensions: - - 'OpenGraphSiteConfigExtension' \ No newline at end of file + - TractorCow\OpenGraph\Extensions\OpenGraphSiteConfigExtension diff --git a/_config/OpenGraph.yml b/_config/OpenGraph.yml index 54ec13b..ac82a1f 100644 --- a/_config/OpenGraph.yml +++ b/_config/OpenGraph.yml @@ -1,8 +1,8 @@ --- Name: opengraphsettings --- -OpenGraph: +TractorCow\OpenGraph\OpenGraph: application_id: 'SiteConfig' admin_id: 'SiteConfig' default_locale: 'en_US' - default_tagbuilder: 'OpenGraphBuilder' \ No newline at end of file + default_tagbuilder: TractorCow\OpenGraph\ObjectBuilders\OpenGraphBuilder diff --git a/_config/OpenGraphLocales.yml b/_config/OpenGraphLocales.yml index e278716..2ca0b2a 100644 --- a/_config/OpenGraphLocales.yml +++ b/_config/OpenGraphLocales.yml @@ -3,7 +3,7 @@ ## See https://www.facebook.com/translations/FacebookLocales.xml for this master list Name: opengraphlocales --- -OpenGraph: +TractorCow\OpenGraph\OpenGraph: locales: af_ZA: 'Afrikaans' ar_AR: 'Arabic' @@ -82,4 +82,3 @@ OpenGraph: zh_CN: 'Simplified Chinese (China)' zh_HK: 'Traditional Chinese (Hong Kong)' zh_TW: 'Traditional Chinese (Taiwan)' - \ No newline at end of file diff --git a/_config/OpenGraphTypes.yml b/_config/OpenGraphTypes.yml index c4a0aba..2e7ac54 100644 --- a/_config/OpenGraphTypes.yml +++ b/_config/OpenGraphTypes.yml @@ -3,41 +3,41 @@ # This list may be added to to create new object types Name: opengraphobjecttypes --- -OpenGraph: +TractorCow\OpenGraph\OpenGraph: types: 'music.song': - interface: IOGMusicSong - tagbuilder: OGMusicSong + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Music\IOGMusicSong + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Music\OGMusicSong 'music.album': - interface: IOGMusicAlbum - tagbuilder: OGMusicAlbum + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Music\IOGMusicAlbum + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Music\OGMusicAlbum 'music.playlist': - interface: IOGMusicPlaylist - tagbuilder: OGMusicPlaylist + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Music\IOGMusicPlaylist + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Music\OGMusicPlaylist 'music.radio_station': - interface: IOGMusicRadioStation - tagbuilder: OGMusicRadioStation + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Music\IOGMusicRadioStation + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Music\OGMusicRadioStation 'video.movie': - interface: IOGVideoMovie - tagbuilder: OGVideoMovie + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Video\IOGVideoMovie + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Video\OGVideoMovie 'video.episode': - interface: IOGVideoEpisode - tagbuilder: OGVideoEpisode + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Video\IOGVideoEpisode + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Video\OGVideoEpisode 'video.tv_show': - interface: IOGVideoTVShow - tagbuilder: OGVideoTVShow + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Video\IOGVideoTVShow + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Video\OGVideoTVShow 'video.other': - interface: IOGVideoOther - tagbuilder: OGVideoOther + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Video\IOGVideoOther + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Video\OGVideoOther 'article': - interface: IOGArticle - tagbuilder: OGArticle + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Other\IOGArticle + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Other\OGArticle 'book': - interface: IOGBook - tagbuilder: OGBook + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Other\IOGBook + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Other\OGBook 'profile': - interface: IOGProfile - tagbuilder: OGProfile + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Other\IOGProfile + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Other\OGProfile 'website': - interface: IOGWebsite - tagbuilder: OGWebsite \ No newline at end of file + interface: TractorCow\OpenGraph\Interfaces\ObjectTypes\Other\IOGWebsite + tagbuilder: TractorCow\OpenGraph\ObjectBuilders\Other\OGWebsite diff --git a/code/Constants/OGDeterminers.php b/code/Constants/OGDeterminers.php deleted file mode 100644 index f62a1d2..0000000 --- a/code/Constants/OGDeterminers.php +++ /dev/null @@ -1,15 +0,0 @@ - element and appends it to a set of header tags. - * Public to allow use by extensions to OpenGraphbuilder - * @param string $tags The current tag string to append these to - * @param string $name Meta name attribute value - * @param mixed $content Meta content attribute value(s) - */ - public function AppendTag(&$tags, $name, $content); -} \ No newline at end of file diff --git a/interfaces/ObjectTypes/IOGObject.php b/interfaces/ObjectTypes/IOGObject.php deleted file mode 100644 index d111b02..0000000 --- a/interfaces/ObjectTypes/IOGObject.php +++ /dev/null @@ -1,16 +0,0 @@ - + + CodeSniffer ruleset for SilverStripe coding conventions. + + + + + + + + + + + + + + + + + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..ad0b6bf --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,15 @@ + + + + tests/ + + + + + src/ + + tests/ + + + + diff --git a/src/Constants/OGDeterminers.php b/src/Constants/OGDeterminers.php new file mode 100644 index 0000000..a0d3d3b --- /dev/null +++ b/src/Constants/OGDeterminers.php @@ -0,0 +1,17 @@ +owner instanceof IOGProfile) { $ns .= ' profile: http://ogp.me/ns/profile#'; } - if ($this->owner instanceof IOGWebsite || $this->owner->getOGType() == OGTypes::DefaultType) { + if ($this->owner instanceof IOGWebsite || $this->owner->getOGType() == OGTypes::DEFAULT_TYPE) { $ns .= ' website: http://ogp.me/ns/website#'; } $ns .= '"'; @@ -91,7 +120,7 @@ public function getOGType() return $type; } - return OGTypes::DefaultType; + return OGTypes::DEFAULT_TYPE; } public function getOGTitle() @@ -111,9 +140,10 @@ public function getOGSiteName() public function getOGImage() { // Since og:image is a required property, provide a reasonable default - if (self::$default_image) { - return Director::absoluteURL(self::$default_image); + if ($image = self::config()->default_image) { + return Director::absoluteURL(ModuleResourceLoader::resourceURL($image)); } + return ''; } public function AbsoluteLink() @@ -143,14 +173,15 @@ public function getOGDescription() // Intelligent fallback for SiteTree instances $contentField = $this->owner->dbObject('Content'); - if ($contentField instanceof Text) { + if ($contentField instanceof DBText) { return $contentField->Summary(100); } + return $contentField; } public function getOGDeterminer() { - return OGDeterminers::DefaultValue; + return OGDeterminers::DEFAULT_VALUE; } public function getOGLocales() diff --git a/code/Extensions/OpenGraphSiteConfigExtension.php b/src/Extensions/OpenGraphSiteConfigExtension.php similarity index 73% rename from code/Extensions/OpenGraphSiteConfigExtension.php rename to src/Extensions/OpenGraphSiteConfigExtension.php index 6b3e949..a59879f 100644 --- a/code/Extensions/OpenGraphSiteConfigExtension.php +++ b/src/Extensions/OpenGraphSiteConfigExtension.php @@ -1,41 +1,50 @@ $db ); } - + public function updateCMSFields(FieldList $fields) { + if (OpenGraph::get_config('application_id') == 'SiteConfig') { $fields->addFieldToTab( 'Root.Facebook', - new TextField('OGApplicationID', 'Facebook Application ID', null, 255) + TextField::create('OGApplicationID', 'Facebook Application ID', null, 255) ); } - + if (OpenGraph::get_config('admin_id') == 'SiteConfig') { $fields->addFieldToTab( 'Root.Facebook', - new TextField('OGAdminID', 'Facebook Admin ID(s)', null, 255) + TextField::create('OGAdminID', 'Facebook Admin ID(s)', null, 255) ); } } - + protected function getConfigurableField($dbField, $configField) { $value = OpenGraph::get_config($configField); diff --git a/src/Interfaces/IOGApplication.php b/src/Interfaces/IOGApplication.php new file mode 100644 index 0000000..c1e76d2 --- /dev/null +++ b/src/Interfaces/IOGApplication.php @@ -0,0 +1,22 @@ + element and appends it to a set of header tags. + * Public to allow use by extensions to OpenGraphbuilder + * @param string $tags The current tag string to append these to + * @param string $name Meta name attribute value + * @param mixed $content Meta content attribute value(s) + */ + public function AppendTag(&$tags, $name, $content); +} diff --git a/src/Interfaces/ObjectTypes/IOGObject.php b/src/Interfaces/ObjectTypes/IOGObject.php new file mode 100644 index 0000000..978fbfd --- /dev/null +++ b/src/Interfaces/ObjectTypes/IOGObject.php @@ -0,0 +1,18 @@ +appendRelatedSongList($tags, $namespace, $value->getOGSong()); $this->AppendTag($tags, "$namespace:disc", $value->getOGDisc()); $this->AppendTag($tags, "$namespace:track", $value->getOGTrack()); return; } - + // Handle single song object - if ($value instanceof IOGMusicSong) { /* @var $value IOGMusicSong */ - return $this->AppendTag($tags, $namespace, $value->AbsoluteLink()); + if ($value instanceof IOGMusicSong) { + /* @var $value IOGMusicSong */ + $this->AppendTag($tags, $namespace, $value->AbsoluteLink()); + return; } // Handle image URL being given if (is_string($value)) { - return $this->AppendTag($tags, $namespace, $value); + $this->AppendTag($tags, $namespace, $value); + return; } // Fail if could not determine presented value type diff --git a/code/ObjectBuilders/Music/OGMusicAlbum.php b/src/ObjectBuilders/Music/OGMusicAlbum.php similarity index 76% rename from code/ObjectBuilders/Music/OGMusicAlbum.php rename to src/ObjectBuilders/Music/OGMusicAlbum.php index 4ca18cd..de768d4 100644 --- a/code/ObjectBuilders/Music/OGMusicAlbum.php +++ b/src/ObjectBuilders/Music/OGMusicAlbum.php @@ -1,6 +1,10 @@ AppendTag($tags, "$namespace:track", $value->getOGTrack()); return; } - - if ($value instanceof IOGMusicAlbum) { /* @var $value IOGMusicAlbum */ - return $this->AppendTag($tags, $namespace, $value->AbsoluteLink()); + + if ($value instanceof IOGMusicAlbum) { + $this->AppendTag($tags, $namespace, $value->AbsoluteLink()); + return; } // Handle image URL being given if (is_string($value)) { - return $this->AppendTag($tags, $namespace, $value); + $this->AppendTag($tags, $namespace, $value); + return; } // Fail if could not determine presented value type diff --git a/code/ObjectBuilders/OpenGraphBuilder.php b/src/ObjectBuilders/OpenGraphBuilder.php similarity index 87% rename from code/ObjectBuilders/OpenGraphBuilder.php rename to src/ObjectBuilders/OpenGraphBuilder.php index 6002b16..ebbb2f3 100644 --- a/code/ObjectBuilders/OpenGraphBuilder.php +++ b/src/ObjectBuilders/OpenGraphBuilder.php @@ -1,10 +1,29 @@ AppendTag($tags, $name, $item); } - return; + return null; } // Handle links to resources (either IOGObject or basic SiteTree if ($this->isValueLinkable($content)) { - return $this->AppendTag($tags, $name, $content->AbsoluteLink()); + $this->AppendTag($tags, $name, $content->AbsoluteLink()); + return null; } // check tag type @@ -86,13 +106,14 @@ protected function appendLink(&$tags, $rel, $link, $type = null) if (empty($rel) || empty($link)) { return; } + $tags .= sprintf( "\n", Convert::raw2att($rel), Convert::raw2att($link), $type - ? $type - : $this->getMimeType($link) + ? $type + : $this->getMimeType($link) ); } @@ -101,6 +122,7 @@ protected function appendLink(&$tags, $rel, $link, $type = null) * @param string $tags The current tag string to append these two * @param string $namespace The namespace to use for this element * @param IOGProfile[]|IOGProfile|string[]|string $value A single, or list of profiles + * @return null|string */ protected function appendRelatedProfileTags(&$tags, $namespace, $value) { @@ -132,7 +154,6 @@ protected function appendMediaMetaTags(&$tags, $namespace, $value, $https = null // Handle File objects if ($value instanceof File) { - /* @var $value IMediaFile */ if (!$value->exists()) { return; } @@ -224,7 +245,7 @@ protected function appendDefaultMetaTags(&$tags, $object) $this->AppendTag($tags, 'og:determiner ', $object->getOGDeterminer()); $this->AppendTag($tags, 'og:site_name', $object->getOGSiteName()); $this->appendLocales($tags, $object->getOGLocales()); - + // Entrypoint for extensions to object tags $this->extend('updateDefaultMetaTags', $tags, $object); } @@ -234,7 +255,7 @@ protected function appendApplicationMetaTags(&$tags, $config) /* @var $config IOGApplication */ $this->AppendTag($tags, 'fb:admins', $config->getOGAdminID()); $this->AppendTag($tags, 'fb:app_id', $config->getOGApplicationID()); - + // Entrypoint for extensions to application tags $this->extend('updateApplicationMetaTags', $tags, $config); } @@ -245,11 +266,11 @@ protected function appendDateTag(&$tags, $name, $date) return; } - if (!($date instanceof DateTime)) { - $date = new DateTime($date); + if (!($date instanceof DBDateTime)) { + $date = DBDatetime::create_field(DBDatetime::class, $date); } - $this->AppendTag($tags, $name, $date->format(DateTime::ISO8601)); + $this->AppendTag($tags, $name, $date->Rfc3339()); } public function BuildTags(&$tags, $object, $config) diff --git a/code/ObjectBuilders/Other/OGArticle.php b/src/ObjectBuilders/Other/OGArticle.php similarity index 82% rename from code/ObjectBuilders/Other/OGArticle.php rename to src/ObjectBuilders/Other/OGArticle.php index d6ab35b..0493feb 100644 --- a/code/ObjectBuilders/Other/OGArticle.php +++ b/src/ObjectBuilders/Other/OGArticle.php @@ -1,5 +1,10 @@ AppendTag($tags, 'profile:first_name', $profile->getOGFirstName()); diff --git a/src/ObjectBuilders/Other/OGWebsite.php b/src/ObjectBuilders/Other/OGWebsite.php new file mode 100644 index 0000000..6372437 --- /dev/null +++ b/src/ObjectBuilders/Other/OGWebsite.php @@ -0,0 +1,10 @@ +appendRelatedActorList($tags, $namespace, $value->getOGActor()); $this->AppendTag($tags, "$namespace:role", $value->getOGRole()); return; } - + // Handle single song object - if ($value instanceof IOGProfile) { /* @var $value IOGProfile */ - return $this->AppendTag($tags, $namespace, $value->AbsoluteLink()); + if ($value instanceof IOGProfile) { + $this->AppendTag($tags, $namespace, $value->AbsoluteLink()); + return; } // Handle image URL being given if (is_string($value)) { - return $this->AppendTag($tags, $namespace, $value); + $this->AppendTag($tags, $namespace, $value); + return; } // Fail if could not determine presented value type trigger_error('Invalid song type: ' . gettype($value), E_USER_ERROR); } - + protected function appendVideoTags(&$tags, IOGVideo $video) { $this->appendRelatedActorList($tags, 'video:actor', $video->getOGVideoActors()); @@ -60,7 +69,7 @@ protected function appendVideoTags(&$tags, IOGVideo $video) public function BuildTags(&$tags, $object, $config) { parent::BuildTags($tags, $object, $config); - + $this->appendVideoTags($tags, $object); } } diff --git a/code/ObjectBuilders/Video/OGVideoEpisode.php b/src/ObjectBuilders/Video/OGVideoEpisode.php similarity index 68% rename from code/ObjectBuilders/Video/OGVideoEpisode.php rename to src/ObjectBuilders/Video/OGVideoEpisode.php index dcfa83e..0418466 100644 --- a/code/ObjectBuilders/Video/OGVideoEpisode.php +++ b/src/ObjectBuilders/Video/OGVideoEpisode.php @@ -1,9 +1,13 @@ appendEpisodeTags($tags, $object); } } diff --git a/src/ObjectBuilders/Video/OGVideoMovie.php b/src/ObjectBuilders/Video/OGVideoMovie.php new file mode 100644 index 0000000..73fe02e --- /dev/null +++ b/src/ObjectBuilders/Video/OGVideoMovie.php @@ -0,0 +1,11 @@ + $details) { $interface = $details['interface']; if ($object instanceof $interface) { @@ -53,15 +59,15 @@ public static function get_object_type($object) } } } - + /** * Retrieves the configured field, or "SiteConfig" if this should be * managed through the siteconfig instead of yaml configuration - * @return string Value of the configured field + * @return mixed Value of the configured field */ public static function get_config($field) { - return Config::inst()->get('OpenGraph', $field); + return self::config()->get($field); } /** @@ -72,9 +78,9 @@ public static function get_config($field) */ public static function set_config($field, $value = 'SiteConfig') { - Config::inst()->update('OpenGraph', $field, $value); + self::config()->update($field, $value); } - + /** * Sets the application ID of this site, or 'SiteConfig' to manage in CMS * @param string $value @@ -83,7 +89,7 @@ public static function set_application($value) { self::set_config('application_id', $value); } - + /** * Sets the admin ID of this site, or 'SiteConfig' to manage in CMS * @param string $value @@ -92,16 +98,16 @@ public static function set_admin($value) { self::set_config('admin_id', $value); } - + /** * Retrieves the default class used to build tags - * @return type + * @return string type */ public static function get_default_tagbuilder() { return self::get_config('default_tagbuilder'); } - + /** * Retrieves the list of all allowed opengraph locales * @return array Associative array of locale to name. E.g. en_UK => 'English (UK)' @@ -110,12 +116,12 @@ public static function get_locales() { return self::get_config('locales'); } - + public static function get_default_locale() { return self::get_config('default_locale'); } - + /** * Check if a given locale is valid * @param string $locale Locale to test in en_NZ format diff --git a/tests/Extensions/OpenGraphObjectExtensionTest.php b/tests/Extensions/OpenGraphObjectExtensionTest.php new file mode 100644 index 0000000..7ce4266 --- /dev/null +++ b/tests/Extensions/OpenGraphObjectExtensionTest.php @@ -0,0 +1,35 @@ +objFromFixture(TestPage::class, 'page1'); + $this->assertEquals( + ' prefix="og: http://ogp.me/ns# fb: http://www.facebook.com/2008/fbml website: http://ogp.me/ns/website#"', + $page->getOGNS() + ); + } + + public function testOGType() + { + $page = $this->objFromFixture(TestPage::class, 'page1'); + $this->assertEquals('website', $page->getOGType()); + + $profile = $this->objFromFixture(TestProfile::class, 'catwoman'); + $this->assertEquals('profile', $profile->getOGType()); + } +} diff --git a/tests/Model/TestPage.php b/tests/Model/TestPage.php new file mode 100644 index 0000000..5e2d770 --- /dev/null +++ b/tests/Model/TestPage.php @@ -0,0 +1,16 @@ + 'Varchar(255)', + 'Surname' => 'Varchar(255)', + 'Nickname' => 'Varchar(64)', + 'Gender' => "Enum('Male,Female','Female')" + ]; + + private static $extensions = [ + OpenGraphObjectExtension::class + ]; + + private static $table_name = 'OG_TestProfile'; + + public function getTitle() + { + return $this->FirstName . ' ' . $this->Surname; + } + + public function getOGImage() + { + return sprintf('http://example.com/pic/%s.jpg', strtolower($this->Nickname)); + } + + /** + * URI to this object + * Named as below to prevent having to wrap the {@link SiteTree::AbsoluteLink} method explicitly + */ + public function AbsoluteLink() + { + return 'http://example.com/profile/' . strtolower($this->Nickname); + } + + /** + * @return string This person's first name + */ + public function getOGFirstName() + { + return $this->FirstName; + } + + /** + * @return string This person's last name + */ + public function getOGLastName() + { + return $this->Surname; + } + + /** + * @return string A short unique string to identify them. + */ + public function getOGUserName() + { + return $this->Nickname; + } + + /** + * @return string Their gender (male or female only) + */ + public function getOGGender() + { + return strtolower($this->Gender); + } +} diff --git a/tests/ObjectBuilders/OGProfileTest.php b/tests/ObjectBuilders/OGProfileTest.php new file mode 100644 index 0000000..9341753 --- /dev/null +++ b/tests/ObjectBuilders/OGProfileTest.php @@ -0,0 +1,36 @@ +BuildTags($tags, $this->objFromFixture(TestProfile::class, 'tractorcow'), $cfg); + + $this->assertContains('', $tags); + $this->assertContains('', $tags); + $this->assertContains('', $tags); + $this->assertContains('', $tags); + $this->assertContains('', $tags); + $this->assertContains('', $tags); + $this->assertContains('', $tags); + $this->assertContains('', $tags); + } +} diff --git a/tests/ObjectBuilders/OpenGraphBuilderTest.php b/tests/ObjectBuilders/OpenGraphBuilderTest.php new file mode 100644 index 0000000..820ac3e --- /dev/null +++ b/tests/ObjectBuilders/OpenGraphBuilderTest.php @@ -0,0 +1,43 @@ +set(i18n::class, 'default_locale', 'en_US'); + i18n::set_locale('en_US'); + } + + public function testBuildTags() + { + $builder = OpenGraphBuilder::create(); + $tags = ''; + $cfg = SiteConfig::current_site_config(); + $builder->BuildTags($tags, $this->objFromFixture(TestPage::class, 'page1'), $cfg); + + $this->assertContains('', $tags); + $this->assertContains('', $tags); + $this->assertRegExp('{}', $tags); + $this->assertRegExp('{}', $tags); + $this->assertContains('', $tags); + $this->assertContains('', $tags); + } +} diff --git a/tests/OpenGraphTest.php b/tests/OpenGraphTest.php new file mode 100644 index 0000000..2e60ac2 --- /dev/null +++ b/tests/OpenGraphTest.php @@ -0,0 +1,34 @@ +set(OpenGraph::class, 'application_id', 'SiteConfig') + ->set(OpenGraph::class, 'admin_id', 'SiteConfig') + ->set(OpenGraph::class, 'default_locale', 'en_US') + ->set(OpenGraph::class, 'default_tagbuilder', 'TractorCow\OpenGraph\ObjectBuilders\OpenGraphBuilder'); + } + + public function testConfig() + { + $this->assertEquals('SiteConfig', OpenGraph::get_config('application_id')); + $this->assertEquals('SiteConfig', OpenGraph::get_config('admin_id')); + $this->assertEquals('en_US', OpenGraph::get_default_locale()); + $this->assertEquals('TractorCow\OpenGraph\ObjectBuilders\OpenGraphBuilder', OpenGraph::get_default_tagbuilder()); + } + + public function testLocaleValid() + { + $this->assertTrue(OpenGraph::is_locale_valid('en_US')); + $this->assertFalse(OpenGraph::is_locale_valid('en_EN')); + } +} diff --git a/tests/fixtures.yml b/tests/fixtures.yml new file mode 100644 index 0000000..82df219 --- /dev/null +++ b/tests/fixtures.yml @@ -0,0 +1,17 @@ +SilverStripe\SiteConfig\SiteConfig: + default: + Title: "Test Website" +TractorCow\OpenGraph\Tests\Model\TestPage: + page1: + Title: Testpage +TractorCow\OpenGraph\Tests\Model\TestProfile: + tractorcow: + FirstName: Damian + Surname: Mooyman + Nickname: TractorCow + Gender: Male + catwoman: + FirstName: Selina + Surname: Kyle + Nickname: Catwoman + Gender: Female diff --git a/travis.yml b/travis.yml new file mode 100644 index 0000000..e69f918 --- /dev/null +++ b/travis.yml @@ -0,0 +1,41 @@ +language: php +sudo: false +dist: trusty + +env: + global: + - SS_ENVIRONMENT_TYPE="dev" + - DB=MYSQL + +matrix: + include: + - php: 5.6 + env: + - PHPCS_TEST=1 + - PHPUNIT_TEST=1 + - php: 7.0 + env: + - PHPUNIT_TEST=1 + - php: 7.1 + env: + - PHPUNIT_COVERAGE_TEST=1 + +before_script: + # Init PHP + - composer self-update || true + - phpenv rehash + - phpenv config-rm xdebug.ini || true + + # Install composer dependencies + - export PATH=~/.composer/vendor/bin:$PATH + - composer validate + - composer update + - if [[ $PHPCS_TEST ]]; then composer global require squizlabs/php_codesniffer:^3 --prefer-dist --no-interaction --no-progress --no-suggest -o; fi + +script: + - if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit; fi + - if [[ $PHPUNIT_COVERAGE_TEST ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-clover=coverage.xml; fi + - if [[ $PHPCS_TEST ]]; then composer run-script lint; fi + +after_success: + - if [[ $PHPUNIT_COVERAGE_TEST ]]; then bash <(curl -s https://codecov.io/bash) -f coverage.xml; fi