Skip to content

Commit

Permalink
Rewrote fix for preserving workbook attrs
Browse files Browse the repository at this point in the history
In response to feedback, the fix for issue PHPOffice#523 has been completely
rewritten.  This fix preserves workbook view attributes when one
reads and writes Xlsx documents.  The old code did this by storing
all workbook attributes in a single map.  The new code stores
each attribute as a separate property with its own gettor and settor
methods.
  • Loading branch information
billblume committed Jun 12, 2018
1 parent 90143d0 commit a6f0e2e
Show file tree
Hide file tree
Showing 4 changed files with 363 additions and 54 deletions.
71 changes: 65 additions & 6 deletions src/PhpSpreadsheet/Reader/Xlsx.php
Original file line number Diff line number Diff line change
Expand Up @@ -1973,14 +1973,10 @@ public function load($pFilename)
}

if ((!$this->readDataOnly) || (!empty($this->loadSheetsOnly))) {
if ($xmlWorkbook->bookViews->workbookView) {
foreach ($xmlWorkbook->bookViews->workbookView->attributes() as $attr => $value) {
$excel->setWorkbookViewAttribute((string) $attr, (string) $value);
}
}
$workbookView = $xmlWorkbook->bookViews->workbookView;

// active sheet index
$activeTab = (int) ($xmlWorkbook->bookViews->workbookView['activeTab']); // refers to old sheet index
$activeTab = (int) ($workbookView['activeTab']); // refers to old sheet index

// keep active sheet index if sheet is still loaded, else first sheet is set as the active
if (isset($mapSheetId[$activeTab]) && $mapSheetId[$activeTab] !== null) {
Expand All @@ -1991,6 +1987,46 @@ public function load($pFilename)
}
$excel->setActiveSheetIndex(0);
}

if (isset($workbookView['showHorizontalScroll'])) {
$showHorizontalScroll = (string) $workbookView['showHorizontalScroll'];
$excel->setShowHorizontalScroll($this->castXsdBooleanToBool($showHorizontalScroll));
}

if (isset($workbookView['showVerticalScroll'])) {
$showVerticalScroll = (string) $workbookView['showVerticalScroll'];
$excel->setShowVerticalScroll($this->castXsdBooleanToBool($showVerticalScroll));
}

if (isset($workbookView['showSheetTabs'])) {
$showSheetTabs = (string) $workbookView['showSheetTabs'];
$excel->setShowSheetTabs($this->castXsdBooleanToBool($showSheetTabs));
}

if (isset($workbookView['minimized'])) {
$minimized = (string) $workbookView['minimized'];
$excel->setMinimized($this->castXsdBooleanToBool($minimized));
}

if (isset($workbookView['autoFilterDateGrouping'])) {
$autoFilterDateGrouping = (string) $workbookView['autoFilterDateGrouping'];
$excel->setAutoFilterDateGrouping($this->castXsdBooleanToBool($autoFilterDateGrouping));
}

if (isset($workbookView['firstSheet'])) {
$firstSheet = (string) $workbookView['firstSheet'];
$excel->setFirstSheetIndex((int) $firstSheet);
}

if (isset($workbookView['visibility'])) {
$visibility = (string) $workbookView['visibility'];
$excel->setVisibility($visibility);
}

if (isset($workbookView['tabRatio'])) {
$tabRatio = (string) $workbookView['tabRatio'];
$excel->setTabRatio((int) $tabRatio);
}
}

break;
Expand Down Expand Up @@ -2481,4 +2517,27 @@ private function readPrinterSettings(Spreadsheet $excel, ZipArchive $zip, $dir,
}
unset($unparsedPrinterSettings);
}

/**
* Convert an 'xsd:boolean' XML value to a PHP boolean value.
* A valid 'xsd:boolean' XML value can be one of the following
* four values: 'true', 'false', '1', '0'. It is case sensitive.
*
* Note that just doing '(bool) $xsdBoolean' is not safe,
* since '(bool) "false"' returns true.
*
* @see https://www.w3.org/TR/xmlschema11-2/#boolean
*
* @param string $xsdBoolean An XML string value of type 'xsd:boolean'
*
* @return bool Boolean value
*/
private function castXsdBooleanToBool($xsdBoolean)
{
if ($xsdBoolean === 'false') {
return false;
}

return (bool) $xsdBoolean;
}
}
268 changes: 250 additions & 18 deletions src/PhpSpreadsheet/Spreadsheet.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@

