36 protected $licenseDao;
49 'text'=>array(
'text',
'Text'),
50 'acknowledgement'=>array(
'acknowledgement',
'Acknowledgement',
'acknowledgements'),
51 'comments'=>array(
'comments',
'Comments'),
52 'is_active'=>array(
'is_active',
'Is Active',
'active'),
53 'created_by'=>array(
'created_by',
'Created By',
'user_name'),
54 'group'=>array(
'group',
'Group',
'group_name'),
55 'licenses_to_add'=>array(
'licenses_to_add',
'Licenses To Add',
'add_licenses'),
56 'licenses_to_remove'=>array(
'licenses_to_remove',
'Licenses To Remove',
'remove_licenses')
68 $this->licenseDao = $licenseDao ?: $GLOBALS[
'container']->get(
'dao.license');
98 if ($fileExtension ===
'json') {
112 $content = file_get_contents($filename);
113 if ($content ===
false) {
114 return _(
"Could not read JSON file");
117 $data = json_decode($content,
true);
118 if (json_last_error() !== JSON_ERROR_NONE) {
119 return _(
"Invalid JSON format: ") . json_last_error_msg();
122 if (!is_array($data)) {
123 return _(
"JSON file must contain an array of phrases");
136 $handle = fopen($filename,
'r');
137 if ($handle ===
false) {
138 return _(
"Could not open CSV file");
141 $this->headrow = fgetcsv($handle, 0, $this->delimiter, $this->enclosure);
142 if ($this->headrow ===
false) {
144 return _(
"Could not read CSV header");
148 $bom = chr(0xEF) . chr(0xBB) . chr(0xBF);
149 if (isset($this->headrow[0]) && strpos($this->headrow[0], $bom) === 0) {
150 $this->headrow[0] = substr($this->headrow[0], 3);
155 while (($row = fgetcsv($handle, 0, $this->delimiter, $this->enclosure)) !==
false) {
157 if (count($row) !== count($this->headrow)) {
159 return sprintf(_(
"CSV line %d has %d columns, expected %d"),
160 $lineNumber, count($row), count($this->headrow));
163 $data[] = array_combine($this->headrow, $row);
180 foreach ($data as $index => $phraseData) {
183 if ($result[
'success']) {
186 $errors[] = sprintf(_(
"Row %d: %s"), $index + 1, $result[
'message']);
189 $errors[] = sprintf(_(
"Row %d: %s"), $index + 1, $e->getMessage());
193 $message = sprintf(_(
"Read file: %d phrases"), $imported);
194 if (!empty($errors)) {
195 $message .=
"\n" . _(
"Errors:") .
"\n" . implode(
"\n", $errors);
212 if (empty($mappedData[
'text'])) {
213 return array(
'success' =>
false,
'message' => _(
"Text is required"));
221 $textMd5 = md5($mappedData[
'text']);
222 $existingSql =
"SELECT cp_pk FROM custom_phrase WHERE text_md5 = $1";
223 $existing = $this->
dbManager->getSingleRow($existingSql, array($textMd5), __METHOD__ .
'.duplicateCheck');
226 return array(
'success' =>
false,
'message' => _(
"Duplicate text already exists"));
230 $insertSql =
"INSERT INTO custom_phrase (text, text_md5, acknowledgement, comments, user_fk, group_fk, is_active)
231 VALUES ($1, $2, $3, $4, $5, $6, $7)";
236 $mappedData[
'acknowledgement'] ??
'',
237 $mappedData[
'comments'] ??
'',
240 $this->
parseBoolean($mappedData[
'is_active'] ??
false) ?
'true' :
'false'
244 $cpPk = $this->
dbManager->insertPreparedAndReturn(__METHOD__ .
'.insertPhrase', $insertSql, $params,
'cp_pk');
245 $message = _(
"Phrase imported successfully");
247 $totalAssociated = 0;
248 $allFailed = array();
249 $allCreated = array();
252 if (!empty($mappedData[
'licenses_to_add'])) {
253 $licenseResult = $this->associateLicenses($cpPk, $mappedData[
'licenses_to_add'],
false);
254 $totalAssociated += $licenseResult[
'associated'];
255 $allFailed = array_merge($allFailed, $licenseResult[
'failed']);
256 $allCreated = array_merge($allCreated, $licenseResult[
'created']);
260 if (!empty($mappedData[
'licenses_to_remove'])) {
261 $licenseResult = $this->associateLicenses($cpPk, $mappedData[
'licenses_to_remove'],
true);
262 $totalAssociated += $licenseResult[
'associated'];
263 $allFailed = array_merge($allFailed, $licenseResult[
'failed']);
264 $allCreated = array_merge($allCreated, $licenseResult[
'created']);
267 if (!empty($allCreated)) {
268 $message .=
". " . sprintf(_(
"Created new licenses: %s"), implode(
', ', $allCreated));
270 if (!empty($allFailed)) {
271 $message .=
". " . sprintf(_(
"Warning: Could not create/find licenses: %s"), implode(
', ', $allFailed));
273 if ($totalAssociated > 0) {
274 $message .=
". " . sprintf(_(
"Associated %d licenses"), $totalAssociated);
277 return array(
'success' =>
true,
'message' => $message);
279 return array(
'success' =>
false,
'message' => _(
"Failed to import phrase: ") . $e->getMessage());
292 foreach ($this->alias as $standardName => $aliases) {
293 foreach ($aliases as
$alias) {
294 if (isset($data[
$alias])) {
295 $mapped[$standardName] = $data[
$alias];
322 foreach (array(
'acknowledgement',
'comments') as $field) {
323 if (isset($mapped[$field])) {
324 if (is_array($mapped[$field])) {
325 $mapped[$field] = implode(
'; ', array_filter($mapped[$field]));
326 } elseif (is_string($mapped[$field]) && strpos($mapped[$field],
'|') !==
false) {
328 $parts = array_map(
'trim', explode(
'|', $mapped[$field]));
329 $mapped[$field] = implode(
'; ', array_filter($parts));
335 if (isset($mapped[
'text']) && is_string($mapped[
'text'])) {
336 $mapped[
'text'] = str_replace(
'\\n',
"\n", $mapped[
'text']);
349 if (is_bool($value)) {
353 $value = strtolower(
trim($value));
354 return in_array($value, array(
'true',
'1',
'yes',
'on',
'active'));
357 private function associateLicenses($cpPk, $licenseNames, $removing =
false, $allowCreate =
false)
359 if (is_array($licenseNames)) {
360 $licenseArray = $licenseNames;
363 $separators = array(
', ',
',',
';',
'|');
364 $licenseArray = array($licenseNames);
366 foreach ($separators as $separator) {
367 if (strpos($licenseNames, $separator) !==
false) {
368 $licenseArray = array_map(
'trim', explode($separator, $licenseNames));
374 $associatedCount = 0;
375 $failedLicenses = array();
376 $createdLicenses = array();
378 foreach ($licenseArray as $licenseName) {
379 if (empty($licenseName)) {
383 $normalizedLicenseName =
trim($licenseName);
385 $license = $this->licenseDao->getLicenseByShortName($normalizedLicenseName);
389 $failedLicenses[] = $licenseName .
" (unknown)";
394 $newLicenseId = $this->licenseDao->insertLicense(
395 $normalizedLicenseName,
399 $license = $this->licenseDao->getLicenseById($newLicenseId);
400 $createdLicenses[] = $normalizedLicenseName;
401 }
catch (Exception $e) {
402 $failedLicenses[] = $licenseName .
" (creation failed)";
408 $licenseId = $license->getId();
411 $checkSql =
"SELECT 1 FROM custom_phrase_license_map WHERE cp_fk = $1 AND rf_fk = $2 LIMIT 1";
412 $existing = $this->
dbManager->getSingleRow($checkSql, array($cpPk, $licenseId),
413 __METHOD__ .
'.check.' . $cpPk .
'.' . $licenseId);
419 'rf_fk' => $licenseId,
420 'removing' => $removing ?
'true' :
'false'
424 $this->
dbManager->insertTableRow(
'custom_phrase_license_map', $insertData);
426 }
catch (Exception $e) {
427 $failedLicenses[] = $licenseName .
" (insert failed)";
435 return array(
'associated' => $associatedCount,
'failed' => $failedLicenses,
'created' => $createdLicenses);
446 if (empty(
trim($shortname))) {
451 if (strlen($shortname) > 256) {
456 if (preg_match(
'/[\x00-\x1F\x7F]/', $shortname)) {
Import custom text phrases from CSV/JSON.
importSinglePhrase($phraseData)
Import a single phrase.
importJsonData($data, string &$msg)
Import JSON data directly.
parseBoolean($value)
Parse boolean value from string.
normalizeBulkExportValues($mapped)
Normalize values from bulk text export format.
setEnclosure($enclosure='"')
Update the enclosure.
setDelimiter($delimiter=',')
Update the delimiter.
isValidLicenseShortname($shortname)
Validate a license shortname before auto-creating it.
handleFile($filename, $fileExtension)
Read the CSV/JSON file and import it.
mapHeaders($data)
Map CSV headers to standard field names.
__construct(DbManager $dbManager, UserDao $userDao, LicenseDao $licenseDao=null)
handleCsvFile($filename)
Handle CSV file import.
handleJsonFile($filename)
Handle JSON file import.
importPhrases($data)
Import phrases from data array.
Contains the constants and helpers for authentication of user.
static getUserId()
Get the current user's id.
static getGroupId()
Get the current user's group id.
char * trim(char *ptext)
Trimming whitespace.
fo_dbManager * dbManager
fo_dbManager object
Utility functions for specific applications.