Issues (216)

Classes/Access/Rootline.php (2 issues)

Labels
Severity
1
<?php
2
namespace ApacheSolrForTypo3\Solr\Access;
3
4
/***************************************************************
5
 *  Copyright notice
6
 *
7
 *  (c) 2011-2015 Ingo Renner <[email protected]>
8
 *  All rights reserved
9
 *
10
 *  This script is part of the TYPO3 project. The TYPO3 project is
11
 *  free software; you can redistribute it and/or modify
12
 *  it under the terms of the GNU General Public License as published by
13
 *  the Free Software Foundation; either version 3 of the License, or
14
 *  (at your option) any later version.
15
 *
16
 *  The GNU General Public License can be found at
17
 *  http://www.gnu.org/copyleft/gpl.html.
18
 *
19
 *  This script is distributed in the hope that it will be useful,
20
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 *  GNU General Public License for more details.
23
 *
24
 *  This copyright notice MUST APPEAR in all copies of the script!
25
 ***************************************************************/
26
27
use TYPO3\CMS\Core\Utility\GeneralUtility;
28
use TYPO3\CMS\Core\Utility\RootlineUtility;
29
use TYPO3\CMS\Frontend\Page\PageRepository;
30
31
/**
32
 * "Access Rootline", represents all pages and specifically those setting
33
 * frontend user group access restrictions in a page's rootline.
34
 *
35
 * The access rootline only contains pages which set frontend user access
36
 * restrictions and extend them to sub-pages. The format is as follows:
37
 *
38
 * pageId1:group1,group2/pageId2:group3/c:group1,group4,groupN
39
 *
40
 * The single elements of the access rootline are separated by a slash
41
 * character. All but the last elements represent pages, the last element
42
 * defines the access restrictions applied to the page's content elements
43
 * and records shown on the page.
44
 * Each page element is composed by the page ID of the page setting frontend
45
 * user access restrictions, a colon, and a comma separated list of frontend
46
 * user group IDs restricting access to the page.
47
 * The content access element does not have a page ID, instead it replaces
48
 * the ID by a lower case C.
49
 *
50
 * The groups for page elements are compared using OR, so the user needs to be
51
 * a member of only one of the groups listed for a page. The elements are
52
 * checked combined using AND, so the user must be member of at least one
53
 * group in each page element. However, the groups in the content access
54
 * element are checked using AND. So the user must be member of all the groups
55
 * listed in the content access element to see the document.
56
 *
57
 * An access rootline for a generic record could instead be short like this:
58
 *
59
 * r:group1,group2,groupN
60
 *
61
 * In this case the lower case R tells us that we're dealing with a record
62
 * like tt_news or the like. For records the groups are checked using OR
63
 * instead of using AND as it would be the case with content elements.
64
 *
65
 * @author Ingo Renner <[email protected]>
66
 */
