Test Failed
Push — master ( 357bf5...71cdad )
by Russell
03:53
created

ExternalContentSource   A

Complexity

Total Complexity 25

Size/Duplication

Total Lines 318
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 25
eloc 62
c 1
b 0
f 1
dl 0
loc 318
rs 10
1
<?php
2
3
use SilverStripe\ORM\DataObject;
4
use SilverStripe\Forms\TextField;
5
use SilverStripe\Forms\CheckboxField;
6
use SilverStripe\ORM\ArrayList;
7
use SilverStripe\Control\Director;
8
use SilverStripe\Core\Config\Configurable;
9
use SilverStripe\Core\Convert;
10
use SilverStripe\Core\Injector\Injectable;
11
use SilverStripe\ORM\FieldType\DBBoolean;
12
use SilverStripe\ORM\FieldType\DBInt;
13
use SilverStripe\ORM\FieldType\DBText;
14
use SilverStripe\ORM\Hierarchy\Hierarchy;
15
16
/**
17
 * A class that represents any kind of an external content source where the
18
 * data can be represented in a tree state
19
 *
20
 * ExternalContentSources are hierarchical in nature, and are tagged
21
 * with the 'Hierarchy' extension to enable them tTraceo be displayed in
22
 * content trees without problem. Due to their nature though, some of the
23
 * hierarchy functionality is explicitly overridden to prevent DB
24
 * access
25
 *
26
 * @author Marcus Nyeholt <[email protected]>
27
 * @license BSD License http://silverstripe.org/bsd-license
28
 *
29
 */
