Passed
Push — master ( 0b9e04...7d8f18 )
by Nicolaas
03:46
created

SearchAdmin::providePermissions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 5
nc 1
nop 0
dl 0
loc 7
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Sunnysideup\SiteWideSearch\Admin;
4
5
use SilverStripe\Admin\LeftAndMain;
6
use SilverStripe\Control\HTTPResponse;
7
use SilverStripe\Core\ClassInfo;
8
use SilverStripe\Core\Injector\Injector;
9
10
use SilverStripe\Core\Environment;
11
use SilverStripe\Forms\CheckboxField;
12
use SilverStripe\Forms\Form;
13
use SilverStripe\Forms\FormAction;
14
use SilverStripe\Forms\HiddenField;
15
use SilverStripe\Forms\HTMLReadonlyField;
16
use SilverStripe\Forms\LiteralField;
17
use SilverStripe\Forms\OptionsetField;
18
use SilverStripe\Forms\TextField;
19
use SilverStripe\Forms\ToggleCompositeField;
20
use SilverStripe\ORM\ArrayList;
21
use SilverStripe\ORM\DataObject;
22
use SilverStripe\ORM\FieldType\DBField;
23
use SilverStripe\Security\PermissionProvider;
24
use Sunnysideup\SiteWideSearch\Api\SearchApi;
25
use Sunnysideup\SiteWideSearch\QuickSearches\QuickSearchBaseClass;
26
27
class SearchAdmin extends LeftAndMain implements PermissionProvider
28
{
29
    protected $listHTML = '';
30
31
    protected $keywords = '';
32
33
    protected $replace = '';
34
35
    protected $applyReplace = false;
36
37
    protected $quickSearchType = '';
38
39
    protected $searchWholePhrase = false;
40
41
    protected $rawData;
42
43
    private static $default_quick_search_type = 'limited';
44
45
    private static $url_segment = 'find';
46
47
    private static $menu_title = 'Search';
48
49
    private static $menu_icon_class = 'font-icon-p-search';
50
51
    private static $menu_priority = 99999;
52
53
    private static $required_permission_codes = [
54
        'CMS_ACCESS_SITE_WIDE_SEARCH',
55
    ];
56
57
    protected function init()
58
    {
59
        if($this->request->param('Action')) {
60
            if(empty($this->request->postVars())) {
61
                $this->redirect('/admin/find');
62
            }
63
        }
64
        parent::init();
65
    }
66
67
    public function getEditForm($id = null, $fields = null)
68
    {
69
        $form = parent::getEditForm($id, $fields);
70
        $fields = $form->Fields();
71
72
        // if ($form instanceof HTTPResponse) {
73
        //     return $form;
74
        // }
75
        // $fields->removeByName('LastVisited');
76
        $fields->push(
77
            (new TextField('Keywords', 'Keyword(s)', $this->keywords ?? ''))
78
                ->setAttribute('placeholder', 'e.g. agreement')
79
        );
80
        $fields->push(
81
            (new HiddenField('IsSubmitHiddenField', 'IsSubmitHiddenField', 1))
82
        );
83
84
        $options = QuickSearchBaseClass::get_list_of_quick_searches();
85
        $fields->push(
86
            OptionsetField::create(
87
                'QuickSearchType',
88
                'Quick Search',
89
                $options
90
            )->setValue($this->bestSearchType())
91
        );
92
93
        $fields->push(
94
            (new CheckboxField('SearchWholePhrase', 'Search exact phrase', $this->searchWholePhrase))
95
                ->setDescription('If ticked, any item will be included that includes the whole phrase (e.g. New Zealand, rather than New OR Zealand)')
96
        );
97
        $fields->push(
98
            ToggleCompositeField::create(
99
                'ReplaceToggle',
100
                _t(__CLASS__ . '.ReplaceToggle', 'Replace with ... (optional - make a backup first!)'),
101
                [
102
                    (new CheckboxField('ApplyReplace', 'Run replace (please make sure to make a backup first!)', $this->applyReplace))
103
                      ->setDescription('Check this to replace the searched value set above with its replacement value. Note that searches ignore uppercase / lowercase, but replace actions will only search and replace values with the same upper / lowercase.'),
104
                    (new TextField('ReplaceWith', 'Replace (optional - careful!)', $this->replace ?? ''))
105
                        ->setAttribute('placeholder', 'e.g. contract - make sure to also tick checkbox below'),
106
                ]
107
            )->setHeadingLevel(4)
108
        );
109
110
111
        if (!$this->getRequest()->requestVar('Keywords')) {
112
            $lastResults = $this->lastSearchResults();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $lastResults is correct as $this->lastSearchResults() targeting Sunnysideup\SiteWideSear...in::lastSearchResults() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
113
            if($lastResults) {
0 ignored issues
show
introduced by
$lastResults is of type null, thus it always evaluated to false.
Loading history...
114
                $resultsTitle = 'Last Results';
115
            } else {
116
                $resultsTitle = 'Last Edited';
117
            }
118
            $this->listHTML = $this->renderWith(self::class . '_Results');
119
        } else {
120
            $resultsTitle = 'Search Results';
121
        }
122
123
        $form->setFormMethod('get', false);
124
125
        $fields->push(
126
            (new HTMLReadonlyField('List', $resultsTitle, DBField::create_field('HTMLText', $this->listHTML)))
127
        );
128
        $form->Actions()->push(
129
            FormAction::create('search', 'Find')
130
                ->addExtraClass('btn-primary')
131
                ->setUseButtonTag(true)
132
        );
133
        $form->addExtraClass('root-form cms-edit-form center fill-height');
134
        // $form->disableSecurityToken();
135
        // $form->setFormMethod('get');
136
137
        return $form;
138
    }
139
140
    public function search(array $data, Form $form): HTTPResponse
141
    {
142
        if (empty($data['Keywords'])) {
143
            $form->sessionMessage('Please enter one or more keywords', 'bad');
144
145
            return $this->redirectBack();
146
        }
147
148
        $request = $this->getRequest();
149
150
        $this->rawData = $data;
151
        $this->listHTML = $this->renderWith(self::class . '_Results');
152
        // Existing or new record?
153
154
        return $this->getResponseNegotiator()->respond($request);
155
    }
156
157
    /**
158
     * Only show first element, as the profile form is limited to editing
159
     * the current member it doesn't make much sense to show the member name
160
     * in the breadcrumbs.
161
     *
162
     * @param bool $unlinked
163
     *
164
     * @return ArrayList
165
     */
166
    public function Breadcrumbs($unlinked = false)
167
    {
168
        $items = parent::Breadcrumbs($unlinked);
169
170
        return new ArrayList([$items[0]]);
171
    }
172
173
    public function IsQuickSearch(): bool
174
    {
175
        return $this->quickSearchType !== 'all';
176
    }
177
178
    public function SearchResults(): ?ArrayList
179
    {
180
        Environment::increaseTimeLimitTo(300);
181
        Environment::setMemoryLimitMax(-1);
182
        Environment::increaseMemoryLimitTo(-1);
183
        if(empty($this->rawData)) {
184
            $lastResults = $this->lastSearchResults();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $lastResults is correct as $this->lastSearchResults() targeting Sunnysideup\SiteWideSear...in::lastSearchResults() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
185
            if($lastResults) {
0 ignored issues
show
introduced by
$lastResults is of type null, thus it always evaluated to false.
Loading history...
186
                return $lastResults;
187
            }
188
        }
189
        $this->keywords = $this->workOutString('Keywords', $this->rawData);
190
        $this->quickSearchType = $this->workOutString('QuickSearchType', $this->rawData, $this->bestSearchType());
191
        $this->searchWholePhrase = $this->workOutBoolean('SearchWholePhrase', $this->rawData, false);
192
        $this->applyReplace = isset($this->rawData['ReplaceWith']) && $this->workOutBoolean('ApplyReplace', $this->rawData, false);
193
        $this->replace = $this->workOutString('ReplaceWith', $this->rawData);
194
        if ($this->applyReplace) {
195
            Injector::inst()->get(SearchApi::class)
196
                ->setQuickSearchType($this->quickSearchType)
197
                ->setSearchWholePhrase(true)
198
                ->setWordsAsString($this->keywords)
199
                ->buildCache() // make sure we have the lastest cache!
200
                ->doReplacement($this->keywords, $this->replace)
201
            ;
202
            $this->applyReplace = false;
203
        }
204
205
        $results = Injector::inst()->get(SearchApi::class)
206
            ->setQuickSearchType($this->quickSearchType)
207
            ->setSearchWholePhrase($this->searchWholePhrase)
208
            ->setWordsAsString($this->keywords)
209
            ->getLinks()
210
        ;
211
        if($results->count() === 1) {
212
            $result = $results->first();
213
            $this->redirect($result->CMSEditLink);
214
            return null;
215
        }
216
        // Accessing the session
217
        $session = $this->getRequest()->getSession();
218
        if($session) {
0 ignored issues
show
introduced by
$session is of type SilverStripe\Control\Session, thus it always evaluated to true.
Loading history...
219
            $session->set('QuickSearchLastResults', serialize($results->toArray()));
220
        }
221
        return $results;
222
    }
223
224
    protected function workOutBoolean(string $fieldName, ?array $data = null, ?bool $default = false): bool
225
    {
226
        return (bool) (isset($data['IsSubmitHiddenField']) ? !empty($data[$fieldName]) : $default);
227
    }
228
229
    protected function workOutString(string $fieldName, ?array $data = null, ?string $default = ''): string
230
    {
231
        return trim($data[$fieldName] ?? $default);
0 ignored issues
show
Bug introduced by
It seems like $data[$fieldName] ?? $default can also be of type null; however, parameter $string of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

231
        return trim(/** @scrutinizer ignore-type */ $data[$fieldName] ?? $default);
Loading history...
232
    }
233
234
    public function providePermissions()
235
    {
236
        return [
237
            'CMS_ACCESS_SITE_WIDE_SEARCH' => [
238
                'name' => 'Access to Search Website in the CMS',
239
                'category' => _t('SilverStripe\\Security\\Permission.CMS_ACCESS_CATEGORY', 'CMS Access'),
240
                'help' => 'Allow users to search for documents (all documents will also be checked to see if they are allowed to be viewed)',
241
            ],
242
        ];
243
    }
244
245
    protected function bestSearchType(): string
246
    {
247
        // Accessing the session
248
        $session = $this->getRequest()->getSession();
249
        if($this->quickSearchType) {
250
            $session->set('QuickSearchType', $this->quickSearchType);
251
        } elseif($session) {
0 ignored issues
show
introduced by
$session is of type SilverStripe\Control\Session, thus it always evaluated to true.
Loading history...
252
            $this->quickSearchType = $session->get('QuickSearchType');
253
            if(isset($_GET['flush'])) {
254
                $this->quickSearchType = '';
255
                $session->set('QuickSearchType', '');
256
            }
257
        }
258
        if(!$this->quickSearchType) {
259
            $this->quickSearchType = $this->Config()->get('default_quick_search_type');
260
        }
261
        return (string) $this->quickSearchType;
262
    }
263
264
    protected function lastSearchResults(): ?ArrayList
265
    {
266
        // Accessing the session
267
        $session = $this->getRequest()->getSession();
268
        if($session) {
0 ignored issues
show
introduced by
$session is of type SilverStripe\Control\Session, thus it always evaluated to true.
Loading history...
269
            if(isset($_GET['flush'])) {
270
                $session->clear('QuickSearchLastResults');
271
            } else {
272
                $data = $session->get('QuickSearchLastResults');
273
                if($data) {
274
                    $array = unserialize($data);
275
                    $al = ArrayList::create();
276
                    foreach($array as $item) {
277
                        $al->push($item);
278
                    }
279
                    return $al;
280
                }
281
            }
282
        }
283
        return null;
284
    }
285
}
286