StreamWrapperManager.php 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <?php
  2. namespace Drupal\Core\StreamWrapper;
  3. use Symfony\Component\DependencyInjection\ContainerAwareInterface;
  4. use Symfony\Component\DependencyInjection\ContainerAwareTrait;
  5. /**
  6. * Provides a StreamWrapper manager.
  7. *
  8. * @see \Drupal\Core\StreamWrapper\StreamWrapperInterface
  9. */
  10. class StreamWrapperManager implements ContainerAwareInterface, StreamWrapperManagerInterface {
  11. use ContainerAwareTrait;
  12. /**
  13. * Contains stream wrapper info.
  14. *
  15. * An associative array where keys are scheme names and values are themselves
  16. * associative arrays with the keys class, type and (optionally) service_id,
  17. * and string values.
  18. *
  19. * @var array
  20. */
  21. protected $info = [];
  22. /**
  23. * Contains collected stream wrappers.
  24. *
  25. * Keyed by filter, each value is itself an associative array keyed by scheme.
  26. * Each of those values is an array representing a stream wrapper, with the
  27. * following keys and values:
  28. * - class: stream wrapper class name
  29. * - type: a bitmask corresponding to the type constants in
  30. * StreamWrapperInterface
  31. * - service_id: name of service
  32. *
  33. * The array on key StreamWrapperInterface::ALL contains representations of
  34. * all schemes and corresponding wrappers.
  35. *
  36. * @var array
  37. */
  38. protected $wrappers = [];
  39. /**
  40. * {@inheritdoc}
  41. */
  42. public function getWrappers($filter = StreamWrapperInterface::ALL) {
  43. if (isset($this->wrappers[$filter])) {
  44. return $this->wrappers[$filter];
  45. }
  46. elseif (isset($this->wrappers[StreamWrapperInterface::ALL])) {
  47. $this->wrappers[$filter] = [];
  48. foreach ($this->wrappers[StreamWrapperInterface::ALL] as $scheme => $info) {
  49. // Bit-wise filter.
  50. if (($info['type'] & $filter) == $filter) {
  51. $this->wrappers[$filter][$scheme] = $info;
  52. }
  53. }
  54. return $this->wrappers[$filter];
  55. }
  56. else {
  57. return [];
  58. }
  59. }
  60. /**
  61. * {@inheritdoc}
  62. */
  63. public function getNames($filter = StreamWrapperInterface::ALL) {
  64. $names = [];
  65. foreach (array_keys($this->getWrappers($filter)) as $scheme) {
  66. $names[$scheme] = $this->getViaScheme($scheme)->getName();
  67. }
  68. return $names;
  69. }
  70. /**
  71. * {@inheritdoc}
  72. */
  73. public function getDescriptions($filter = StreamWrapperInterface::ALL) {
  74. $descriptions = [];
  75. foreach (array_keys($this->getWrappers($filter)) as $scheme) {
  76. $descriptions[$scheme] = $this->getViaScheme($scheme)->getDescription();
  77. }
  78. return $descriptions;
  79. }
  80. /**
  81. * {@inheritdoc}
  82. */
  83. public function getViaScheme($scheme) {
  84. return $this->getWrapper($scheme, $scheme . '://');
  85. }
  86. /**
  87. * {@inheritdoc}
  88. */
  89. public function getViaUri($uri) {
  90. $scheme = file_uri_scheme($uri);
  91. return $this->getWrapper($scheme, $uri);
  92. }
  93. /**
  94. * {@inheritdoc}
  95. */
  96. public function getClass($scheme) {
  97. if (isset($this->info[$scheme])) {
  98. return $this->info[$scheme]['class'];
  99. }
  100. return FALSE;
  101. }
  102. /**
  103. * Returns a stream wrapper instance.
  104. *
  105. * @param string $scheme
  106. * The scheme of the desired stream wrapper.
  107. * @param string $uri
  108. * The URI of the stream.
  109. *
  110. * @return \Drupal\Core\StreamWrapper\StreamWrapperInterface|bool
  111. * A stream wrapper object, or false if the scheme is not available.
  112. */
  113. protected function getWrapper($scheme, $uri) {
  114. if (isset($this->info[$scheme]['service_id'])) {
  115. $instance = $this->container->get($this->info[$scheme]['service_id']);
  116. $instance->setUri($uri);
  117. return $instance;
  118. }
  119. return FALSE;
  120. }
  121. /**
  122. * Adds a stream wrapper.
  123. *
  124. * Internal use only.
  125. *
  126. * @param string $service_id
  127. * The service id.
  128. * @param string $class
  129. * The stream wrapper class.
  130. * @param string $scheme
  131. * The scheme for which the wrapper should be registered.
  132. */
  133. public function addStreamWrapper($service_id, $class, $scheme) {
  134. $this->info[$scheme] = [
  135. 'class' => $class,
  136. 'type' => $class::getType(),
  137. 'service_id' => $service_id,
  138. ];
  139. }
  140. /**
  141. * Registers the tagged stream wrappers.
  142. *
  143. * Internal use only.
  144. */
  145. public function register() {
  146. foreach ($this->info as $scheme => $info) {
  147. $this->registerWrapper($scheme, $info['class'], $info['type']);
  148. }
  149. }
  150. /**
  151. * Unregisters the tagged stream wrappers.
  152. *
  153. * Internal use only.
  154. */
  155. public function unregister() {
  156. // Normally, there are definitely wrappers set for the ALL filter. However,
  157. // in some cases involving many container rebuilds (e.g. WebTestBase),
  158. // $this->wrappers may be empty although wrappers are still registered
  159. // globally. Thus an isset() check is needed before iterating.
  160. if (isset($this->wrappers[StreamWrapperInterface::ALL])) {
  161. foreach (array_keys($this->wrappers[StreamWrapperInterface::ALL]) as $scheme) {
  162. stream_wrapper_unregister($scheme);
  163. }
  164. }
  165. }
  166. /**
  167. * {@inheritdoc}
  168. */
  169. public function registerWrapper($scheme, $class, $type) {
  170. if (in_array($scheme, stream_get_wrappers(), TRUE)) {
  171. stream_wrapper_unregister($scheme);
  172. }
  173. if (($type & StreamWrapperInterface::LOCAL) == StreamWrapperInterface::LOCAL) {
  174. stream_wrapper_register($scheme, $class);
  175. }
  176. else {
  177. stream_wrapper_register($scheme, $class, STREAM_IS_URL);
  178. }
  179. // Pre-populate the static cache with the filters most typically used.
  180. $info = ['type' => $type, 'class' => $class];
  181. $this->wrappers[StreamWrapperInterface::ALL][$scheme] = $info;
  182. if (($type & StreamWrapperInterface::WRITE_VISIBLE) == StreamWrapperInterface::WRITE_VISIBLE) {
  183. $this->wrappers[StreamWrapperInterface::WRITE_VISIBLE][$scheme] = $info;
  184. }
  185. }
  186. }