class Spreadsheet
{
// Allowable values for workbook window visilbity
const VISIBILITY_VISIBLE = 'visible';
const VISIBILITY_HIDDEN = 'hidden';
const VISIBILITY_VERY_HIDDEN = 'veryHidden';

private static $workbookViewVisibilityValues = [
self::VISIBILITY_VISIBLE,
self::VISIBILITY_HIDDEN,
self::VISIBILITY_VERY_HIDDEN,
];

/**
* Unique ID.
*
Expand Down Expand Up @@ -124,11 +135,65 @@ class Spreadsheet
private $unparsedLoadedData = [];

/**
* workbookViewAttributes : null if workbook isn't Excel 2007 or doesn't have any workbook bookviews.
* Controls visibility of the horizonal scroll bar in the application.
*
* @var null|array
* @var bool
*/
private $showHorizontalScroll = true;

/**
* Controls visibility of the horizonal scroll bar in the application.
*
* @var bool
*/
private $showVerticalScroll = true;

/**
* Controls visibility of the sheet tabs in the application.
*
* @var bool
*/
private $showSheetTabs = true;

/**
* Specifies a boolean value that indicates whether the workbook window
* is minimized.
*
* @var bool
*/
private $minimized = false;

/**
* Specifies a boolean value that indicates whether to group dates
* when presenting the user with filtering optiomd in the user
* interface.
*
* @var bool
*/
private $autoFilterDateGrouping = true;

/**
* Specifies the index to the first sheet in the book view.
*
* @var int
*/
private $firstSheetIndex = 0;

/**
* Specifies the visible status of the workbook.
*
* @var string
*/
private $workbookViewAttributes;
private $visibility = self::VISIBILITY_VISIBLE;

/**
* Specifies the ratio between the workbook tabs bar and the horizontal
* scroll bar. TabRatio is assumed to be out of 1000 of the horizontal
* window width.
*
* @var int
*/
private $tabRatio = 600;

/**
* The workbook has macros ?
Expand Down Expand Up @@ -1225,34 +1290,201 @@ public function getID()
}

/**
* Get a workbook bookview attribute.
* Get the visibility of the horizonal scroll bar in the application.
*
* @param string $attr Name of attribute to read
* @param null|string $default Value to return if attribute doesn't exist
* @return bool True if horizonal scroll bar is visible
*/
public function getShowHorizontalScroll()
{
return $this->showHorizontalScroll;
}

/**
* Set the visibility of the horizonal scroll bar in the application.
*
* @param bool $showHorizontalScroll True if horizonal scroll bar is visible
*/
public function setShowHorizontalScroll($showHorizontalScroll)
{
$this->showHorizontalScroll = (bool) $showHorizontalScroll;
}

/**
* Get the visibility of the vertical scroll bar in the application.
*
* @return string Value of attribute
* @return bool True if vertical scroll bar is visible
*/
public function getWorkbookViewAttribute($attr, $default = null)
public function getShowVerticalScroll()
{
if ($this->workbookViewAttributes && isset($this->workbookViewAttributes[$attr])) {
return $this->workbookViewAttributes[$attr];
return $this->showVerticalScroll;
}

/**
* Set the visibility of the vertical scroll bar in the application.
*
* @param bool $showVerticalScroll True if vertical scroll bar is visible
*/
public function setShowVerticalScroll($showVerticalScroll)
{
$this->showVerticalScroll = (bool) $showVerticalScroll;
}

/**
* Get the visibility of the sheet tabs in the application.
*
* @return bool True if the sheet tabs are visible
*/
public function getShowSheetTabs()
{
return $this->showSheetTabs;
}

/**
* Set the visibility of the sheet tabs in the application.
*
* @param bool $showSheetTabs True if sheet tabs are visible
*/
public function setShowSheetTabs($showSheetTabs)
{
$this->showSheetTabs = (bool) $showSheetTabs;
}

/**
* Return whether the workbook window is minimized.
*
* @return bool true if workbook window is minimized
*/
public function getMinimized()
{
return $this->minimized;
}

/**
* Set whether the workbook window is minimized.
*
* @param bool $minimized true if workbook window is minimized
*/
public function setMinimized($minimized)
{
$this->minimized = (bool) $minimized;
}

/**
* Return whether to group dates when presenting the user with
* filtering optiomd in the user interface.
*
* @return bool true if workbook window is minimized
*/
public function getAutoFilterDateGrouping()
{
return $this->autoFilterDateGrouping;
}

/**
* Set whether to group dates when presenting the user with
* filtering optiomd in the user interface.
*
* @param bool $autoFilterDateGrouping true if workbook window is minimized
*/
public function setAutoFilterDateGrouping($autoFilterDateGrouping)
{
$this->autoFilterDateGrouping = (bool) $autoFilterDateGrouping;
}

/**
* Return the first sheet in the book view.
*
* @return int First sheet in book view
*/
public function getFirstSheetIndex()
{
return $this->firstSheetIndex;
}

/**
* Set the first sheet in the book view.
*
* @param int $firstSheetIndex First sheet in book view
*
* @throws PhpSpreadsheetException if the given value is invalid
*/
public function setFirstSheetIndex($firstSheetIndex)
{
if ($firstSheetIndex >= 0) {
$this->firstSheetIndex = (int) $firstSheetIndex;
} else {
throw new Exception('First sheet index must be a positive integer.');
}
}

return $default;
/**
* Return the visibility status of the workbook.
*
* This may be one of the following three values:
* - visibile
*
* @return string Visible status
*/
public function getVisibility()
{
return $this->visibility;
}

/**
* Set a workbook bookview attribute.
* Set the visibility status of the workbook.
*
* Valid values are:
* - 'visible' (self::VISIBILITY_VISIBLE):
* Workbook window is visible
* - 'hidden' (self::VISIBILITY_HIDDEN):
* Workbook window is hidden, but can be shown by the user
* via the user interface
* - 'veryHidden' (self::VISIBILITY_VERY_HIDDEN):
* Workbook window is hidden and cannot be shown in the
* user interface.
*
* @param string $attr Name of attribute to set
* @param string $value Value of the attribute
* @param string $visibility visibility status of the workbook
*
* @throws PhpSpreadsheetException if the given value is invalid
*/
public function setWorkbookViewAttribute($attr, $value)
public function setVisibility($visibility)
{
if ($this->workbookViewAttributes === null) {
$this->workbookViewAttributes = [];
if ($visibility === null) {
$visibility = self::VISIBILITY_VISIBLE;
}

if (in_array($visibility, self::$workbookViewVisibilityValues)) {
$this->visibility = $visibility;
} else {
throw new PhpSpreadsheetException('Invalid visibility value.');
}
}

/**
* Get the ratio between the workbook tabs bar and the horizontal scroll bar.
* TabRatio is assumed to be out of 1000 of the horizontal window width.
*
* @return int Ratio between the workbook tabs bar and the horizontal scroll bar
*/
public function getTabRatio()
{
return $this->tabRatio;
}

$this->workbookViewAttributes[$attr] = $value;
/**
* Set the ratio between the workbook tabs bar and the horizontal scroll bar
* TabRatio is assumed to be out of 1000 of the horizontal window width.
*
* @param int $tabRatio Ratio between the tabs bar and the horizontal scroll bar
*
* @throws PhpSpreadsheetException if the given value is invalid
*/
public function setTabRatio($tabRatio)
{
if ($tabRatio >= 0 || $tabRatio <= 1000) {
$this->tabRatio = (int) $tabRatio;
} else {
throw new PhpSpreadsheetException('Tab ratio must be between 0 and 1000.');
}
}
}
Loading

0 comments on commit a6f0e2e

Please sign in to comment.