PageRenderTime 4970ms CodeModel.GetById 27ms RepoModel.GetById 5ms app.codeStats 0ms

/OData Producer for PHP/library/ODataProducer/Writers/Metadata/MetadataResourceTypeSet.php

#
PHP | 316 lines | 134 code | 27 blank | 155 comment | 18 complexity | 799412b05b9ea0f4c6d82608ef803598 MD5 | raw file
  1. <?php
  2. /**
  3. * Finds all visible resource sets and types from the given provider
  4. *
  5. * Iterate over all resource (entity) types belongs to
  6. * visible resource (entity) sets,for each entity type
  7. * retrieve its derived and base resource types,
  8. * group these resource types (base types, type, derived types)
  9. * based on the namespace in which it falls.
  10. * Note: DataServiceConfiguration::setEntitySetAccessRule is used to
  11. * make a resource set visible
  12. *
  13. * Iterate through the properties of each resource (entity) type,
  14. * retrieve resource type of complex properties,
  15. * group these resource types based on namespace in which it falls.
  16. *
  17. * PHP version 5.3
  18. *
  19. * @category ODataProducer
  20. * @package ODataProducer_Writers_Metadata
  21. * @author Anu T Chandy <odataphpproducer_alias@microsoft.com>
  22. * @copyright 2011 Microsoft Corp. (http://www.microsoft.com)
  23. * @license New BSD license, (http://www.opensource.org/licenses/bsd-license.php)
  24. * @version SVN: 1.0
  25. * @link http://odataphpproducer.codeplex.com
  26. *
  27. */
  28. namespace ODataProducer\Writers\Metadata;
  29. use ODataProducer\Common\Messages;
  30. use ODataProducer\Common\InvalidOperationException;
  31. use ODataProducer\Providers\Metadata\ResourcePropertyKind;
  32. use ODataProducer\Providers\Metadata\ResourceSetWrapper;
  33. use ODataProducer\Providers\Metadata\ResourceType;
  34. use ODataProducer\Providers\Metadata\ResourceTypeKind;
  35. use ODataProducer\Providers\MetadataQueryProviderWrapper;
  36. /**
  37. * Resource type set class for metadata
  38. *
  39. * @category ODataProducer
  40. * @package ODataProducer_Writers_Metadata
  41. * @author Anu T Chandy <odataphpproducer_alias@microsoft.com>
  42. * @copyright 2011 Microsoft Corp. (http://www.microsoft.com)
  43. * @license New BSD license, (http://www.opensource.org/licenses/bsd-license.php)
  44. * @version Release: 1.0
  45. * @link http://odataphpproducer.codeplex.com
  46. */
  47. class MetadataResourceTypeSet extends MetadataBase
  48. {
  49. /**
  50. * Array of namespace along with the resource types in that namespace.
  51. * Namespace will be the key and value will be array of 'ResourceType'
  52. * in that namespace
  53. * (as key value pair key: Resource type name, value:ResourceType))
  54. * array(namespace_name, array(resource_type_name, ResourceType))
  55. *
  56. * @var array(string, array(string, ResourceType))
  57. */
  58. private $_resourceTypes = array();
  59. /**
  60. * Array of all resource types
  61. *
  62. * @var array(ResourceType)
  63. */
  64. private $_resourceTypesNoNamespace = null;
  65. /**
  66. * Set to true if found any visible MLE in the resource (entity) types
  67. *
  68. * @var boolean
  69. */
  70. private $_hasVisibleMediaLinkEntry = false;
  71. /**
  72. * Set to true if found any visible named streams in the resource (entity) types
  73. *
  74. * @var boolean
  75. */
  76. private $_hasVisibleNamedStreams = false;
  77. /**
  78. * Set to true if found any bag property in the resource (entity) types
  79. *
  80. * @var boolean
  81. */
  82. private $_hasBagProperty = false;
  83. /**
  84. * Construct new instance of MetadataResourceTypeSet, this constructor
  85. * finds and caches all resource types in the service
  86. *
  87. * @param MetadataQueryProviderWrapper $provider Reference to the
  88. * service metadata and query provider wrapper
  89. */
  90. public function __construct(MetadataQueryProviderWrapper $provider)
  91. {
  92. parent::__construct($provider);
  93. foreach ($this->metadataQueryproviderWrapper->getResourceSets() as $resourceSetWrapper) {
  94. $this->_populateResourceTypeForSet($resourceSetWrapper);
  95. }
  96. }
  97. /**
  98. * To check is there any MLE resource type
  99. *
  100. * @return boolean
  101. */
  102. public function hasMediaLinkEntry()
  103. {
  104. return $this->_hasVisibleMediaLinkEntry;
  105. }
  106. /**
  107. * To check is there any resource type with named stream prtoperty
  108. *
  109. * @return boolean
  110. */
  111. public function hasNamedStreams()
  112. {
  113. return $this->_hasVisibleNamedStreams;
  114. }
  115. /**
  116. * To check is there any resource type with bag prtoperty
  117. *
  118. * @return boolean
  119. */
  120. public function hasBagProperty()
  121. {
  122. return $this->_hasBagProperty;
  123. }
  124. /**
  125. * Gets collection of resource types belongs to the
  126. * given namespace, creates a collection
  127. * for the namespace, if its not already there.
  128. *
  129. * @param string $namespace The namespace name to get the
  130. * resource types belongs to
  131. *
  132. * @return array(string, ResourceType)
  133. */
  134. public function &getResourceTypesForNamespace($namespace)
  135. {
  136. if (!array_key_exists($namespace, $this->_resourceTypes)) {
  137. $this->_resourceTypes[$namespace] = array();
  138. }
  139. return $this->_resourceTypes[$namespace];
  140. }
  141. /**
  142. * Gets collection of resource types with their namespace.
  143. *
  144. * @return array(string, array(string, ResourceType))
  145. */
  146. public function getResourceTypesAlongWithNamespace()
  147. {
  148. return $this->_resourceTypes;
  149. }
  150. /**
  151. * Gets collection of all resource type in the service.
  152. *
  153. * @return array(ResourceType)
  154. */
  155. public function getResourceTypes()
  156. {
  157. if (is_null($this->_resourceTypesNoNamespace)) {
  158. $this->_resourceTypesNoNamespace = array();
  159. foreach ($this->_resourceTypes as $nameSpace => $resourceTypeWithName) {
  160. foreach ($resourceTypeWithName as $typeName => $resourceType) {
  161. $this->_resourceTypesNoNamespace[] = $resourceType;
  162. }
  163. }
  164. }
  165. return $this->_resourceTypesNoNamespace;
  166. }
  167. /**
  168. * Gets array of all visible resource properties from a resource type
  169. *
  170. * @param ResourceType $resourceType The resource type to inspect
  171. *
  172. * @return array(ResourceProperty)
  173. */
  174. public function getAllVisiblePropertiesDeclaredOnThisType(ResourceType $resourceType)
  175. {
  176. $visibleProperties = array();
  177. foreach ($resourceType->getPropertiesDeclaredOnThisType() as $name => $resourceProperty) {
  178. if ($resourceProperty->getTypeKind() == ResourceTypeKind::ENTITY) {
  179. $resourceType = $resourceProperty->getResourceType();
  180. $resourceTypeNamespace = $this->getResourceTypeNamespace($resourceType);
  181. $resourceTypesInNamespace = $this->getResourceTypesForNamespace($resourceTypeNamespace);
  182. if (!array_key_exists($resourceTypeNamespace . '.' . $resourceType->getName(), $resourceTypesInNamespace)) {
  183. continue;
  184. }
  185. }
  186. $visibleProperties[] = $resourceProperty;
  187. }
  188. return $visibleProperties;
  189. }
  190. /**
  191. * Iterate over the resource type of the given resource set,
  192. * derived resource types base resource types and complex types
  193. * used in these resource types and cache them.
  194. *
  195. * @param ResourceSetWrapper $resourceSetWrapper The resource set to inspect
  196. *
  197. * @return void
  198. *
  199. * @throws InvalidOperationException Throws exception in floowing cases:
  200. * (1) If IDSMP::getDerivedTypes returns any type other than null or array
  201. * (2) If Named streams are found on derived types
  202. */
  203. private function _populateResourceTypeForSet(ResourceSetWrapper $resourceSetWrapper)
  204. {
  205. $derivedTypes = $this->metadataQueryproviderWrapper->getDerivedTypes($resourceSetWrapper->getResourceType());
  206. if (!is_null($derivedTypes)) {
  207. if (!is_array($derivedTypes)) {
  208. throw new InvalidOperationException(Messages::metadataAssociationTypeSetInvalidGetDerivedTypesReturnType($resourceSetWrapper->getName()));
  209. }
  210. //Populate Resource type for derived types and
  211. //complex types in derived types
  212. foreach ($derivedTypes as $derivedType) {
  213. if ($derivedType->hasNamedStream()) {
  214. throw new InvalidOperationException(Messages::metadataResourceTypeSetNamedStreamsOnDerivedEntityTypesNotSupported($resourceSetWrapper->getName(), $derivedType->getFullName()));
  215. }
  216. $this->_populateResourceTypes($derivedType);
  217. $this->_populateComplexTypes($derivedType);
  218. }
  219. }
  220. //Populate Resource type for for this type and
  221. //base types and complex types in this type and base types
  222. $resourceType = $resourceSetWrapper->getResourceType();
  223. while ($resourceType != null) {
  224. $this->_populateResourceTypes($resourceType);
  225. $this->_populateComplexTypes($resourceType);
  226. $resourceType = $resourceType->getBaseType();
  227. }
  228. }
  229. /**
  230. * Store the given resource type into the
  231. * cache for the resource type namespace, if not already cached,
  232. * also check for MLE and named stream to set the corrosponding
  233. * class level properties.
  234. *
  235. * @param ResourceType $resourceType The resource type to cache
  236. *
  237. * @return boolean True if the resource type is already in the cache,
  238. * false otherwise
  239. */
  240. private function _populateResourceTypes(ResourceType $resourceType)
  241. {
  242. $resourceTypeNamespace = $this->getResourceTypeNamespace($resourceType);
  243. $resourceTypesInNamespace = &$this->getResourceTypesForNamespace($resourceTypeNamespace);
  244. $resourceNameWithNamespace = $resourceTypeNamespace . '.' . $resourceType->getName();
  245. if (!array_key_exists($resourceNameWithNamespace, $resourceTypesInNamespace)) {
  246. if ($resourceType->isMediaLinkEntry()) {
  247. $this->_hasVisibleMediaLinkEntry = true;
  248. }
  249. if ($resourceType->hasNamedStream()) {
  250. $this->_hasVisibleNamedStreams = true;
  251. }
  252. $arrayToDetectLoop = array();
  253. if ($resourceType->hasBagProperty($arrayToDetectLoop)) {
  254. $this->_hasBagProperty = true;
  255. }
  256. $resourceTypesInNamespace[$resourceNameWithNamespace] = $resourceType;
  257. return true;
  258. }
  259. return false;
  260. }
  261. /**
  262. * Retrieve the complex type(s) used in the given resource type and cache them.
  263. *
  264. * @param ResourceType $resourceType The resource type to inspect
  265. *
  266. * @return void
  267. *
  268. * @throws InvalidOperationException If found any complex type bag property
  269. * with derived type(s)
  270. */
  271. private function _populateComplexTypes(ResourceType $resourceType)
  272. {
  273. foreach ($resourceType->getPropertiesDeclaredOnThisType() as $property) {
  274. if ($property->isKindOf(ResourcePropertyKind::COMPLEX_TYPE)) {
  275. if ($property->isKindOf(ResourcePropertyKind::BAG)) {
  276. //Validate the bag complex type
  277. //as it should not have derived type
  278. if ($this->metadataQueryproviderWrapper->hasDerivedTypes($resourceType)) {
  279. throw new InvalidOperationException(Messages::metadataResourceTypeSetBagOfComplexTypeWithDerivedTypes($resourceType->getFullName()));
  280. }
  281. }
  282. if ($this->_populateResourceTypes($property->getResourceType())) {
  283. $this->_populateComplexTypes($property->getResourceType());
  284. }
  285. }
  286. }
  287. }
  288. }
  289. ?>