67
class Rootline
68
{
69
70
    /**
71
     * Delimiter for page and content access right elements in the rootline.
72
     *
73
     * @var string
74
     */
75
    const ELEMENT_DELIMITER = '/';
76
77
    /**
78
     * Storage for access rootline elements
79
     *
80
     * @var array
81
     */
82
    protected $rootlineElements = [];
83
84
    /**
85
     * Constructor, turns a string representation of an access rootline into an
86
     * object representation.
87
     *
88
     * @param string $accessRootline Access Rootline String representation.
89 71
     */
90
    public function __construct($accessRootline = null)
91 71
    {
92 71
        if (!is_null($accessRootline)) {
93 71
            $rawRootlineElements = explode(self::ELEMENT_DELIMITER, $accessRootline);
94
            foreach ($rawRootlineElements as $rawRootlineElement) {
95 71
                try {
96 71
                    $this->push(GeneralUtility::makeInstance(RootlineElement::class, /** @scrutinizer ignore-type */ $rawRootlineElement));
97
                } catch (RootlineElementFormatException $e) {
98
                    // just ignore the faulty element for now, might log this later
99
                }
100
            }
101 71
        }
102
    }
103
104
    /**
105
     * Adds an Access Rootline Element to the end of the rootline.
106
     *
107
     * @param RootlineElement $rootlineElement Element to add.
108 71
     */
109
    public function push(RootlineElement $rootlineElement)
110 71
    {
111
        $lastElementIndex = max(0, (count($this->rootlineElements) - 1));
112 71
113 1
        if (!empty($this->rootlineElements[$lastElementIndex])) {
114
            if ($this->rootlineElements[$lastElementIndex]->getType() == RootlineElement::ELEMENT_TYPE_CONTENT) {
115
                throw new RootlineElementFormatException(
116
                    'Can not add an element to an Access Rootline whose\' last element is a content type element.',
117
                    1294422132
118
                );
119
            }
120 1
121
            if ($this->rootlineElements[$lastElementIndex]->getType() == RootlineElement::ELEMENT_TYPE_RECORD) {
122
                throw new RootlineElementFormatException(
123
                    'Can not add an element to an Access Rootline whose\' last element is a record type element.',
124
                    1308343423
125
                );
126
            }
127
        }
128 71
129 71
        $this->rootlineElements[] = $rootlineElement;
130
    }
131
132
    /**
133
     * Gets the Access Rootline for a specific page Id.
134
     *
135
     * @param int $pageId The page Id to generate the Access Rootline for.
136
     * @param string $mountPointParameter The mount point parameter for generating the rootline.
137
     * @return \ApacheSolrForTypo3\Solr\Access\Rootline Access Rootline for the given page Id.
138 13
     */
139
    public static function getAccessRootlineByPageId(
140
        $pageId,
141
        $mountPointParameter = ''
142 13
    ) {
143
        $accessRootline = GeneralUtility::makeInstance(Rootline::class);
144 13
        $rootlineUtility = GeneralUtility::makeInstance(RootlineUtility::class, $pageId, $mountPointParameter);
0 ignored issues
show
$mountPointParameter of type string is incompatible with the type array|array<mixed,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

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

144
        $rootlineUtility = GeneralUtility::makeInstance(RootlineUtility::class, $pageId, /** @scrutinizer ignore-type */ $mountPointParameter);
Loading history...
$pageId of type integer is incompatible with the type array|array<mixed,mixed> expected by parameter $constructorArguments of TYPO3\CMS\Core\Utility\G...Utility::makeInstance(). ( Ignorable by Annotation )

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

144
        $rootlineUtility = GeneralUtility::makeInstance(RootlineUtility::class, /** @scrutinizer ignore-type */ $pageId, $mountPointParameter);
Loading history...
145 13
        try {
146 13
            $rootline = $rootlineUtility->get();
147 13
        } catch (\RuntimeException $e) {
148
            $rootline = [];
149 13
        }
150 13
        $rootline = array_reverse($rootline);
151 13
        // parent pages
152 13
        foreach ($rootline as $pageRecord) {
153
            if ($pageRecord['fe_group']
154
                && $pageRecord['extendToSubpages']
155
                && $pageRecord['uid'] != $pageId
156 13
            ) {
157
                $accessRootline->push(GeneralUtility::makeInstance(
158
                    RootlineElement::class,
159
                    /** @scrutinizer ignore-type */ $pageRecord['uid'] . RootlineElement::PAGE_ID_GROUP_DELIMITER . $pageRecord['fe_group']
160
                ));
161
            }
162 13
        }
163 13
164 2
            /** @var  $pageSelector PageRepository */
165 2
        $pageSelector = GeneralUtility::makeInstance(PageRepository::class);
166 2
167
        // current page
168
        $currentPageRecord = $pageSelector->getPage($pageId, true);
169
        if ($currentPageRecord['fe_group']) {
170 13
            $accessRootline->push(GeneralUtility::makeInstance(
171
                RootlineElement::class,
172
                /** @scrutinizer ignore-type */ $currentPageRecord['uid'] . RootlineElement::PAGE_ID_GROUP_DELIMITER . $currentPageRecord['fe_group']
173
            ));
174
        }
175
176
        return $accessRootline;
177
    }
178 68
179
    /**
180 68
     * Returns the string representation of the access rootline.
181
     *
182 68
     * @return string String representation of the access rootline.
183 57
     */
184
    public function __toString()
185
    {
186 68
        $stringElements = [];
187
188
        foreach ($this->rootlineElements as $rootlineElement) {
189
            $stringElements[] = (string)$rootlineElement;
190
        }
191
192
        return implode(self::ELEMENT_DELIMITER, $stringElements);
193
    }
194 71
195
    /**
196 71
     * Gets a the groups in the Access Rootline.
197
     *
198 71
     * @return array An array of sorted, unique user group IDs required to access a page.
199 60
     */
200 60
    public function getGroups()
201
    {
202
        $groups = [];
203 71
204
        foreach ($this->rootlineElements as $rootlineElement) {
205 71
            $rootlineElementGroups = $rootlineElement->getGroups();
206
            $groups = array_merge($groups, $rootlineElementGroups);
207
        }
208
209
        $groups = $this->cleanGroupArray($groups);
210
211
        return $groups;
212
    }
213
214
    /**
215 75
     * Cleans an array of frontend user group IDs. Removes duplicates and sorts
216
     * the array.
217 75
     *
218 75
     * @param array $groups An array of frontend user group IDs
219
     * @return array An array of cleaned frontend user group IDs, unique, sorted.
220 75
     */
221
    public static function cleanGroupArray(array $groups)
222
    {
223
        $groups = array_unique($groups); // removes duplicates
224
        sort($groups, SORT_NUMERIC); // sort
225
226
        return $groups;
227
    }
228
}
229