FOSSology  4.7.1
Open Source License Compliance by Open Source Software
BulkTextExport.php
Go to the documentation of this file.
1 <?php
2 /*
3  SPDX-FileCopyrightText: © 2026 Kaushlendra Pratap <kaushlendra-pratap.singh@siemens.com>
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 
9 
11 
22 {
25  protected $dbManager;
28  protected $delimiter = ',';
31  protected $enclosure = '"';
32 
37  public function __construct(DbManager $dbManager)
38  {
39  $this->dbManager = $dbManager;
40  }
41 
46  public function setDelimiter($delimiter=',')
47  {
48  if (!is_string($delimiter) || strlen($delimiter) !== 1) {
49  throw new \InvalidArgumentException("CSV delimiter must be a non-empty single-byte character.");
50  }
51  if ($delimiter === $this->enclosure) {
52  throw new \InvalidArgumentException("CSV delimiter and enclosure must be different characters.");
53  }
54  $this->delimiter = $delimiter;
55  }
56 
61  public function setEnclosure($enclosure='"')
62  {
63  if (!is_string($enclosure) || strlen($enclosure) !== 1) {
64  throw new \InvalidArgumentException("CSV enclosure must be a non-empty single-byte character.");
65  }
66  if ($enclosure === $this->delimiter) {
67  throw new \InvalidArgumentException("CSV delimiter and enclosure must be different characters.");
68  }
69  $this->enclosure = $enclosure;
70  }
71 
79  public function exportBulkText($user_pk=0, $group_pk=0, $generateJson=false, $includeLicenseText=false)
80  {
81  $whereClause = "";
82  $params = array();
83 
84  if ($user_pk > 0) {
85  $whereClause = "WHERE lrb.user_fk = $1";
86  $params[] = $user_pk;
87  } elseif ($group_pk > 0) {
88  $whereClause = "WHERE lrb.group_fk = $1";
89  $params[] = $group_pk;
90  }
91 
92  $licenseTextColumn = $includeLicenseText ? ",\n lr.rf_text AS license_text" : "";
93 
94  // Subquery picks the latest lrb_pk per unique rf_text so duplicates keep only the newest entry.
95  $sql = "SELECT
96  lrb.rf_text,
97  lr.rf_shortname,
98  lsb.removing,
99  lsb.comment,
100  lsb.reportinfo,
101  lsb.acknowledgement,
102  lr.rf_active$licenseTextColumn
103  FROM (
104  SELECT rf_text, MAX(lrb_pk) AS lrb_pk
105  FROM license_ref_bulk
106  $whereClause
107  GROUP BY rf_text
108  ) latest
109  JOIN license_ref_bulk lrb ON lrb.lrb_pk = latest.lrb_pk
110  LEFT JOIN license_set_bulk lsb ON lsb.lrb_fk = lrb.lrb_pk
111  LEFT JOIN license_ref lr ON lr.rf_pk = lsb.rf_fk
112  ORDER BY lrb.rf_text, lr.rf_shortname";
113 
114  $result = $this->dbManager->getRows($sql, $params);
115 
116  if ($generateJson) {
117  return $this->createJson($result, $includeLicenseText);
118  } else {
119  return $this->createCsvContent($result, $includeLicenseText);
120  }
121  }
122 
129  private function groupResultsByText($result, $includeLicenseText=false)
130  {
131  $grouped = array();
132  foreach ($result as $row) {
133  $text = $row['rf_text'] ?: '';
134  if (!isset($grouped[$text])) {
135  $grouped[$text] = array(
136  'licenses' => array(),
137  'is_active_values' => array()
138  );
139  }
140 
141  if (!empty($row['rf_shortname'])) {
142  $removing = ($row['removing'] === 't' || $row['removing'] === true);
143  $license = array(
144  'shortname' => $row['rf_shortname'],
145  'removing' => $removing,
146  'comment' => $row['comment'] ?: '',
147  'reportinfo' => $row['reportinfo'] ?: '',
148  'acknowledgement' => $row['acknowledgement'] ?: ''
149  );
150  if ($includeLicenseText && !empty($row['license_text'])) {
151  $license['license_text'] = $row['license_text'];
152  }
153  $grouped[$text]['licenses'][] = $license;
154  }
155 
156  if ($row['rf_active'] !== null) {
157  $isActive = ($row['rf_active'] === 't' || $row['rf_active'] === true);
158  $grouped[$text]['is_active_values'][] = $isActive;
159  }
160  }
161 
162  foreach ($grouped as $text => $values) {
163  $grouped[$text]['is_active'] = empty($values['is_active_values'])
164  ? null
165  : !in_array(false, $values['is_active_values'], true);
166  unset($grouped[$text]['is_active_values']);
167  }
168 
169  return $grouped;
170  }
171 
178  private function createCsvContent($result, $includeLicenseText=false)
179  {
180  $headers = array(
181  'Text', 'Is Active', 'License Shortname', 'Removing',
182  'Comment', 'License Text', 'Acknowledgement'
183  );
184  if ($includeLicenseText) {
185  $headers[] = 'license_ref_text';
186  }
187 
188  $out = fopen('php://output', 'w');
189  ob_start();
190  fputs($out, chr(0xEF) . chr(0xBB) . chr(0xBF));
191  fputcsv($out, $headers, $this->delimiter, $this->enclosure);
192 
193  foreach ($this->groupResultsByText($result, $includeLicenseText) as $text => $entry) {
194  $isActive = $entry['is_active'] === null ? '' : ($entry['is_active'] ? 'true' : 'false');
195 
196  if (empty($entry['licenses'])) {
197  $row = array(
198  $this->normalizeNewlinesForCsv($text),
199  $isActive, '', '', '', '', ''
200  );
201  if ($includeLicenseText) {
202  $row[] = '';
203  }
204  fputcsv($out, $row, $this->delimiter, $this->enclosure);
205  } else {
206  foreach ($entry['licenses'] as $lic) {
207  $row = array(
208  $this->normalizeNewlinesForCsv($text),
209  $isActive,
210  $lic['shortname'],
211  $lic['removing'] ? 'true' : 'false',
212  $this->normalizeNewlinesForCsv($lic['comment']),
213  $this->normalizeNewlinesForCsv($lic['reportinfo']),
214  $this->normalizeNewlinesForCsv($lic['acknowledgement'])
215  );
216  if ($includeLicenseText) {
217  $row[] = $this->normalizeNewlinesForCsv($lic['license_text'] ?? '');
218  }
219  fputcsv($out, $row, $this->delimiter, $this->enclosure);
220  }
221  }
222  }
223 
224  $content = ob_get_contents();
225  ob_end_clean();
226  return $content;
227  }
228 
234  private function normalizeNewlinesForCsv($value)
235  {
236  return CustomTextEscaping::escapeNewlines($value);
237  }
238 
245  private function createJson($result, $includeLicenseText=false)
246  {
247  $data = array();
248 
249  foreach ($this->groupResultsByText($result, $includeLicenseText) as $text => $entry) {
250  $licenses = array_map(function($lic) use ($includeLicenseText) {
251  $out = array(
252  'shortname' => $lic['shortname'],
253  'removing' => $lic['removing'],
254  'comment' => $lic['comment'],
255  'reportinfo' => $lic['reportinfo'],
256  'acknowledgement' => $lic['acknowledgement']
257  );
258  if ($includeLicenseText) {
259  $out['license_ref_text'] = $lic['license_text'] ?? '';
260  }
261  return $out;
262  }, $entry['licenses']);
263 
264  $data[] = array(
265  'text' => $text,
266  'is_active' => $entry['is_active'],
267  'licenses' => $licenses
268  );
269  }
270 
271  return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
272  }
273 }
Helper class to export license reference bulk data as CSV or JSON from the DB.
setDelimiter($delimiter=',')
Update the delimiter.
exportBulkText($user_pk=0, $group_pk=0, $generateJson=false, $includeLicenseText=false)
Export license reference bulk data from the DB as CSV or JSON.
createJson($result, $includeLicenseText=false)
Create JSON content, nested licenses format, compatible with CustomTextImport.
normalizeNewlinesForCsv($value)
Convert CR/LF variants to literal for line-safe CSV rows.
groupResultsByText($result, $includeLicenseText=false)
Group flat DB rows by rf_text into the nested licenses format.
createCsvContent($result, $includeLicenseText=false)
Create CSV content, one row per text+license, compatible with CustomTextImport.
setEnclosure($enclosure='"')
Update the enclosure.
static escapeNewlines($value)
Flatten real newlines to a literal so a field stays on one physical CSV line. Backslashes are escap...
fo_dbManager * dbManager
fo_dbManager object
Definition: process.c:16
Utility functions for specific applications.