Blueprints.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. <?php
  2. namespace Grav\Common\Data;
  3. use Grav\Common\File\CompiledYamlFile;
  4. use Grav\Common\GravTrait;
  5. use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator;
  6. /**
  7. * Blueprints class keeps track on blueprint instances.
  8. *
  9. * @author RocketTheme
  10. * @license MIT
  11. */
  12. class Blueprints
  13. {
  14. use GravTrait;
  15. protected $search;
  16. protected $types;
  17. protected $instances = array();
  18. /**
  19. * @param string|array $search Search path.
  20. */
  21. public function __construct($search)
  22. {
  23. $this->search = $search;
  24. }
  25. /**
  26. * Get blueprint.
  27. *
  28. * @param string $type Blueprint type.
  29. * @return Blueprint
  30. * @throws \RuntimeException
  31. */
  32. public function get($type)
  33. {
  34. if (!isset($this->instances[$type])) {
  35. $parents = [];
  36. if (is_string($this->search)) {
  37. $filename = $this->search . $type . YAML_EXT;
  38. // Check if search is a stream and resolve the path.
  39. if (strpos($filename, '://')) {
  40. $grav = static::getGrav();
  41. /** @var UniformResourceLocator $locator */
  42. $locator = $grav['locator'];
  43. $parents = $locator->findResources($filename);
  44. $filename = array_shift($parents);
  45. }
  46. } else {
  47. $filename = isset($this->search[$type]) ? $this->search[$type] : '';
  48. }
  49. if ($filename && is_file($filename)) {
  50. $file = CompiledYamlFile::instance($filename);
  51. $blueprints = $file->content();
  52. } else {
  53. $blueprints = [];
  54. }
  55. $blueprint = new Blueprint($type, $blueprints, $this);
  56. if (isset($blueprints['@extends'])) {
  57. // Extend blueprint by other blueprints.
  58. $extends = (array) $blueprints['@extends'];
  59. if (is_string(key($extends))) {
  60. $extends = [ $extends ];
  61. }
  62. foreach ($extends as $extendConfig) {
  63. $extendType = !is_string($extendConfig) ? empty($extendConfig['type']) ? false : $extendConfig['type'] : $extendConfig;
  64. if (!$extendType) {
  65. continue;
  66. } elseif ($extendType === '@parent') {
  67. $parentFile = array_shift($parents);
  68. if (!$parentFile || !is_file($parentFile)) {
  69. continue;
  70. }
  71. $blueprints = CompiledYamlFile::instance($parentFile)->content();
  72. $parent = new Blueprint($type.'-parent', $blueprints, $this);
  73. $blueprint->extend($parent);
  74. continue;
  75. }
  76. if (is_string($extendConfig) || empty($extendConfig['context'])) {
  77. $context = $this;
  78. } else {
  79. // Load blueprints from external context.
  80. $array = explode('://', $extendConfig['context'], 2);
  81. $scheme = array_shift($array);
  82. $path = array_shift($array);
  83. if ($path) {
  84. $scheme .= '://';
  85. $extendType = $path ? "{$path}/{$extendType}" : $extendType;
  86. }
  87. $context = new self($scheme);
  88. }
  89. $blueprint->extend($context->get($extendType));
  90. }
  91. }
  92. $this->instances[$type] = $blueprint;
  93. }
  94. return $this->instances[$type];
  95. }
  96. /**
  97. * Get all available blueprint types.
  98. *
  99. * @return array List of type=>name
  100. */
  101. public function types()
  102. {
  103. if ($this->types === null) {
  104. $this->types = array();
  105. // Check if search is a stream.
  106. if (strpos($this->search, '://')) {
  107. // Stream: use UniformResourceIterator.
  108. $grav = static::getGrav();
  109. /** @var UniformResourceLocator $locator */
  110. $locator = $grav['locator'];
  111. $iterator = $locator->getIterator($this->search, null);
  112. } else {
  113. // Not a stream: use DirectoryIterator.
  114. $iterator = new \DirectoryIterator($this->search);
  115. }
  116. /** @var \DirectoryIterator $file */
  117. foreach ($iterator as $file) {
  118. if (!$file->isFile() || '.' . $file->getExtension() != YAML_EXT) {
  119. continue;
  120. }
  121. $name = $file->getBasename(YAML_EXT);
  122. $this->types[$name] = ucfirst(strtr($name, '_', ' '));
  123. }
  124. }
  125. return $this->types;
  126. }
  127. }