updated a couple packages (#1567)
[openemr.git] / vendor / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Collection / Cells.php
blobac5faf047966a1f7e3202d8350a5e20679fd6a45
1 <?php
3 namespace PhpOffice\PhpSpreadsheet\Collection;
5 use PhpOffice\PhpSpreadsheet\Cell\Cell;
6 use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
7 use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;
8 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
9 use Psr\SimpleCache\CacheInterface;
11 class Cells
13 /**
14 * @var \Psr\SimpleCache\CacheInterface
16 private $cache;
18 /**
19 * Parent worksheet.
21 * @var Worksheet
23 private $parent;
25 /**
26 * The currently active Cell.
28 * @var Cell
30 private $currentCell;
32 /**
33 * Coordinate of the currently active Cell.
35 * @var string
37 private $currentCoordinate;
39 /**
40 * Flag indicating whether the currently active Cell requires saving.
42 * @var bool
44 private $currentCellIsDirty = false;
46 /**
47 * An index of existing cells. Booleans indexed by their coordinate.
49 * @var bool[]
51 private $index = [];
53 /**
54 * Prefix used to uniquely identify cache data for this worksheet.
56 * @var string
58 private $cachePrefix;
60 /**
61 * Initialise this new cell collection.
63 * @param Worksheet $parent The worksheet for this cell collection
64 * @param CacheInterface $cache
66 public function __construct(Worksheet $parent, CacheInterface $cache)
68 // Set our parent worksheet.
69 // This is maintained here to facilitate re-attaching it to Cell objects when
70 // they are woken from a serialized state
71 $this->parent = $parent;
72 $this->cache = $cache;
73 $this->cachePrefix = $this->getUniqueID();
76 /**
77 * Return the parent worksheet for this cell collection.
79 * @return Worksheet
81 public function getParent()
83 return $this->parent;
86 /**
87 * Whether the collection holds a cell for the given coordinate.
89 * @param string $pCoord Coordinate of the cell to check
91 * @return bool
93 public function has($pCoord)
95 if ($pCoord === $this->currentCoordinate) {
96 return true;
99 // Check if the requested entry exists in the index
100 return isset($this->index[$pCoord]);
104 * Add or update a cell in the collection.
106 * @param Cell $cell Cell to update
108 * @throws PhpSpreadsheetException
110 * @return Cell
112 public function update(Cell $cell)
114 return $this->add($cell->getCoordinate(), $cell);
118 * Delete a cell in cache identified by coordinate.
120 * @param string $pCoord Coordinate of the cell to delete
122 public function delete($pCoord)
124 if ($pCoord === $this->currentCoordinate && $this->currentCell !== null) {
125 $this->currentCell->detach();
126 $this->currentCoordinate = null;
127 $this->currentCell = null;
128 $this->currentCellIsDirty = false;
131 unset($this->index[$pCoord]);
133 // Delete the entry from cache
134 $this->cache->delete($this->cachePrefix . $pCoord);
138 * Get a list of all cell coordinates currently held in the collection.
140 * @return string[]
142 public function getCoordinates()
144 return array_keys($this->index);
148 * Get a sorted list of all cell coordinates currently held in the collection by row and column.
150 * @return string[]
152 public function getSortedCoordinates()
154 $sortKeys = [];
155 foreach ($this->getCoordinates() as $coord) {
156 sscanf($coord, '%[A-Z]%d', $column, $row);
157 $sortKeys[sprintf('%09d%3s', $row, $column)] = $coord;
159 ksort($sortKeys);
161 return array_values($sortKeys);
165 * Get highest worksheet column and highest row that have cell records.
167 * @return array Highest column name and highest row number
169 public function getHighestRowAndColumn()
171 // Lookup highest column and highest row
172 $col = ['A' => '1A'];
173 $row = [1];
174 foreach ($this->getCoordinates() as $coord) {
175 sscanf($coord, '%[A-Z]%d', $c, $r);
176 $row[$r] = $r;
177 $col[$c] = strlen($c) . $c;
179 if (!empty($row)) {
180 // Determine highest column and row
181 $highestRow = max($row);
182 $highestColumn = substr(max($col), 1);
185 return [
186 'row' => $highestRow,
187 'column' => $highestColumn,
192 * Return the cell coordinate of the currently active cell object.
194 * @return string
196 public function getCurrentCoordinate()
198 return $this->currentCoordinate;
202 * Return the column coordinate of the currently active cell object.
204 * @return string
206 public function getCurrentColumn()
208 sscanf($this->currentCoordinate, '%[A-Z]%d', $column, $row);
210 return $column;
214 * Return the row coordinate of the currently active cell object.
216 * @return int
218 public function getCurrentRow()
220 sscanf($this->currentCoordinate, '%[A-Z]%d', $column, $row);
222 return (int) $row;
226 * Get highest worksheet column.
228 * @param string $row Return the highest column for the specified row,
229 * or the highest column of any row if no row number is passed
231 * @return string Highest column name
233 public function getHighestColumn($row = null)
235 if ($row == null) {
236 $colRow = $this->getHighestRowAndColumn();
238 return $colRow['column'];
241 $columnList = [1];
242 foreach ($this->getCoordinates() as $coord) {
243 sscanf($coord, '%[A-Z]%d', $c, $r);
244 if ($r != $row) {
245 continue;
247 $columnList[] = Coordinate::columnIndexFromString($c);
250 return Coordinate::stringFromColumnIndex(max($columnList) + 1);
254 * Get highest worksheet row.
256 * @param string $column Return the highest row for the specified column,
257 * or the highest row of any column if no column letter is passed
259 * @return int Highest row number
261 public function getHighestRow($column = null)
263 if ($column == null) {
264 $colRow = $this->getHighestRowAndColumn();
266 return $colRow['row'];
269 $rowList = [0];
270 foreach ($this->getCoordinates() as $coord) {
271 sscanf($coord, '%[A-Z]%d', $c, $r);
272 if ($c != $column) {
273 continue;
275 $rowList[] = $r;
278 return max($rowList);
282 * Generate a unique ID for cache referencing.
284 * @return string Unique Reference
286 private function getUniqueID()
288 return uniqid('phpspreadsheet.', true) . '.';
292 * Clone the cell collection.
294 * @param Worksheet $parent The new worksheet that we're copying to
296 * @return self
298 public function cloneCellCollection(Worksheet $parent)
300 $this->storeCurrentCell();
301 $newCollection = clone $this;
303 $newCollection->parent = $parent;
304 if (($newCollection->currentCell !== null) && (is_object($newCollection->currentCell))) {
305 $newCollection->currentCell->attach($this);
308 // Get old values
309 $oldKeys = $newCollection->getAllCacheKeys();
310 $oldValues = $newCollection->cache->getMultiple($oldKeys);
311 $newValues = [];
312 $oldCachePrefix = $newCollection->cachePrefix;
314 // Change prefix
315 $newCollection->cachePrefix = $newCollection->getUniqueID();
316 foreach ($oldValues as $oldKey => $value) {
317 $newValues[str_replace($oldCachePrefix, $newCollection->cachePrefix, $oldKey)] = clone $value;
320 // Store new values
321 $stored = $newCollection->cache->setMultiple($newValues);
322 if (!$stored) {
323 $newCollection->__destruct();
325 throw new PhpSpreadsheetException('Failed to copy cells in cache');
328 return $newCollection;
332 * Remove a row, deleting all cells in that row.
334 * @param string $row Row number to remove
336 public function removeRow($row)
338 foreach ($this->getCoordinates() as $coord) {
339 sscanf($coord, '%[A-Z]%d', $c, $r);
340 if ($r == $row) {
341 $this->delete($coord);
347 * Remove a column, deleting all cells in that column.
349 * @param string $column Column ID to remove
351 public function removeColumn($column)
353 foreach ($this->getCoordinates() as $coord) {
354 sscanf($coord, '%[A-Z]%d', $c, $r);
355 if ($c == $column) {
356 $this->delete($coord);
362 * Store cell data in cache for the current cell object if it's "dirty",
363 * and the 'nullify' the current cell object.
365 * @throws PhpSpreadsheetException
367 private function storeCurrentCell()
369 if ($this->currentCellIsDirty && !empty($this->currentCoordinate)) {
370 $this->currentCell->detach();
372 $stored = $this->cache->set($this->cachePrefix . $this->currentCoordinate, $this->currentCell);
373 if (!$stored) {
374 $this->__destruct();
376 throw new PhpSpreadsheetException("Failed to store cell {$this->currentCoordinate} in cache");
378 $this->currentCellIsDirty = false;
381 $this->currentCoordinate = null;
382 $this->currentCell = null;
386 * Add or update a cell identified by its coordinate into the collection.
388 * @param string $pCoord Coordinate of the cell to update
389 * @param Cell $cell Cell to update
391 * @throws PhpSpreadsheetException
393 * @return \PhpOffice\PhpSpreadsheet\Cell\Cell
395 public function add($pCoord, Cell $cell)
397 if ($pCoord !== $this->currentCoordinate) {
398 $this->storeCurrentCell();
400 $this->index[$pCoord] = true;
402 $this->currentCoordinate = $pCoord;
403 $this->currentCell = $cell;
404 $this->currentCellIsDirty = true;
406 return $cell;
410 * Get cell at a specific coordinate.
412 * @param string $pCoord Coordinate of the cell
414 * @throws PhpSpreadsheetException
416 * @return \PhpOffice\PhpSpreadsheet\Cell\Cell Cell that was found, or null if not found
418 public function get($pCoord)
420 if ($pCoord === $this->currentCoordinate) {
421 return $this->currentCell;
423 $this->storeCurrentCell();
425 // Return null if requested entry doesn't exist in collection
426 if (!$this->has($pCoord)) {
427 return null;
430 // Check if the entry that has been requested actually exists
431 $cell = $this->cache->get($this->cachePrefix . $pCoord);
432 if ($cell === null) {
433 throw new PhpSpreadsheetException("Cell entry {$pCoord} no longer exists in cache. This probably means that the cache was cleared by someone else.");
436 // Set current entry to the requested entry
437 $this->currentCoordinate = $pCoord;
438 $this->currentCell = $cell;
439 // Re-attach this as the cell's parent
440 $this->currentCell->attach($this);
442 // Return requested entry
443 return $this->currentCell;
447 * Clear the cell collection and disconnect from our parent.
449 public function unsetWorksheetCells()
451 if ($this->currentCell !== null) {
452 $this->currentCell->detach();
453 $this->currentCell = null;
454 $this->currentCoordinate = null;
457 // Flush the cache
458 $this->__destruct();
460 $this->index = [];
462 // detach ourself from the worksheet, so that it can then delete this object successfully
463 $this->parent = null;
467 * Destroy this cell collection.
469 public function __destruct()
471 $this->cache->deleteMultiple($this->getAllCacheKeys());
475 * Returns all known cache keys.
477 * @return string[]
479 private function getAllCacheKeys()
481 $keys = [];
482 foreach ($this->getCoordinates() as $coordinate) {
483 $keys[] = $this->cachePrefix . $coordinate;
486 return $keys;