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 Services_Category_Controller
9{
10	function setUp()
11	{
12		global $prefs;
13
14		if ($prefs['feature_categories'] != 'y') {
15			throw new Services_Exception_Disabled('feature_categories');
16		}
17	}
18
19	function action_list_categories($input)
20	{
21		global $prefs;
22
23		$parentId = $input->parentId->int();
24		$descends = $input->descends->int();
25
26		if (! $parentId) {
27			throw new Services_Exception_MissingValue('parentId');
28		}
29
30		$categlib = TikiLib::lib('categ');
31		return $categlib->getCategories(['identifier' => $parentId, 'type' => $descends ? 'descendants' : 'children']);
32	}
33
34	function action_categorize($input)
35	{
36		$categId = $input->categId->int();
37		$objects = (array) $input->objects->none();
38
39		$perms = Perms::get('category', $categId);
40
41		if (! $perms->add_objects) {
42			throw new Services_Exception(tr('Permission denied'), 403);
43		}
44
45		$filteredObjects = $originalObjects = $this->convertObjects($objects);
46		$util =new Services_Utilities();
47		if (count($originalObjects) && $util->isActionPost()) {
48			//first determine if objects are already in the category
49			$categlib = TikiLib::lib('categ');
50			$inCategory = [];
51			foreach ($originalObjects as $key => $object) {
52				$objCategories = $categlib->get_object_categories($object['type'], $object['id']);
53				if (in_array($categId, $objCategories)) {
54					$inCategory[] = $object;
55					unset($filteredObjects[$key]);
56				}
57			}
58			//provide appropriate feedback for objects already in category
59			if ($inCount = count($inCategory)) {
60				$msg = $inCount === 1 ? tr('No change made for one object already in the category')
61					: tr('No change made for %0 objects already in the category', $inCount);
62				Feedback::note($msg);
63			}
64			//now add objects to the category
65			if (count($filteredObjects)) {
66				$return = $this->processObjects('doCategorize', $categId, $filteredObjects);
67				$count = isset($return['objects']) ? count($return['objects']) : 0;
68				if ($count) {
69					$msg = $count === 1 ? tr('One object added to category')
70						: tr('%0 objects added to category', $count);
71					Feedback::success($msg);
72				} else {
73					Feedback::error(tr('No objects added to category'));
74				}
75				return $return;
76			} else {
77				//this code is reached when all objects selected were already in the category
78				return [
79					'categId'	=> $categId,
80					'objects'	=> $objects,
81					'count'		=> 'unchanged'
82				];
83			}
84		} else {
85			return [
86				'categId' => $categId,
87				'objects' => $objects,
88			];
89		}
90	}
91
92	function action_uncategorize($input)
93	{
94		$categId = $input->categId->digits();
95		$objects = (array) $input->objects->none();
96
97		$perms = Perms::get('category', $categId);
98
99		if (! $perms->remove_objects) {
100			throw new Services_Exception(tr('Permission denied'), 403);
101		}
102
103		$filteredObjects = $originalObjects = $this->convertObjects($objects);
104		$util =new Services_Utilities();
105		if (count($originalObjects) && $util->isActionPost()) {
106			//first determine if objects are already not in the category
107			$categlib = TikiLib::lib('categ');
108			$notInCategory = [];
109			foreach ($originalObjects as $key => $object) {
110				$objCategories = $categlib->get_object_categories($object['type'], $object['id']);
111				if (! in_array($categId, $objCategories)) {
112					$notInCategory[] = $object;
113					unset($filteredObjects[$key]);
114				}
115			}
116			//provide appropriate feedback for objects already not in category
117			if ($notCount = count($notInCategory)) {
118				$msg = $notCount === 1 ? tr('No change made for one object not in the category')
119					: tr('No change made for %0 objects not in the category', $notCount);
120				Feedback::note($msg);
121			}
122			//now uncategorize objects that are in the category
123			if (count($filteredObjects)) {
124				$return = $this->processObjects('doUncategorize', $categId, $filteredObjects);
125				$count = isset($return['objects']) ? count($return['objects']) : 0;
126				if ($count) {
127					$msg = $count === 1 ? tr('One object removed from category')
128						: tr('%0 objects removed from category', $count);
129					Feedback::success($msg);
130				} else {
131					Feedback::error(tr('No objects removed from category'));
132				}
133				return $return;
134			} else {
135				//this code is reached when all objects selected were already not in the category
136				return [
137					'categId'	=> $categId,
138					'objects'	=> $objects,
139					'count'		=> 'unchanged'
140				];
141			}
142		} else {
143			return [
144				'categId' => $categId,
145				'objects' => $objects,
146			];
147		}
148	}
149
150	function action_select($input)
151	{
152		$categlib = TikiLib::lib('categ');
153		$objectlib = TikiLib::lib('object');
154		$smarty = TikiLib::lib('smarty');
155
156		$type = $input->type->text();
157		$object = $input->object->text();
158
159		$perms = Perms::get($type, $object);
160		if (! $perms->modify_object_categories) {
161			throw new Services_Exception_Denied('Not allowed to modify categories');
162		}
163
164		$input->replaceFilter('subset', 'int');
165		$subset = $input->asArray('subset', ',');
166
167		if ($_SERVER['REQUEST_METHOD'] == 'POST') {
168			$smarty->loadPlugin('smarty_modifier_sefurl');
169			$name = $objectlib->get_title($type, $object);
170			$url = smarty_modifier_sefurl($object, $type);
171			$targetCategories = (array) $input->categories->int();
172			$count = $categlib->update_object_categories($targetCategories, $object, $type, '', $name, $url, $subset, false);
173		}
174
175		$categories = $categlib->get_object_categories($type, $object);
176		return [
177			'subset' => implode(',', $subset),
178			'categories' => array_combine(
179				$subset,
180				array_map(
181					function ($categId) use ($categories) {
182						return [
183							'name' => TikiLib::lib('object')->get_title('category', $categId),
184							'selected' => in_array($categId, $categories),
185						];
186					},
187					$subset
188				)
189			),
190		];
191	}
192
193	private function processObjects($function, $categId, $objects)
194	{
195		$tx = TikiDb::get()->begin();
196
197		foreach ($objects as & $object) {
198			$type = $object['type'];
199			$id = $object['id'];
200
201			$object['catObjectId'] = $this->$function($categId, $type, $id);
202		}
203
204		$tx->commit();
205
206		$categlib = TikiLib::lib('categ');
207		$category = $categlib->get_category((int) $categId);
208
209		return [
210			'categId' => $categId,
211			'count' => $category['objects'],
212			'objects' => $objects,
213		];
214	}
215
216	private function doCategorize($categId, $type, $id)
217	{
218		$categlib = TikiLib::lib('categ');
219		return $categlib->categorize_any($type, $id, $categId);
220	}
221
222	private function doUncategorize($categId, $type, $id)
223	{
224		$categlib = TikiLib::lib('categ');
225		if ($oId = $categlib->is_categorized($type, $id)) {
226			$result = $categlib->uncategorize($oId, $categId);
227			return $oId;
228		}
229		return 0;
230	}
231
232	private function convertObjects($objects)
233	{
234		$out = [];
235		foreach ($objects as $object) {
236			$object = explode(':', $object, 2);
237
238			if (count($object) == 2) {
239				list($type, $id) = $object;
240				$objectPerms = Perms::get($type, $id);
241
242				if ($objectPerms->modify_object_categories) {
243					$out[] = ['type' => $type, 'id' => $id];
244				}
245			}
246		}
247
248		return $out;
249	}
250}
251