Issues (50)

src/Service/ResourcePopulator.php (1 issue)

Severity
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
The private property $dependencies is not used, and could be removed.
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