1<?php 2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project 3// 4// All Rights Reserved. See copyright.txt for details and a complete list of authors. 5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details. 6// $Id$ 7 8class Category_Manipulator 9{ 10 private $objectType; 11 private $objectId; 12 13 private $current = []; 14 private $managed = []; 15 private $unmanaged = []; 16 private $constraints = [ 17 'required' => [], 18 ]; 19 private $new = []; 20 21 private $prepared = false; 22 private $overrides = []; 23 private $overrideAll = false; 24 25 function __construct($objectType, $objectId) 26 { 27 $this->objectType = $objectType; 28 $this->objectId = $objectId; 29 } 30 31 function addRequiredSet(array $categories, $default, $filter = null, $type = null) 32 { 33 $categories = array_unique($categories); 34 $this->constraints['required'][] = [ 35 'set' => $categories, 36 'default' => $default, 37 'filter' => $filter, 38 'type' => $type 39 ]; 40 } 41 42 function overrideChecks() 43 { 44 $this->overrideAll = true; 45 } 46 47 function setCurrentCategories(array $categories) 48 { 49 $this->current = $categories; 50 } 51 52 function setManagedCategories(array $categories) 53 { 54 $this->managed = $categories; 55 } 56 57 function setUnmanagedCategories(array $categories) 58 { 59 $this->unmanaged = $categories; 60 } 61 62 function setNewCategories(array $categories) 63 { 64 $this->new = $categories; 65 } 66 67 function getAddedCategories() 68 { 69 $this->prepare(); 70 71 $attempt = array_diff($this->new, $this->current); 72 return $this->filter($attempt, 'add_object'); 73 } 74 75 function getRemovedCategories() 76 { 77 $this->prepare(); 78 79 $attempt = array_diff($this->current, $this->new); 80 return $this->filter($attempt, 'remove_object'); 81 } 82 83 84 /* 85 * Check wether the given permission is allowed for the given categories. 86 * Note: The group in question requires also the _global_ permission 'modify_object_categories' 87 * which could be given to a parent object like parent Tracker of a TrackerItem. 88 * @param array $categories - requested categories 89 * @param string $permission - required permission for that category. Ie. 'add_category' 90 * @return array $authorizedCategories - filterd list of given $categories that have proper permissions set. 91 */ 92 private function filter($categories, $permission) 93 { 94 $objectperms = Perms::get(['type' => $this->objectType, 'object' => $this->objectId]); 95 $canModifyObject = $objectperms->modify_object_categories; 96 97 $out = []; 98 foreach ($categories as $categ) { 99 $perms = Perms::get(['type' => 'category', 'object' => $categ]); 100 $hasCategoryPermission = $perms->$permission; 101 102 if ($this->overrideAll || ($canModifyObject && $hasCategoryPermission) || in_array($categ, $this->overrides)) { 103 $out[] = $categ; 104 } 105 } 106 107 return $out; 108 } 109 110 111 private function prepare() 112 { 113 if ($this->prepared) { 114 return; 115 } 116 117 $categories = $this->managed; 118 Perms::bulk(['type' => 'category'], 'object', $categories); 119 120 if (count($this->managed)) { 121 $base = array_diff($this->current, $this->managed); 122 $managed = array_intersect($this->new, $this->managed); 123 $this->new = array_merge($base, $managed); 124 } 125 126 if (count($this->unmanaged)) { 127 $base = array_intersect($this->current, $this->unmanaged); 128 $managed = array_diff($this->new, $this->unmanaged); 129 $this->new = array_merge($base, $managed); 130 } 131 132 $this->applyConstraints(); 133 134 $this->prepared = true; 135 } 136 137 private function applyConstraints() 138 { 139 foreach ($this->constraints['required'] as $constraint) { 140 $set = $constraint['set']; 141 $default = $constraint['default']; 142 $filter = $constraint['filter']; 143 $type = $constraint['type']; 144 145 $interim = array_intersect($this->new, $set); 146 147 if (! empty($type) && $type != $this->objectType) { 148 return; 149 } 150 151 if (! empty($filter)) { 152 $objectlib = TikiLib::lib('object'); 153 $info = $objectlib->get_info($this->objectType, $this->objectId); 154 if (! preg_match($filter, $info['title'])) { 155 return; 156 } 157 } 158 159 if (count($interim) == 0 && ! in_array($default, $this->new)) { 160 $this->new[] = $default; 161 $this->overrides[] = $default; 162 } 163 } 164 } 165} 166