diff options
author | emkael <emkael@tlen.pl> | 2017-01-16 22:04:43 +0100 |
---|---|---|
committer | emkael <emkael@tlen.pl> | 2017-01-16 22:50:24 +0100 |
commit | 677953067f2bb5502a70f0d004f1ac844b18a128 (patch) | |
tree | 003c26454b543c2a8d73f0602446482fdbbef8db /lib/facebook-graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php | |
parent | f7b2bfae9778af2c99e0c7fe7b2634e0f4f0973f (diff) |
* Facebook support
Diffstat (limited to 'lib/facebook-graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php')
-rw-r--r-- | lib/facebook-graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/lib/facebook-graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php b/lib/facebook-graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php new file mode 100644 index 0000000..e1bedd9 --- /dev/null +++ b/lib/facebook-graph-sdk/src/Facebook/GraphNodes/GraphNodeFactory.php @@ -0,0 +1,392 @@ +<?php +/** + * Copyright 2014 Facebook, Inc. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to + * use, copy, modify, and distribute this software in source code or binary + * form for use in connection with the web services and APIs provided by + * Facebook. + * + * As with any software that integrates with the Facebook platform, your use + * of this software is subject to the Facebook Developer Principles and + * Policies [http://developers.facebook.com/policy/]. This copyright notice + * shall be included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ +namespace Facebook\GraphNodes; + +use Facebook\FacebookResponse; +use Facebook\Exceptions\FacebookSDKException; + +/** + * Class GraphNodeFactory + * + * @package Facebook + * + * ## Assumptions ## + * GraphEdge - is ALWAYS a numeric array + * GraphEdge - is ALWAYS an array of GraphNode types + * GraphNode - is ALWAYS an associative array + * GraphNode - MAY contain GraphNode's "recurrable" + * GraphNode - MAY contain GraphEdge's "recurrable" + * GraphNode - MAY contain DateTime's "primitives" + * GraphNode - MAY contain string's "primitives" + */ +class GraphNodeFactory +{ + /** + * @const string The base graph object class. + */ + const BASE_GRAPH_NODE_CLASS = '\Facebook\GraphNodes\GraphNode'; + + /** + * @const string The base graph edge class. + */ + const BASE_GRAPH_EDGE_CLASS = '\Facebook\GraphNodes\GraphEdge'; + + /** + * @const string The graph object prefix. + */ + const BASE_GRAPH_OBJECT_PREFIX = '\Facebook\GraphNodes\\'; + + /** + * @var FacebookResponse The response entity from Graph. + */ + protected $response; + + /** + * @var array The decoded body of the FacebookResponse entity from Graph. + */ + protected $decodedBody; + + /** + * Init this Graph object. + * + * @param FacebookResponse $response The response entity from Graph. + */ + public function __construct(FacebookResponse $response) + { + $this->response = $response; + $this->decodedBody = $response->getDecodedBody(); + } + + /** + * Tries to convert a FacebookResponse entity into a GraphNode. + * + * @param string|null $subclassName The GraphNode sub class to cast to. + * + * @return GraphNode + * + * @throws FacebookSDKException + */ + public function makeGraphNode($subclassName = null) + { + $this->validateResponseAsArray(); + $this->validateResponseCastableAsGraphNode(); + + return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName); + } + + /** + * Convenience method for creating a GraphAchievement collection. + * + * @return GraphAchievement + * + * @throws FacebookSDKException + */ + public function makeGraphAchievement() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAchievement'); + } + + /** + * Convenience method for creating a GraphAlbum collection. + * + * @return GraphAlbum + * + * @throws FacebookSDKException + */ + public function makeGraphAlbum() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphAlbum'); + } + + /** + * Convenience method for creating a GraphPage collection. + * + * @return GraphPage + * + * @throws FacebookSDKException + */ + public function makeGraphPage() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphPage'); + } + + /** + * Convenience method for creating a GraphSessionInfo collection. + * + * @return GraphSessionInfo + * + * @throws FacebookSDKException + */ + public function makeGraphSessionInfo() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphSessionInfo'); + } + + /** + * Convenience method for creating a GraphUser collection. + * + * @return GraphUser + * + * @throws FacebookSDKException + */ + public function makeGraphUser() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphUser'); + } + + /** + * Convenience method for creating a GraphEvent collection. + * + * @return GraphEvent + * + * @throws FacebookSDKException + */ + public function makeGraphEvent() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphEvent'); + } + + /** + * Convenience method for creating a GraphGroup collection. + * + * @return GraphGroup + * + * @throws FacebookSDKException + */ + public function makeGraphGroup() + { + return $this->makeGraphNode(static::BASE_GRAPH_OBJECT_PREFIX . 'GraphGroup'); + } + + /** + * Tries to convert a FacebookResponse entity into a GraphEdge. + * + * @param string|null $subclassName The GraphNode sub class to cast the list items to. + * @param boolean $auto_prefix Toggle to auto-prefix the subclass name. + * + * @return GraphEdge + * + * @throws FacebookSDKException + */ + public function makeGraphEdge($subclassName = null, $auto_prefix = true) + { + $this->validateResponseAsArray(); + $this->validateResponseCastableAsGraphEdge(); + + if ($subclassName && $auto_prefix) { + $subclassName = static::BASE_GRAPH_OBJECT_PREFIX . $subclassName; + } + + return $this->castAsGraphNodeOrGraphEdge($this->decodedBody, $subclassName); + } + + /** + * Validates the decoded body. + * + * @throws FacebookSDKException + */ + public function validateResponseAsArray() + { + if (!is_array($this->decodedBody)) { + throw new FacebookSDKException('Unable to get response from Graph as array.', 620); + } + } + + /** + * Validates that the return data can be cast as a GraphNode. + * + * @throws FacebookSDKException + */ + public function validateResponseCastableAsGraphNode() + { + if (isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data'])) { + throw new FacebookSDKException( + 'Unable to convert response from Graph to a GraphNode because the response looks like a GraphEdge. Try using GraphNodeFactory::makeGraphEdge() instead.', + 620 + ); + } + } + + /** + * Validates that the return data can be cast as a GraphEdge. + * + * @throws FacebookSDKException + */ + public function validateResponseCastableAsGraphEdge() + { + if (!(isset($this->decodedBody['data']) && static::isCastableAsGraphEdge($this->decodedBody['data']))) { + throw new FacebookSDKException( + 'Unable to convert response from Graph to a GraphEdge because the response does not look like a GraphEdge. Try using GraphNodeFactory::makeGraphNode() instead.', + 620 + ); + } + } + + /** + * Safely instantiates a GraphNode of $subclassName. + * + * @param array $data The array of data to iterate over. + * @param string|null $subclassName The subclass to cast this collection to. + * + * @return GraphNode + * + * @throws FacebookSDKException + */ + public function safelyMakeGraphNode(array $data, $subclassName = null) + { + $subclassName = $subclassName ?: static::BASE_GRAPH_NODE_CLASS; + static::validateSubclass($subclassName); + + // Remember the parent node ID + $parentNodeId = isset($data['id']) ? $data['id'] : null; + + $items = []; + + foreach ($data as $k => $v) { + // Array means could be recurable + if (is_array($v)) { + // Detect any smart-casting from the $graphObjectMap array. + // This is always empty on the GraphNode collection, but subclasses can define + // their own array of smart-casting types. + $graphObjectMap = $subclassName::getObjectMap(); + $objectSubClass = isset($graphObjectMap[$k]) + ? $graphObjectMap[$k] + : null; + + // Could be a GraphEdge or GraphNode + $items[$k] = $this->castAsGraphNodeOrGraphEdge($v, $objectSubClass, $k, $parentNodeId); + } else { + $items[$k] = $v; + } + } + + return new $subclassName($items); + } + + /** + * Takes an array of values and determines how to cast each node. + * + * @param array $data The array of data to iterate over. + * @param string|null $subclassName The subclass to cast this collection to. + * @param string|null $parentKey The key of this data (Graph edge). + * @param string|null $parentNodeId The parent Graph node ID. + * + * @return GraphNode|GraphEdge + * + * @throws FacebookSDKException + */ + public function castAsGraphNodeOrGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null) + { + if (isset($data['data'])) { + // Create GraphEdge + if (static::isCastableAsGraphEdge($data['data'])) { + return $this->safelyMakeGraphEdge($data, $subclassName, $parentKey, $parentNodeId); + } + // Sometimes Graph is a weirdo and returns a GraphNode under the "data" key + $data = $data['data']; + } + + // Create GraphNode + return $this->safelyMakeGraphNode($data, $subclassName); + } + + /** + * Return an array of GraphNode's. + * + * @param array $data The array of data to iterate over. + * @param string|null $subclassName The GraphNode subclass to cast each item in the list to. + * @param string|null $parentKey The key of this data (Graph edge). + * @param string|null $parentNodeId The parent Graph node ID. + * + * @return GraphEdge + * + * @throws FacebookSDKException + */ + public function safelyMakeGraphEdge(array $data, $subclassName = null, $parentKey = null, $parentNodeId = null) + { + if (!isset($data['data'])) { + throw new FacebookSDKException('Cannot cast data to GraphEdge. Expected a "data" key.', 620); + } + + $dataList = []; + foreach ($data['data'] as $graphNode) { + $dataList[] = $this->safelyMakeGraphNode($graphNode, $subclassName, $parentKey, $parentNodeId); + } + + $metaData = $this->getMetaData($data); + + // We'll need to make an edge endpoint for this in case it's a GraphEdge (for cursor pagination) + $parentGraphEdgeEndpoint = $parentNodeId && $parentKey ? '/' . $parentNodeId . '/' . $parentKey : null; + $className = static::BASE_GRAPH_EDGE_CLASS; + + return new $className($this->response->getRequest(), $dataList, $metaData, $parentGraphEdgeEndpoint, $subclassName); + } + + /** + * Get the meta data from a list in a Graph response. + * + * @param array $data The Graph response. + * + * @return array + */ + public function getMetaData(array $data) + { + unset($data['data']); + + return $data; + } + + /** + * Determines whether or not the data should be cast as a GraphEdge. + * + * @param array $data + * + * @return boolean + */ + public static function isCastableAsGraphEdge(array $data) + { + if ($data === []) { + return true; + } + + // Checks for a sequential numeric array which would be a GraphEdge + return array_keys($data) === range(0, count($data) - 1); + } + + /** + * Ensures that the subclass in question is valid. + * + * @param string $subclassName The GraphNode subclass to validate. + * + * @throws FacebookSDKException + */ + public static function validateSubclass($subclassName) + { + if ($subclassName == static::BASE_GRAPH_NODE_CLASS || is_subclass_of($subclassName, static::BASE_GRAPH_NODE_CLASS)) { + return; + } + + throw new FacebookSDKException('The given subclass "' . $subclassName . '" is not valid. Cannot cast to an object that is not a GraphNode subclass.', 620); + } +} |