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 |