3 namespace Drupal\permissions_by_term\Service;
5 use Drupal\Component\Utility\Tags;
6 use Drupal\Core\Database\Connection;
7 use Drupal\Core\Form\FormState;
8 use Drupal\Core\Session\AccountInterface;
9 use Drupal\user\Entity\User;
12 * Class AccessStorage.
14 * @package Drupal\permissions_by_term
19 * The database connection.
26 * The term name for which the access is set.
33 * The user ids which gain granted access.
37 protected $aUserIdsGrantedAccess;
40 * The roles with granted access.
44 protected $aSubmittedRolesGrantedAccess;
54 const NODE_ACCESS_REALM = 'permissions_by_term';
59 protected $accessCheck;
62 * AccessStorageService constructor.
64 * @param Connection $database
66 * @param AccessCheck $accessCheck
68 public function __construct(Connection $database, Term $term, AccessCheck $accessCheck) {
69 $this->database = $database;
71 $this->accessCheck = $accessCheck;
75 * Gets submitted roles with granted access from form.
78 * An array with chosen roles.
80 public function getSubmittedRolesGrantedAccess(FormState $form_state) {
81 $aRoles = $form_state->getValue('access')['role'];
83 foreach ($aRoles as $sRole) {
85 $aChosenRoles[] = $sRole;
92 * @param FormState $form_state
94 public function checkIfUsersExists(FormState $form_state) {
95 $sAllowedUsers = $form_state->getValue('access')['user'];
96 $aAllowedUsers = Tags::explode($sAllowedUsers);
97 foreach ($aAllowedUsers as $sUserId) {
98 $aUserId = \Drupal::entityQuery('user')
99 ->condition('uid', $sUserId)
101 if (empty($aUserId)) {
102 $form_state->setErrorByName('access][user',
103 t('The user with ID %user_id does not exist.',
104 ['%user_id' => $sUserId]));
110 * @param int $term_id
114 public function getUserTermPermissionsByTid($term_id) {
115 return $this->database->select('permissions_by_term_user', 'pu')
116 ->condition('tid', $term_id)
117 ->fields('pu', ['uid'])
128 public function getPermittedTids($uid, $rids) {
129 $permittedTids = $this->database->select('permissions_by_term_user', 'pu')
130 ->condition('uid', $uid)
131 ->fields('pu', ['tid'])
135 foreach ($rids as $rid) {
136 $permittedTidsByRid = $this->database->select('permissions_by_term_role', 'pr')
137 ->condition('rid', $rid)
138 ->fields('pr', ['tid'])
142 $permittedTids = array_merge($permittedTidsByRid, $permittedTids);
145 return array_unique($permittedTids);
153 public function getUserTermPermissionsByTids($tids) {
156 foreach ($tids as $tid) {
157 if (!empty($tmpUids = $this->getUserTermPermissionsByTid($tid))) {
158 foreach ($tmpUids as $tmpUid) {
168 * @param int $term_id
172 public function getRoleTermPermissionsByTid($term_id) {
173 return $this->database->select('permissions_by_term_role', 'pr')
174 ->condition('tid', $term_id)
175 ->fields('pr', ['rid'])
185 public function getRoleTermPermissionsByTids($tids) {
188 foreach ($tids as $tid) {
189 $tmpRids = $this->getRoleTermPermissionsByTid($tid);
190 if (!empty($tmpRids)) {
191 foreach ($tmpRids as $tmpRid) {
201 * @param string $sUsername
205 public function getUserIdByName($sUsername) {
206 return $this->database->select('users_field_data', 'ufd')
207 ->condition('name', $sUsername)
208 ->fields('ufd', ['uid'])
214 * @param array $aUserNames
218 public function getUserIdsByNames($aUserNames) {
220 foreach ($aUserNames as $userName) {
221 $iUserId = $this->getUserIdByName($userName)['uid'];
222 $aUserIds[] = $iUserId['uid'];
228 * @param int $term_id
232 public function getAllowedUserIds($term_id) {
233 $query = $this->database->select('permissions_by_term_user', 'p')
234 ->fields('p', ['uid'])
235 ->condition('p.tid', $term_id);
237 // fetchCol() returns all results, fetchAssoc() only "one" result.
238 return $query->execute()
243 * @param array $aUserIdsAccessRemove
244 * @param int $term_id
246 public function deleteTermPermissionsByUserIds($aUserIdsAccessRemove, $term_id) {
247 foreach ($aUserIdsAccessRemove as $iUserId) {
248 $this->database->delete('permissions_by_term_user')
249 ->condition('uid', $iUserId, '=')
250 ->condition('tid', $term_id, '=')
256 * @param array $aRoleIdsAccessRemove
257 * @param int $term_id
259 public function deleteTermPermissionsByRoleIds($aRoleIdsAccessRemove, $term_id) {
260 foreach ($aRoleIdsAccessRemove as $sRoleId) {
261 $this->database->delete('permissions_by_term_role')
262 ->condition('rid', $sRoleId, '=')
263 ->condition('tid', $term_id, '=')
271 public function deleteAllTermPermissionsByUserId($userId) {
272 $this->database->delete('permissions_by_term_user')
273 ->condition('uid', $userId, '=')
278 * Delete access storage when a term is removed.
280 * @param int $term_id
281 * The term ID being deleted.
283 public function deleteAllTermPermissionsByTid($term_id) {
284 $this->database->delete('permissions_by_term_user')
285 ->condition('tid', $term_id, '=')
288 $this->database->delete('permissions_by_term_role')
289 ->condition('tid', $term_id, '=')
294 * @param array $aUserIdsGrantedAccess
295 * @param int $term_id
296 * @param string $langcode
300 public function addTermPermissionsByUserIds($aUserIdsGrantedAccess, $term_id, $langcode = 'en') {
301 foreach ($aUserIdsGrantedAccess as $iUserIdGrantedAccess) {
302 $this->database->insert('permissions_by_term_user')
303 ->fields(['tid', 'uid', 'langcode'], [$term_id, $iUserIdGrantedAccess, $langcode])
309 * @param array $aRoleIdsGrantedAccess
310 * @param int $term_id
311 * @param string $langcode
315 public function addTermPermissionsByRoleIds($aRoleIdsGrantedAccess, $term_id, $langcode = 'en') {
316 foreach ($aRoleIdsGrantedAccess as $sRoleIdGrantedAccess) {
317 $this->database->insert('permissions_by_term_role')
318 ->fields(['tid', 'rid', 'langcode'], [$term_id, $sRoleIdGrantedAccess, $langcode])
324 * Gets the user ids which have been submitted by form.
326 * Users which will gain granted access to taxonomy terms.
329 * The user ids which have been submitted.
331 public function getSubmittedUserIds() {
332 /* There's a $this->oFormState->getValues() method, but
333 * it is loosing multiple form values. Don't know why.
334 * So there're some custom lines on the $_REQUEST array. */
335 $sRawUsers = $_REQUEST['access']['user'];
337 if (empty($sRawUsers)) {
341 $aRawUsers = Tags::explode($sRawUsers);
344 if (!empty($aRawUsers)) {
345 foreach ($aRawUsers as $sRawUser) {
346 if (preg_match("/.+\s\(([^\)]+)\)/", $sRawUser, $matches)) {
347 $aUserIds[] = $matches[1];
356 * Saves term permissions by users.
358 * Opposite to save term permission by roles.
360 * @param FormState $form_state
361 * @param int $term_id
364 * Data for database queries.
366 public function saveTermPermissions(FormState $form_state, $term_id) {
367 $aExistingUserPermissions = $this->getUserTermPermissionsByTid($term_id);
368 $aSubmittedUserIdsGrantedAccess = $this->getSubmittedUserIds();
370 $aExistingRoleIdsGrantedAccess = $this->getRoleTermPermissionsByTid($term_id);
371 $aSubmittedRolesGrantedAccess = $this->getSubmittedRolesGrantedAccess($form_state);
373 $aRet = $this->getPreparedDataForDatabaseQueries($aExistingUserPermissions,
374 $aSubmittedUserIdsGrantedAccess, $aExistingRoleIdsGrantedAccess,
375 $aSubmittedRolesGrantedAccess);
378 if (!empty($form_state->getValue('langcode', 'en'))) {
379 $langcode = $form_state->getValue('langcode', 'en')['0']['value'];
382 // Run the database queries.
383 $this->deleteTermPermissionsByUserIds($aRet['UserIdPermissionsToRemove'], $term_id);
384 $this->addTermPermissionsByUserIds($aRet['UserIdPermissionsToAdd'], $term_id, $langcode);
386 $this->deleteTermPermissionsByRoleIds($aRet['UserRolePermissionsToRemove'], $term_id);
387 $this->addTermPermissionsByRoleIds($aRet['aRoleIdPermissionsToAdd'], $term_id, $langcode);
393 * Get array items to remove.
395 * The array items which aren't in the new items array, but are in old items
396 * array, will be returned.
398 * @param array $aExistingItems
399 * The existing array items.
400 * @param array|bool $aNewItems
401 * Either false if there're no new items or an array with items.
404 * The array items to remove.
406 private function getArrayItemsToRemove($aExistingItems, $aNewItems) {
409 foreach ($aExistingItems as $existingItem) {
410 if (!in_array($existingItem, $aNewItems)) {
411 $aRet[] = $existingItem;
419 * Get the array items to add.
421 * The items in the new items array, which aren't in the existing items array,
424 * @param array $aNewItems
425 * The new array items.
426 * @param array $aExistingItems
427 * The existing array items.
430 * The items which needs to be added.
432 private function getArrayItemsToAdd($aNewItems, $aExistingItems) {
435 foreach ($aNewItems as $newItem) {
436 if (!in_array($newItem, $aExistingItems)) {
445 * Prepares the data which has to be applied to the database.
447 * @param array $aExistingUserPermissions
448 * The permissions for existing user.
449 * @param array $aSubmittedUserIdsGrantedAccess
450 * The user ids which get access.
451 * @param array $aExistingRoleIdsGrantedAccess
452 * The existing role ids.
453 * @param array $aSubmittedRolesGrantedAccess
454 * The user roles which get access.
457 * User ID and role data.
459 public function getPreparedDataForDatabaseQueries($aExistingUserPermissions,
460 $aSubmittedUserIdsGrantedAccess,
461 $aExistingRoleIdsGrantedAccess,
462 $aSubmittedRolesGrantedAccess) {
463 // Fill array with user ids to remove permission.
464 $aRet['UserIdPermissionsToRemove'] =
465 $this->getArrayItemsToRemove($aExistingUserPermissions,
466 $aSubmittedUserIdsGrantedAccess);
468 // Fill array with user ids to add permission.
469 $aRet['UserIdPermissionsToAdd'] =
470 $this->getArrayItemsToAdd($aSubmittedUserIdsGrantedAccess,
471 $aExistingUserPermissions);
473 // Fill array with user roles to remove permission.
474 $aRet['UserRolePermissionsToRemove'] =
475 $this->getArrayItemsToRemove($aExistingRoleIdsGrantedAccess,
476 $aSubmittedRolesGrantedAccess);
478 // Fill array with user roles to add permission.
479 $aRet['aRoleIdPermissionsToAdd'] =
480 $this->getArrayItemsToAdd($aSubmittedRolesGrantedAccess,
481 $aExistingRoleIdsGrantedAccess);
487 * The form value for allowed users as string to be shown to the user.
489 * @param User[] $aAllowedUsers
490 * An array with the allowed users.
492 * @return null|string
493 * Either null or the user name.
495 public function getUserFormValue($aAllowedUsers) {
499 if (!empty($aAllowedUsers)) {
501 foreach ($aAllowedUsers as $oUser) {
502 $iUid = intval($oUser->id());
504 $sUsername = $oUser->getDisplayName();
507 $sUsername = t('Anonymous User');
510 $sUserInfos .= "$sUsername ($iUid), ";
513 // Remove space and comma at the end of the string.
514 $sUserInfos = substr($sUserInfos, 0, -2);
525 public function getTidsByNid($nid)
527 $node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);
530 foreach ($node->getFields() as $field) {
531 if ($field->getFieldDefinition()->getType() == 'entity_reference' && $field->getFieldDefinition()->getSetting('target_type') == 'taxonomy_term') {
532 $aReferencedTaxonomyTerms = $field->getValue();
533 if (!empty($aReferencedTaxonomyTerms)) {
534 foreach ($aReferencedTaxonomyTerms as $aReferencedTerm) {
535 if (isset($aReferencedTerm['target_id'])) {
536 $tids[] = $aReferencedTerm['target_id'];
549 public function getAllUids()
551 $nodes = \Drupal::entityQuery('user')
554 return array_values($nodes);
562 public function getNodeType($nid)
564 $query = $this->database->select('node', 'n')
565 ->fields('n', ['type'])
566 ->condition('n.nid', $nid);
568 return $query->execute()
569 ->fetchAssoc()['type'];
577 public function getLangCode($nid)
579 $query = $this->database->select('node', 'n')
580 ->fields('n', ['langcode'])
581 ->condition('n.nid', $nid);
583 return $query->execute()
584 ->fetchAssoc()['langcode'];
588 * @param AccountInterface $user
592 public function getGids(AccountInterface $user)
596 if (!empty($permittedNids = $this->computePermittedTids($user))) {
597 $query = $this->database->select('node_access', 'na')
598 ->fields('na', ['gid'])
599 ->condition('na.nid', $permittedNids, 'IN')
600 ->condition('na.realm', self::NODE_ACCESS_REALM);
602 $gids = $query->execute()->fetchCol();
604 foreach ($gids as $gid) {
605 $grants[self::NODE_ACCESS_REALM][] = $gid;
612 private function computePermittedTids(AccountInterface $user)
614 $nidsWithNoTidRestriction = $this->getUnrestrictedNids();
615 $nidsByTids = $this->term->getNidsByTids($this->getPermittedTids($user->id(), $user->getRoles()));
617 if (\Drupal::config('permissions_by_term.settings.single_term_restriction')->get('value')) {
619 foreach ($nidsByTids as $nid) {
620 if($this->accessCheck->canUserAccessByNodeId($nid, $user->id(), $this->getLangCode($nid))) {
621 $permittedNids[] = $nid;
624 $nidsByTids = $permittedNids;
627 if (!empty($nidsByTids)) {
629 $this->getUnrestrictedNids(),
634 return $nidsWithNoTidRestriction;
637 private function getUnrestrictedNids() {
638 $tidsRestrictedUserQuery = $this->database->select('permissions_by_term_user', 'u')
639 ->fields('u', ['tid']);
641 $restrictedTids = $this->database->select('permissions_by_term_role', 'r')
642 ->fields('r', ['tid'])
643 ->union($tidsRestrictedUserQuery)
647 if (empty($restrictedTids)) {
648 return $this->getAllNids();
651 $restrictedNids = $this->database->select('taxonomy_index', 't')
652 ->fields('t', ['nid'])
653 ->condition('t.tid', $restrictedTids, 'IN')
658 if (empty($restrictedNids)) {
659 return $this->getAllNids();
662 $unrestrictedNids = $this->database->select('taxonomy_index', 't')
663 ->fields('t', ['nid'])
664 ->condition('t.nid', $restrictedNids, 'NOT IN')
669 return $unrestrictedNids;
675 public function getAllNids() {
676 return $this->database->select('node', 'n')
677 ->fields('n', ['nid'])
687 public function getAllNidsUserCanAccess($uid)
689 $query = $this->database->select('node_access', 'na')
690 ->fields('na', ['nid'])
691 ->condition('na.realm', 'permissions_by_term__uid_' . $uid);
693 return $query->execute()
702 public function getNidsByTid($tid)
704 $query = $this->database->select('taxonomy_index', 'ti')
705 ->fields('ti', ['nid'])
706 ->condition('ti.tid', $tid);
708 return $query->execute()->fetchCol();