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
8namespace Tiki\Command;
9
10use DateInterval;
11use DateTimeInterface;
12use Exception;
13use Symfony\Component\Console\Command\Command;
14use Symfony\Component\Console\Input\InputArgument;
15use Symfony\Component\Console\Input\InputInterface;
16use Symfony\Component\Console\Input\InputOption;
17use Symfony\Component\Console\Output\OutputInterface;
18use Faker\Factory as FakerFactory;
19use TikiLib;
20use Tiki\Faker as TikiFaker;
21
22/**
23 * Enabled the usage of Faker as a way to load random data to trackers
24 */
25class FakerCommentsCommand extends Command
26{
27	/**
28	 * Configures the current command.
29	 */
30	protected function configure()
31	{
32		$this
33			->setName('faker:comments')
34			->setDescription('Generate comments fake data')
35			->addArgument(
36				'object',
37				InputArgument::REQUIRED,
38				'Object Id'
39			)
40			->addArgument(
41				'type',
42				InputArgument::OPTIONAL,
43				'Object Type',
44				'wiki page'
45			)
46			->addOption(
47				'items',
48				'i',
49				InputOption::VALUE_OPTIONAL,
50				'Number of comments (items) to generate',
51				100
52			)
53			->addOption(
54				'replies',
55				'r',
56				InputOption::VALUE_OPTIONAL,
57				'Percentage of comments as replies',
58				40
59			)
60			->addOption(
61				'anonymous',
62				'a',
63				InputOption::VALUE_OPTIONAL,
64				'Percentage of anonymous posts if permitted',
65				20
66			)
67			->addOption(
68				'minstart',
69				's',
70				InputOption::VALUE_OPTIONAL,
71				'Earliest start date for first comment',
72				'-1 year'
73			)
74			->addOption(
75				'maxstart',
76				'e',
77				InputOption::VALUE_OPTIONAL,
78				'Latest start date for first comment',
79				'-11 months'
80			)
81			->addOption(
82				'mingap',
83				'',
84				InputOption::VALUE_OPTIONAL,
85				'Shortest gap between comments',
86				'10 minutes'
87			)
88			->addOption(
89				'maxgap',
90				'g',
91				InputOption::VALUE_OPTIONAL,
92				'Longest gap between comments',
93				'5 days'
94			);
95	}
96
97	/**
98	 * Executes the current command.
99	 *
100	 * @param InputInterface  $input
101	 * @param OutputInterface $output
102	 *
103	 * @return null|int
104	 * @throws Exception
105	 */
106	protected function execute(InputInterface $input, OutputInterface $output)
107	{
108		global $prefs;
109
110		$commentslib = TikiLib::lib('comments');
111		$tikilib = TikiLib::lib('tiki');
112
113		if (! class_exists('\Faker\Factory')) {
114			$output->writeln('<error>' . tra('Please install Faker package') . '</error>');
115			return null;
116		}
117
118		$objectId = $input->getArgument('object');
119		$objectType = $input->getArgument('type');
120
121		// check for object's existence
122		if (! TikiLib::lib('object')->get_object_id($objectType, $objectId)) {
123			$output->writeln('<error>' . tr('Object "%0" of type "%1" not found', $objectId, $objectType) . '</error>');
124			return null;
125		}
126
127		$numberItems = $input->getOption('items');
128		if (! is_numeric($numberItems)) {
129			$output->writeln('<error>' . tra('The value of items is not a number') . '</error>');
130			return null;
131		}
132
133		$numberItems = (int)$numberItems;
134
135		$replyPercentage = $input->getOption('replies');
136		$anonymousPercentage = $input->getOption('anonymous');
137
138		// dates
139		$minStart = $input->getOption('minstart');
140		$maxStart = $input->getOption('maxstart');
141		$minGap = $input->getOption('mingap');
142		$maxGap = $input->getOption('maxgap');
143
144		$faker = FakerFactory::create();
145		$tikiFaker = new TikiFaker($faker);
146		$faker->addProvider($tikiFaker);
147
148		$startDate = $faker->dateTimeBetween($minStart, $maxStart);
149		$lastDateTime = $startDate;
150		$lastDateTime->add(DateInterval::createFromDateString($minGap));
151
152		$fakerMap = [
153			'title' => '',
154			'data'  => 'text',
155		];
156
157		if ($prefs['comments_notitle'] !== 'y') {
158			$fakerMap['title'] = ['text', [30]];
159		}
160
161		$threadId = 0;
162		// need user names, jnot real
163		$showRealNames = $prefs['user_show_realnames'];
164		$prefs['user_show_realnames'] = 'n';
165
166		for ($i = 0; $i < $numberItems; $i++) {
167
168			if ($prefs['feature_comments_post_as_anonymous'] === 'y' && random_int(0, 100) < $anonymousPercentage) {
169				$fakerMap['userName'] = '';
170				$fakerMap['anonymous_name'] = 'name';
171				$fakerMap['anonymous_email'] = 'email';
172				$fakerMap['website'] = 'url';
173			} else {
174				$fakerMap['userName'] = ['tikiUserSelector', false,];
175				$fakerMap['anonymous_name'] = '';
176				$fakerMap['anonymous_email'] = '';
177				$fakerMap['website'] = '';
178			}
179
180			$commentData = [];
181
182			foreach ($fakerMap as $argument => $thisFaker) {
183
184				if (is_array($thisFaker)) {
185					$fakerAction = $thisFaker[0];
186					$fakerArguments = $thisFaker[1];
187					if (! is_array($fakerArguments)) {
188						$fakerArguments = [$fakerArguments];
189					}
190					$value = call_user_func_array([$faker, $fakerAction], $fakerArguments);
191				} elseif (! empty($thisFaker)) {
192					$fakerAction = $thisFaker;
193					$value = $faker->$fakerAction;
194				} else {
195					$value = '';
196				}
197
198				if (isset($value)) {
199					$commentData[$argument] = $value;
200				}
201			}
202
203			// special handling for commentDateTime
204
205			$commentDateTime = $faker->dateTimeInInterval($lastDateTime->format(DateTimeInterface::ATOM), $maxGap);
206
207			if (! empty($commentData)) {
208				$message_id = '';        // returned by reference
209				if ($threadId && random_int(0, 100) < $replyPercentage) {
210					$parentId = $threadId;        // add thread parent here sometimes
211				} else {
212					$parentId = 0;
213				}
214				$commentDateUnix = $commentDateTime->format('U');
215				if ($prefs['comments_notitle'] === 'y') {
216					$commentData['title'] = 'Untitled ' . $tikilib->get_long_datetime($commentDateUnix);
217				}
218
219				try {
220					$threadId = $commentslib->post_new_comment(
221						"$objectType:$objectId",
222						$parentId,
223						$commentData['userName'],
224						$commentData['title'],
225						$commentData['data'],
226						$message_id,
227						'',    // reply to for forums only?
228						'n',
229						'',
230						'',
231						[],
232						$commentData['anonymous_name'],
233						$commentDateUnix,
234						$commentData['anonymous_email'],
235						$commentData['website'],
236						[],                    // parent info for forums
237						0            // version of object for save and comment
238					);
239				} catch (Exception $e) {
240					$output->writeln('<error>' . $e->getMessage() . '</error>');
241				}
242
243				$lastDateTime = $commentDateTime;
244			}
245		}
246
247		$prefs['user_show_realnames'] = $showRealNames;
248
249		return 0;
250	}
251
252
253}
254