silverstripe /
silverstripe-ckan-registry
| 1 | <?php |
||
| 2 | |||
| 3 | namespace SilverStripe\CKANRegistry\Service; |
||
| 4 | |||
| 5 | use RuntimeException; |
||
| 6 | use SilverStripe\CKANRegistry\Model\Resource; |
||
| 7 | use SilverStripe\CKANRegistry\Model\ResourceField; |
||
| 8 | use SilverStripe\Core\Injector\Injectable; |
||
| 9 | |||
| 10 | /** |
||
| 11 | * This service will take a CKAN Resource and populate its Fields `has_many` relationship and other data |
||
| 12 | * from the CKAN API |
||
| 13 | */ |
||
| 14 | class ResourcePopulator implements ResourcePopulatorInterface |
||
| 15 | { |
||
| 16 | use Injectable; |
||
| 17 | |||
| 18 | private static $dependencies = [ |
||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||
| 19 | 'APIClient' => '%$' . APIClientInterface::class, |
||
| 20 | ]; |
||
| 21 | |||
| 22 | /** |
||
| 23 | * @var APIClientInterface |
||
| 24 | */ |
||
| 25 | protected $apiClient; |
||
| 26 | |||
| 27 | /** |
||
| 28 | * Populates the {@link Resource} with metadata from the API response, such as the name of the data set |
||
| 29 | * |
||
| 30 | * @param Resource $resource |
||
| 31 | * @return $this |
||
| 32 | */ |
||
| 33 | public function populateMetadata(Resource $resource) |
||
| 34 | { |
||
| 35 | $this->validateResource($resource); |
||
| 36 | |||
| 37 | $data = $this->getAPIClient()->getPackage($resource); |
||
| 38 | |||
| 39 | // Get the title of the data set |
||
| 40 | $datasetTitle = isset($data['result']['title']) ? $data['result']['title'] : ''; |
||
| 41 | |||
| 42 | // Get the title of the selected resource |
||
| 43 | $resources = isset($data['result']['resources']) |
||
| 44 | ? array_column($data['result']['resources'], 'name', 'id') |
||
| 45 | : []; |
||
| 46 | $resourceTitle = isset($resources[$resource->Identifier]) ? $resources[$resource->Identifier] : ''; |
||
| 47 | |||
| 48 | $resource->Name = $datasetTitle; |
||
| 49 | $resource->ResourceName = $resourceTitle; |
||
| 50 | |||
| 51 | return $this; |
||
| 52 | } |
||
| 53 | |||
| 54 | /** |
||
| 55 | * Take a CKAN {@link Resource} and populate its Fields `has_many` relationship and other data |
||
| 56 | * from the CKAN API response. |
||
| 57 | * |
||
| 58 | * @param Resource $resource |
||
| 59 | * @return $this |
||
| 60 | */ |
||
| 61 | public function populateFields(Resource $resource) |
||
| 62 | { |
||
| 63 | $this->validateResource($resource); |
||
| 64 | |||
| 65 | $data = $this->getAPIClient()->getSearchData($resource); |
||
| 66 | $fieldSpecs = isset($data['result']['fields']) ? $data['result']['fields'] : []; |
||
| 67 | |||
| 68 | $newFields = []; |
||
| 69 | $fields = $resource->Fields(); |
||
| 70 | $position = 1; |
||
| 71 | |||
| 72 | foreach ($fieldSpecs as $fieldSpec) { |
||
| 73 | $id = $fieldSpec['id']; |
||
| 74 | |||
| 75 | // Skip fields that may already exist |
||
| 76 | if ($fields->find('OriginalLabel', $id)) { |
||
| 77 | continue; |
||
| 78 | } |
||
| 79 | |||
| 80 | // Create a new field |
||
| 81 | $newFields[] = $field = ResourceField::create(); |
||
| 82 | $field->OriginalLabel = $id; |
||
| 83 | $field->Position = $position++; |
||
| 84 | // Attempt to parse a readable name |
||
| 85 | $field->ReadableLabel = $this->parseName($id); |
||
| 86 | $field->Type = $fieldSpec['type']; |
||
| 87 | } |
||
| 88 | |||
| 89 | // Add our new fields |
||
| 90 | $fields->addMany($newFields); |
||
| 91 | |||
| 92 | return $this; |
||
| 93 | } |
||
| 94 | |||
| 95 | /** |
||
| 96 | * Validates that the given {@link Resource} has the necessary data to make the request |
||
| 97 | * |
||
| 98 | * @param Resource $resource |
||
| 99 | * @return bool True if successful |
||
| 100 | * @throws RuntimeException If validation fails |
||
| 101 | */ |
||
| 102 | protected function validateResource(Resource $resource) |
||
| 103 | { |
||
| 104 | if (!$resource->Endpoint || !$resource->DataSet || !$resource->Identifier) { |
||
| 105 | throw new RuntimeException('Could not fetch fields for a resource that is not fully configured'); |
||
| 106 | } |
||
| 107 | return true; |
||
| 108 | } |
||
| 109 | |||
| 110 | /** |
||
| 111 | * Parse given column ID for a more readable version |
||
| 112 | * |
||
| 113 | * @param string $id |
||
| 114 | * @return string |
||
| 115 | */ |
||
| 116 | protected function parseName($id) |
||
| 117 | { |
||
| 118 | // Parse "camelCase" to "space case" |
||
| 119 | $name = strtolower(preg_replace('/(?<=[a-z\d])([A-Z])/', ' \1', $id)); |
||
| 120 | |||
| 121 | // Swap out certain characters with spaces |
||
| 122 | $name = str_replace(['_', '-'], ' ', $name); |
||
| 123 | |||
| 124 | // Remove some non-alphanumeric characters |
||
| 125 | $name = trim(preg_replace('/[^\/\w\s]/', '', $name)); |
||
| 126 | |||
| 127 | // Remove extra spaces around slashes |
||
| 128 | $name = str_replace(' / ', '/', $name); |
||
| 129 | |||
| 130 | return ucfirst($name); |
||
| 131 | } |
||
| 132 | |||
| 133 | /** |
||
| 134 | * @return APIClientInterface |
||
| 135 | */ |
||
| 136 | public function getAPIClient() |
||
| 137 | { |
||
| 138 | return $this->apiClient; |
||
| 139 | } |
||
| 140 | |||
| 141 | /** |
||
| 142 | * @param APIClientInterface $client |
||
| 143 | * @return $this |
||
| 144 | */ |
||
| 145 | public function setAPIClient(APIClientInterface $apiClient) |
||
| 146 | { |
||
| 147 | $this->apiClient = $apiClient; |
||
| 148 | return $this; |
||
| 149 | } |
||
| 150 | } |
||
| 151 |