30
class ExternalContentSource extends DataObject
31
{
32
    use Injectable;
33
    use Configurable;
34
35
    private static $db = array(
36
        'Name' => DBText::class,
37
        'ShowContentInMenu' => DBBoolean::class, // should child items of this be seen in menus?,
38
        'Sort' => DBInt::class,
39
    );
40
41
    private static $defaults = array(
42
        'ParentID' => '0'
43
    );
44
45
    private static $default_source = null;
46
47
    private static $extensions = [
48
        'hierarchy' => Hierarchy::class,
49
    ];
50
51
    private static $table_name = 'ExternalContentSource';
52
53
    /**
54
     * @var string - icon for cms tree
55
     **/
56
    private static $icon = 'cms/images/treeicons/root.png';
57
58
    /**
59
     * @var ArrayList - children
60
     **/
61
    private $children;
62
63
    /**
64
     * Get the object represented by an external ID
65
     *
66
     * All external content sources must override this
67
     * method by providing an implementation that looks up the content in
68
     * the remote data source and returns an ExternalContentItem subclass
69
     * that wraps around that external data.
70
     *
71
     * @param String $objectId
72
     * @return DataObject
73
     */
74
    public function getObject($objectId)
75
    {
76
        throw new \Exception("Child classes MUST provide an implementation of getObject()");
77
    }
78
79
    /**
80
     * Gets the root item of this content source (used in templates if there's
81
     * not one specified)
82
     *
83
     * @return ExternalContentItem
84
     */
85
    public function getRoot()
86
    {
87
        throw new \Exception("Child classes MUST override this method");
88
    }
89
90
    /*
91
     * The following overrides are mostly placeholders, content
92
     * sources aren't really referred to by URL directly
93
     */
94
95
    public function Link($action = null)
96
    {
97
        return Director::baseURL() . $this->RelativeLink($action);
98
    }
99
100
    public function RelativeLink($action = null)
101
    {
102
        return ExternalContentPage_Controller::URL_STUB . '/view/' . $this->ID;
103
    }
104
105
    public function TreeTitle()
106
    {
107
        return $this->Name;
108
    }
109
110
    /**
111
     * Child classes should provide connection details to the external
112
     * content source
113
     *
114
     * @see sapphire/core/model/DataObject#getCMSFields($params)
115
     * @return FieldSet
116
     */
117
    public function getCMSFields()
118
    {
119
        $fields = parent::getCMSFields();
120
121
        $fields->removeByName('Sort');
122
        $fields->removeByName('ParentID');
123
        $fields->addFieldToTab('Root.Main', TextField::create('Name', _t('ExternalContentSource.NAME', 'Name')));
124
        $fields->addFieldToTab('Root.Main', CheckboxField::create("ShowContentInMenu", _t('ExternalContentSource.SHOW_IN_MENUS', 'Show Content in Menus')));
125
126
        return $fields;
127
    }
128
129
    /**
130
     * Override to replace Hierarchy::numChildren
131
     *
132
     * This method should be overridden in child classes to
133
     * handle the functionality in a more efficient way. Doing
134
     * things via the method implemented below will work, but
135
     * could cause several remote calls when it might be
136
     * better to just return 1 and let subsequent requests
137
     * get more children.
138
     *
139
     * @return int
140
     */
141
    public function numChildren()
142
    {
143
        return 1;
144
    }
145
146
    /**
147
     * Get the content importer to use for importing content from
148
     * this external source
149
     *
150
     * The $target parameter lets the user specify a specific type of import,
151
     * depending on where they've chosen to import to.
152
     *
153
     * @param String $target
154
     * 			The type of the target we're importing to (SiteTree, File, User etc)
155
     *
156
     * @return ExternalContentImporter
157
     */
158
    public function getContentImporter($target=null)
159
    {
160
        return null;
161
    }
162
163
    /**
164
     * Return an array of import locations that the importer for
165
     * this content source supports. For example, an alfresco content
166
     * importer may only support importing to the 'file' tree
167
     *
168
     * Return an array of the following format ('false' entries can
169
     * be safely omitted)
170
     *
171
     * array(
172
     * 		'file' => true,
173
     * 		'sitetree' => false,
174
     * )
175
     *
176
     * @return array
177
     */
178
    public function allowedImportTargets()
179
    {
180
        return array();
181
    }
182
183
    /**
184
     * Controls whether the user can create this content source.
185
     *
186
     * @return bool
187
     */
188
    public function canCreate($member = null, $context = [])
189
    {
190
        return true;
191
    }
192
193
    /**
194
     * We flag external content as being editable so it's
195
     * accessible in the backend, but the individual
196
     * implementations will protect users from editing... for now
197
     *
198
     * TODO: Fix this up to use proper permission checks
199
     *
200
     * @see sapphire/core/model/DataObject#canEdit($member)
201
     */
202
    public function canEdit($member = null)
203
    {
204
        return true;
205
    }
206
207
    /**
208
     * Is this item viewable?
209
     *
210
     * Just proxy to the content source for now. Child implementations can
211
     * override if needbe
212
     *
213
     * @see sapphire/core/model/DataObject#canView($member)
214
     */
215
    public function canView($member = null)
216
    {
217
        return true;
218
    }
219
220
    /**
221
     * Returns whether or not this source can be imported, defaulting to true.
222
     *
223
     * @return bool
224
     */
225
    public function canImport()
226
    {
227
        $importer =  $this->getContentImporter();
228
        return $importer != null;
229
    }
230
231
    /**
232
     * Override to return the top level content items from the remote
233
     * content source.
234
     *
235
     * Specific implementations should effectively query the remote
236
     * source for all items that are children of the 'root' node.
237
     *
238
     * @param boolean $showAll
239
     * @return DataObjectSet
240
     */
241
    public function stageChildren($showAll = false)
242
    {
243
        // if we don't have an ID directly, we should load and return ALL the external content sources
244
        if (!$this->ID) {
245
            return DataObject::get(ExternalContentSource::class);
246
        }
247
248
        $children = ArrayList::create();
249
        return $children;
250
    }
251
252
    /**
253
     * Handle a children call by retrieving from stageChildren
254
     */
255
    public function Children()
256
    {
257
        if (!$this->children) {
258
            $this->children = ArrayList::create();
259
            $kids = $this->stageChildren();
260
            if ($kids) {
261
                foreach ($kids as $child) {
262
                    if ($child->canView()) {
263
                        $this->children->push($child);
264
                    }
265
                }
266
            }
267
        }
268
        return $this->children;
269
    }
270
271
    /**
272
     * Helper function to encode a remote ID that is safe to use within
273
     * silverstripe
274
     *
275
     * @param $id
276
     * 			The external content ID
277
     * @return string
278
     * 			A safely encoded ID
279
     */
280
    public function encodeId($id)
281
    {
282
        return str_replace(
283
            array('=', '/', '+'),
284
            array('-', '~' ,','),
285
            base64_encode($id)
286
        );
287
    }
288
289
    /**
290
     * Decode an ID encoded by the above encodeId method
291
     *
292
     * @param String $id
293
     * 			The encoded ID
294
     * @return String
295
     * 			A decoded ID
296
     */
297
    public function decodeId($id)
298
    {
299
        $id= str_replace(
300
            array('-', '~' ,','),
301
            array('=', '/', '+'),
302
            $id
303
        );
304
        return base64_decode($id);
305
    }
306
307
308
    /**
309
     * Return the CSS classes to apply to this node in the CMS tree
310
     *
311
     * @return string
312
     */
313
    public function CMSTreeClasses()
314
    {
315
        $classes = sprintf('class-%s', $this->class);
316
        // Ensure that classes relating to whether there are further nodes to download are included
317
        //$classes .= $this->markingClasses();
318
        return $classes;
319
    }
320
321
322
    /**
323
     * Return the CSS declarations to apply to nodes of this type in the CMS tree
324
     *
325
     * @return string
326
     */
327
    public function CMSTreeCSS()
328
    {
329
        return null;
330
    }
331
332
333
    /**
334
     * getTreeTitle will return two <span> html DOM elements, an empty <span> with
335
     * the class 'jstree-pageicon' in front, following by a <span> wrapping around its
336
     * MenutTitle
337
     *
338
     * @return string a html string ready to be directly used in a template
339
     */
340
    public function getTreeTitle()
341
    {
342
        $treeTitle = sprintf(
343
            "<span class=\"jstree-pageicon\"></span><span class=\"item\">%s</span>",
344
            Convert::raw2xml(str_replace(array("\n","\r"), "", $this->Name))
345
        );
346
347
        return $treeTitle;
348
    }
349
}
350