ILIAS  eassessment Revision 61809
 All Data Structures Namespaces Files Functions Variables Groups Pages
Style.php
Go to the documentation of this file.
1 <?php
37 {
43  private $_font;
44 
50  private $_fill;
51 
57  private $_borders;
58 
64  private $_alignment;
65 
71  private $_numberFormat;
72 
79 
85  private $_protection;
86 
92  private $_isSupervisor;
93 
99  private $_parent;
100 
106  private $_index;
107 
113  public function __construct($isSupervisor = false)
114  {
115  // Supervisor?
116  $this->_isSupervisor = $isSupervisor;
117 
118  // Initialise values
119  $this->_conditionalStyles = array();
120  $this->_font = new PHPExcel_Style_Font($isSupervisor);
121  $this->_fill = new PHPExcel_Style_Fill($isSupervisor);
122  $this->_borders = new PHPExcel_Style_Borders($isSupervisor);
123  $this->_alignment = new PHPExcel_Style_Alignment($isSupervisor);
124  $this->_numberFormat = new PHPExcel_Style_NumberFormat($isSupervisor);
125  $this->_protection = new PHPExcel_Style_Protection($isSupervisor);
126 
127  // bind parent if we are a supervisor
128  if ($isSupervisor) {
129  $this->_font->bindParent($this);
130  $this->_fill->bindParent($this);
131  $this->_borders->bindParent($this);
132  $this->_alignment->bindParent($this);
133  $this->_numberFormat->bindParent($this);
134  $this->_protection->bindParent($this);
135  }
136  }
137 
144  public function bindParent($parent)
145  {
146  $this->_parent = $parent;
147  return $this;
148  }
149 
155  public function getIsSupervisor()
156  {
157  return $this->_isSupervisor;
158  }
159 
166  public function getSharedComponent()
167  {
168  $activeSheet = $this->getActiveSheet();
169  $selectedCell = $this->getActiveCell(); // e.g. 'A1'
170 
171  if ($activeSheet->cellExists($selectedCell)) {
172  $xfIndex = $activeSheet->getCell($selectedCell)->getXfIndex();
173  } else {
174  $xfIndex = 0;
175  }
176 
177  return $this->_parent->getCellXfByIndex($xfIndex);
178  }
179 
185  public function getActiveSheet()
186  {
187  return $this->_parent->getActiveSheet();
188  }
189 
196  public function getSelectedCells()
197  {
198  return $this->_parent->getActiveSheet()->getSelectedCells();
199  }
200 
207  public function getActiveCell()
208  {
209  return $this->_parent->getActiveSheet()->getActiveCell();
210  }
211 
217  public function getParent()
218  {
219  return $this->_parent;
220  }
221 
261  public function applyFromArray($pStyles = null, $pAdvanced = true) {
262  if (is_array($pStyles)) {
263  if ($this->_isSupervisor) {
264 
265  $pRange = $this->getSelectedCells();
266 
267  // Uppercase coordinate
268  $pRange = strtoupper($pRange);
269 
270  // Is it a cell range or a single cell?
271  if (strpos($pRange, ':') === false) {
272  $rangeA = $pRange;
273  $rangeB = $pRange;
274  } else {
275  list($rangeA, $rangeB) = explode(':', $pRange);
276  }
277 
278  // Calculate range outer borders
279  $rangeStart = PHPExcel_Cell::coordinateFromString($rangeA);
280  $rangeEnd = PHPExcel_Cell::coordinateFromString($rangeB);
281 
282  // Translate column into index
283  $rangeStart[0] = PHPExcel_Cell::columnIndexFromString($rangeStart[0]) - 1;
284  $rangeEnd[0] = PHPExcel_Cell::columnIndexFromString($rangeEnd[0]) - 1;
285 
286  // Make sure we can loop upwards on rows and columns
287  if ($rangeStart[0] > $rangeEnd[0] && $rangeStart[1] > $rangeEnd[1]) {
288  $tmp = $rangeStart;
289  $rangeStart = $rangeEnd;
290  $rangeEnd = $tmp;
291  }
292 
293  // ADVANCED MODE:
294 
295  if ($pAdvanced && isset($pStyles['borders'])) {
296 
297  // 'allborders' is a shorthand property for 'outline' and 'inside' and
298  // it applies to components that have not been set explicitly
299  if (isset($pStyles['borders']['allborders'])) {
300  foreach (array('outline', 'inside') as $component) {
301  if (!isset($pStyles['borders'][$component])) {
302  $pStyles['borders'][$component] = $pStyles['borders']['allborders'];
303  }
304  }
305  unset($pStyles['borders']['allborders']); // not needed any more
306  }
307 
308  // 'outline' is a shorthand property for 'top', 'right', 'bottom', 'left'
309  // it applies to components that have not been set explicitly
310  if (isset($pStyles['borders']['outline'])) {
311  foreach (array('top', 'right', 'bottom', 'left') as $component) {
312  if (!isset($pStyles['borders'][$component])) {
313  $pStyles['borders'][$component] = $pStyles['borders']['outline'];
314  }
315  }
316  unset($pStyles['borders']['outline']); // not needed any more
317  }
318 
319  // 'inside' is a shorthand property for 'vertical' and 'horizontal'
320  // it applies to components that have not been set explicitly
321  if (isset($pStyles['borders']['inside'])) {
322  foreach (array('vertical', 'horizontal') as $component) {
323  if (!isset($pStyles['borders'][$component])) {
324  $pStyles['borders'][$component] = $pStyles['borders']['inside'];
325  }
326  }
327  unset($pStyles['borders']['inside']); // not needed any more
328  }
329 
330  // width and height characteristics of selection, 1, 2, or 3 (for 3 or more)
331  $xMax = min($rangeEnd[0] - $rangeStart[0] + 1, 3);
332  $yMax = min($rangeEnd[1] - $rangeStart[1] + 1, 3);
333 
334  // loop through up to 3 x 3 = 9 regions
335  for ($x = 1; $x <= $xMax; ++$x) {
336  // start column index for region
337  $colStart = ($x == 3) ?
339  : PHPExcel_Cell::stringFromColumnIndex($rangeStart[0] + $x - 1);
340 
341  // end column index for region
342  $colEnd = ($x == 1) ?
344  : PHPExcel_Cell::stringFromColumnIndex($rangeEnd[0] - $xMax + $x);
345 
346  for ($y = 1; $y <= $yMax; ++$y) {
347 
348  // which edges are touching the region
349  $edges = array();
350 
351  // are we at left edge
352  if ($x == 1) {
353  $edges[] = 'left';
354  }
355 
356  // are we at right edge
357  if ($x == $xMax) {
358  $edges[] = 'right';
359  }
360 
361  // are we at top edge?
362  if ($y == 1) {
363  $edges[] = 'top';
364  }
365 
366  // are we at bottom edge?
367  if ($y == $yMax) {
368  $edges[] = 'bottom';
369  }
370 
371  // start row index for region
372  $rowStart = ($y == 3) ?
373  $rangeEnd[1] : $rangeStart[1] + $y - 1;
374 
375  // end row index for region
376  $rowEnd = ($y == 1) ?
377  $rangeStart[1] : $rangeEnd[1] - $yMax + $y;
378 
379  // build range for region
380  $range = $colStart . $rowStart . ':' . $colEnd . $rowEnd;
381 
382  // retrieve relevant style array for region
383  $regionStyles = $pStyles;
384  unset($regionStyles['borders']['inside']);
385 
386  // what are the inner edges of the region when looking at the selection
387  $innerEdges = array_diff( array('top', 'right', 'bottom', 'left'), $edges );
388 
389  // inner edges that are not touching the region should take the 'inside' border properties if they have been set
390  foreach ($innerEdges as $innerEdge) {
391  switch ($innerEdge) {
392  case 'top':
393  case 'bottom':
394  // should pick up 'horizontal' border property if set
395  if (isset($pStyles['borders']['horizontal'])) {
396  $regionStyles['borders'][$innerEdge] = $pStyles['borders']['horizontal'];
397  } else {
398  unset($regionStyles['borders'][$innerEdge]);
399  }
400  break;
401  case 'left':
402  case 'right':
403  // should pick up 'vertical' border property if set
404  if (isset($pStyles['borders']['vertical'])) {
405  $regionStyles['borders'][$innerEdge] = $pStyles['borders']['vertical'];
406  } else {
407  unset($regionStyles['borders'][$innerEdge]);
408  }
409  break;
410  }
411  }
412 
413  // apply region style to region by calling applyFromArray() in simple mode
414  $this->getActiveSheet()->getStyle($range)->applyFromArray($regionStyles, false);
415  }
416  }
417  return;
418  }
419 
420  // SIMPLE MODE:
421 
422  // Selection type, inspect
423  if (preg_match('/^[A-Z]+1:[A-Z]+1048576$/', $pRange)) {
424  $selectionType = 'COLUMN';
425  } else if (preg_match('/^A[0-9]+:XFD[0-9]+$/', $pRange)) {
426  $selectionType = 'ROW';
427  } else {
428  $selectionType = 'CELL';
429  }
430 
431  // First loop through columns, rows, or cells to find out which styles are affected by this operation
432  switch ($selectionType) {
433  case 'COLUMN':
434  $oldXfIndexes = array();
435  for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
436  $oldXfIndexes[$this->getActiveSheet()->getColumnDimensionByColumn($col)->getXfIndex()] = true;
437  }
438  break;
439 
440  case 'ROW':
441  $oldXfIndexes = array();
442  for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
443  if ($this->getActiveSheet()->getRowDimension($row)->getXfIndex() == null) {
444  $oldXfIndexes[0] = true; // row without explicit style should be formatted based on default style
445  } else {
446  $oldXfIndexes[$this->getActiveSheet()->getRowDimension($row)->getXfIndex()] = true;
447  }
448  }
449  break;
450 
451  case 'CELL':
452  $oldXfIndexes = array();
453  for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
454  for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
455  $oldXfIndexes[$this->getActiveSheet()->getCellByColumnAndRow($col, $row)->getXfIndex()] = true;
456  }
457  }
458  break;
459  }
460 
461  // clone each of the affected styles, apply the style arrray, and add the new styles to the workbook
462  $workbook = $this->getActiveSheet()->getParent();
463  foreach ($oldXfIndexes as $oldXfIndex => $dummy) {
464  $style = $workbook->getCellXfByIndex($oldXfIndex);
465  $newStyle = clone $style;
466  $newStyle->applyFromArray($pStyles);
467 
468  if ($existingStyle = $workbook->getCellXfByHashCode($newStyle->getHashCode())) {
469  // there is already such cell Xf in our collection
470  $newXfIndexes[$oldXfIndex] = $existingStyle->getIndex();
471  } else {
472  // we don't have such a cell Xf, need to add
473  $workbook->addCellXf($newStyle);
474  $newXfIndexes[$oldXfIndex] = $newStyle->getIndex();
475  }
476  }
477 
478  // Loop through columns, rows, or cells again and update the XF index
479  switch ($selectionType) {
480  case 'COLUMN':
481  for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
482  $columnDimension = $this->getActiveSheet()->getColumnDimensionByColumn($col);
483  $oldXfIndex = $columnDimension->getXfIndex();
484  $columnDimension->setXfIndex($newXfIndexes[$oldXfIndex]);
485  }
486  break;
487 
488  case 'ROW':
489  for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
490  $rowDimension = $this->getActiveSheet()->getRowDimension($row);
491  $oldXfIndex = $rowDimension->getXfIndex() === null ?
492  0 : $rowDimension->getXfIndex(); // row without explicit style should be formatted based on default style
493  $rowDimension->setXfIndex($newXfIndexes[$oldXfIndex]);
494  }
495  break;
496 
497  case 'CELL':
498  for ($col = $rangeStart[0]; $col <= $rangeEnd[0]; ++$col) {
499  for ($row = $rangeStart[1]; $row <= $rangeEnd[1]; ++$row) {
500  $cell = $this->getActiveSheet()->getCellByColumnAndRow($col, $row);
501  $oldXfIndex = $cell->getXfIndex();
502  $cell->setXfIndex($newXfIndexes[$oldXfIndex]);
503  }
504  }
505  break;
506  }
507 
508  } else {
509  // not a supervisor, just apply the style array directly on style object
510  if (array_key_exists('fill', $pStyles)) {
511  $this->getFill()->applyFromArray($pStyles['fill']);
512  }
513  if (array_key_exists('font', $pStyles)) {
514  $this->getFont()->applyFromArray($pStyles['font']);
515  }
516  if (array_key_exists('borders', $pStyles)) {
517  $this->getBorders()->applyFromArray($pStyles['borders']);
518  }
519  if (array_key_exists('alignment', $pStyles)) {
520  $this->getAlignment()->applyFromArray($pStyles['alignment']);
521  }
522  if (array_key_exists('numberformat', $pStyles)) {
523  $this->getNumberFormat()->applyFromArray($pStyles['numberformat']);
524  }
525  if (array_key_exists('protection', $pStyles)) {
526  $this->getProtection()->applyFromArray($pStyles['protection']);
527  }
528  }
529  } else {
530  throw new Exception("Invalid style array passed.");
531  }
532  return $this;
533  }
534 
540  public function getFill() {
541  return $this->_fill;
542  }
543 
549  public function getFont() {
550  return $this->_font;
551  }
552 
559  public function setFont(PHPExcel_Style_Font $font)
560  {
561  $this->_font = $font;
562  return $this;
563  }
564 
570  public function getBorders() {
571  return $this->_borders;
572  }
573 
579  public function getAlignment() {
580  return $this->_alignment;
581  }
582 
588  public function getNumberFormat() {
589  return $this->_numberFormat;
590  }
591 
597  public function getConditionalStyles() {
598  return $this->getActiveSheet()->getConditionalStyles($this->getActiveCell());
599  }
600 
607  public function setConditionalStyles($pValue = null) {
608  if (is_array($pValue)) {
609  $this->getActiveSheet()->setConditionalStyles($this->getSelectedCells(), $pValue);
610  }
611  return $this;
612  }
613 
619  public function getProtection() {
620  return $this->_protection;
621  }
622 
628  public function getHashCode() {
629  $hashConditionals = '';
630  foreach ($this->_conditionalStyles as $conditional) {
631  $hashConditionals .= $conditional->getHashCode();
632  }
633 
634  return md5(
635  $this->_fill->getHashCode()
636  . $this->_font->getHashCode()
637  . $this->_borders->getHashCode()
638  . $this->_alignment->getHashCode()
639  . $this->_numberFormat->getHashCode()
640  . $hashConditionals
641  . $this->_protection->getHashCode()
642  . __CLASS__
643  );
644  }
645 
651  public function getIndex()
652  {
653  return $this->_index;
654  }
655 
661  public function setIndex($pValue)
662  {
663  $this->_index = $pValue;
664  }
665 
669  public function __clone() {
670  $vars = get_object_vars($this);
671  foreach ($vars as $key => $value) {
672  if ((is_object($value)) && ($key != '_parent')) {
673  $this->$key = clone $value;
674  } else {
675  $this->$key = $value;
676  }
677  }
678  }
679 }