Passed
Push — master ( e0d136...68aff5 )
by Nicolaas
03:37
created

SearchAdmin::bestSearchType()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 4
nop 0
dl 0
loc 13
rs 10
c 0
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
    public function getEditForm($id = null, $fields = null)
58
    {
59
        $form = parent::getEditForm($id, $fields);
60
        $fields = $form->Fields();
61
62
        // if ($form instanceof HTTPResponse) {
63
        //     return $form;
64
        // }
65
        // $fields->removeByName('LastVisited');
66
        $fields->push(
67
            (new TextField('Keywords', 'Keyword(s)', $this->keywords ?? ''))
68
                ->setAttribute('placeholder', 'e.g. agreement')
69
        );
70
        $fields->push(
71
            (new HiddenField('IsSubmitHiddenField', 'IsSubmitHiddenField', 1))
72
        );
73
74
        $options = QuickSearchBaseClass::get_list_of_quick_searches();
75
        $fields->push(
76
            OptionsetField::create(
77
                'QuickSearchType',
78
                'Quick Search',
79
                $options
80
            )->setValue($this->bestSearchType())
81
        );
82
83
        $fields->push(
84
            (new CheckboxField('SearchWholePhrase', 'Search exact phrase', $this->searchWholePhrase))
85
                ->setDescription('If ticked, any item will be included that includes the whole phrase (e.g. New Zealand, rather than New OR Zealand)')
86
        );
87
        $fields->push(
88
            ToggleCompositeField::create(
89
                'ReplaceToggle',
90
                _t(__CLASS__ . '.ReplaceToggle', 'Replace with ... (optional - make a backup first!)'),
91
                [
92
                    (new CheckboxField('ApplyReplace', 'Run replace (please make sure to make a backup first!)', $this->applyReplace))
93
                      ->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.'),
94
                    (new TextField('ReplaceWith', 'Replace (optional - careful!)', $this->replace ?? ''))
95
                        ->setAttribute('placeholder', 'e.g. contract - make sure to also tick checkbox below'),
96
                ]
97
            )->setHeadingLevel(4)
98
        );
99
100
101
        if (!$this->getRequest()->requestVar('Keywords')) {
102
            $resultsTitle = 'Recently Edited';
103
            $this->listHTML = $this->renderWith(self::class . '_Results');
104
        } else {
105
            $resultsTitle = 'Search Results';
106
        }
107
108
        $form->setFormMethod('get', false);
109
110
        $fields->push(
111
            (new HTMLReadonlyField('List', $resultsTitle, DBField::create_field('HTMLText', $this->listHTML)))
112
        );
113
        $form->Actions()->push(
114
            FormAction::create('search', 'Find')
115
                ->addExtraClass('btn-primary')
116
                ->setUseButtonTag(true)
117
        );
118
        $form->addExtraClass('root-form cms-edit-form center fill-height');
119
        // $form->disableSecurityToken();
120
        // $form->setFormMethod('get');
121
122
        return $form;
123
    }
124
125
    public function search(array $data, Form $form): HTTPResponse
126
    {
127
        if (empty($data['Keywords'])) {
128
            $form->sessionMessage('Please enter one or more keywords', 'bad');
129
130
            return $this->redirectBack();
131
        }
132
133
        $request = $this->getRequest();
134
135
        $this->rawData = $data;
136
        $this->listHTML = $this->renderWith(self::class . '_Results');
137
        // Existing or new record?
138
139
        return $this->getResponseNegotiator()->respond($request);
140
    }
141
142
    /**
143
     * Only show first element, as the profile form is limited to editing
144
     * the current member it doesn't make much sense to show the member name
145
     * in the breadcrumbs.
146
     *
147
     * @param bool $unlinked
148
     *
149
     * @return ArrayList
150
     */
151
    public function Breadcrumbs($unlinked = false)
152
    {
153
        $items = parent::Breadcrumbs($unlinked);
154
155
        return new ArrayList([$items[0]]);
156
    }
157
158
    public function IsQuickSearch(): bool
159
    {
160
        return $this->quickSearchType !== 'all';
161
    }
162
163
    public function SearchResults(): ?ArrayList
164
    {
165
        Environment::increaseTimeLimitTo(300);
166
        Environment::setMemoryLimitMax(-1);
167
        Environment::increaseMemoryLimitTo(-1);
168
        $this->keywords = $this->workOutString('Keywords', $this->rawData);
169
        $this->quickSearchType = $this->workOutString('QuickSearchType', $this->rawData, $this->bestSearchType());
170
        $this->searchWholePhrase = $this->workOutBoolean('SearchWholePhrase', $this->rawData, false);
171
        $this->applyReplace = isset($this->rawData['ReplaceWith']) && $this->workOutBoolean('ApplyReplace', $this->rawData, false);
172
        $this->replace = $this->workOutString('ReplaceWith', $this->rawData);
173
        if ($this->applyReplace) {
174
            Injector::inst()->get(SearchApi::class)
175
                ->setQuickSearchType($this->quickSearchType)
176
                ->setSearchWholePhrase(true)
177
                ->setWordsAsString($this->keywords)
178
                ->buildCache() // make sure we have the lastest cache!
179
                ->doReplacement($this->keywords, $this->replace)
180
            ;
181
            $this->applyReplace = false;
182
        }
183
184
        $results = Injector::inst()->get(SearchApi::class)
185
            ->setQuickSearchType($this->quickSearchType)
186
            ->setSearchWholePhrase($this->searchWholePhrase)
187
            ->setWordsAsString($this->keywords)
188
            ->getLinks()
189
        ;
190
        if($results->count() === 1) {
191
            $result = $results->first();
192
            $this->redirect($result->CMSEditLink);
193
            return null;
194
        }
195
        return $results;
196
    }
197
198
    protected function workOutBoolean(string $fieldName, ?array $data = null, ?bool $default = false): bool
199
    {
200
        return (bool) (isset($data['IsSubmitHiddenField']) ? !empty($data[$fieldName]) : $default);
201
    }
202
203
    protected function workOutString(string $fieldName, ?array $data = null, ?string $default = ''): string
204
    {
205
        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

205
        return trim(/** @scrutinizer ignore-type */ $data[$fieldName] ?? $default);
Loading history...
206
    }
207
208
    public function providePermissions()
209
    {
210
        return [
211
            'CMS_ACCESS_SITE_WIDE_SEARCH' => [
212
                'name' => 'Access to Search Website in the CMS',
213
                'category' => _t('SilverStripe\\Security\\Permission.CMS_ACCESS_CATEGORY', 'CMS Access'),
214
                'help' => 'Allow users to search for documents (all documents will also be checked to see if they are allowed to be viewed)',
215
            ],
216
        ];
217
    }
218
219
    protected function bestSearchType(): string
220
    {
221
        // Accessing the session
222
        $session = $this->getRequest()->getSession();
223
        if($this->quickSearchType) {
224
            $session->set('QuickSearchType', $this->quickSearchType);
225
        } else {
226
            $this->quickSearchType = $session->get('QuickSearchType');
227
        }
228
        if(!$this->quickSearchType) {
229
            $this->quickSearchType = $this->Config()->get('default_quick_search_type');
230
        }
231
        return (string) $this->quickSearchType;
232
    }
233
}
234