<?php

namespace RodrigoPedra\ClearSaleID\Entity\Request;

use InvalidArgumentException;
use RodrigoPedra\ClearSaleID\Entity\XmlEntityInterface;
use RodrigoPedra\ClearSaleID\Exception\RequiredFieldException;
use XMLWriter;

class Phone implements XmlEntityInterface
{
    const NAO_DEFINIDO = 0;
    const RESIDENCIAL  = 1;
    const COMERCIAL    = 2;
    const RECADOS      = 3;
    const COBRANCA     = 4;
    const TEMPORARIO   = 5;
    const CELULAR      = 6;

    private static $types = [
        self::NAO_DEFINIDO,
        self::RESIDENCIAL,
        self::COMERCIAL,
        self::RECADOS,
        self::COBRANCA,
        self::TEMPORARIO,
        self::CELULAR,
    ];

    /** @var  int */
    private $type;

    /** @var  string */
    private $ddi;

    /** @var  string */
    private $ddd;

    /** @var  string */
    private $number;

    /** @var  string */
    private $extension;

    /**
     * @param  int    $type
     * @param  string $ddd
     * @param  string $number
     *
     * @return \RodrigoPedra\ClearSaleID\Entity\Request\Phone
     */
    public static function create( $type, $ddd, $number )
    {
        $instance = new self;

        $instance->setType( $type );
        $instance->setDDD( $ddd );
        $instance->setNumber( $number );

        return $instance;
    }

    /**
     * @return int
     */
    public function getType()
    {
        return $this->type;
    }

    /**
     * @param  int $type
     *
     * @return $this
     */
    public function setType( $type )
    {
        if (!in_array( intval( $type ), self::$types )) {
            throw new InvalidArgumentException( sprintf( 'Invalid type (%s)', $type ) );
        }

        $this->type = $type;

        return $this;
    }

    /**
     * @return string
     */
    public function getDDI()
    {
        return $this->ddi;
    }

    /**
     * @param  string $ddi
     *
     * @return $this
     */
    public function setDDI( $ddi )
    {
        $ddi = preg_replace( '/^0+|\D/', '', $ddi );

        if (strlen( $ddi ) < 1 || strlen( $ddi ) > 3) {
            throw new InvalidArgumentException( sprintf( 'Invalid DDI (%s)', $ddi ) );
        }

        $this->ddi = $ddi;

        return $this;
    }

    /**
     * @return string
     */
    public function getDDD()
    {
        return $this->ddd;
    }

    /**
     * @param  string $ddd
     *
     * @return $this
     */
    public function setDDD( $ddd )
    {
        $ddd = preg_replace( '/^0+|\D/', '', $ddd );

        if (strlen( $ddd ) !== 2) {
            throw new InvalidArgumentException( sprintf( 'Invalid DDD (%s)', $ddd ) );
        }

        $this->ddd = $ddd;

        return $this;
    }

    /**
     * @return string
     */
    public function getNumber()
    {
        return $this->number;
    }

    /**
     * @param  string $number
     *
     * @return $this
     */
    public function setNumber( $number )
    {
        $number = preg_replace( '/^0+|\D/', '', $number );

        if (strlen( $number ) !== 9 && strlen( $number ) !== 8) {
            throw new InvalidArgumentException( sprintf( 'Invalid Number (%s)', $number ) );
        }

        $this->number = $number;

        return $this;
    }

    /**
     * @return string
     */
    public function getExtension()
    {
        return $this->extension;
    }

    /**
     * @param  string $extension
     *
     * @return $this
     */
    public function setExtension( $extension )
    {
        if (strlen( $extension ) > 5) {
            throw new InvalidArgumentException( sprintf( 'Extension should be no longer than 5 characters (%s)',
                $extension ) );
        }

        $this->extension = $extension;

        return $this;
    }

    /**
     * @param  \XMLWriter $XMLWriter
     *
     * @throws \RodrigoPedra\ClearSaleID\Exception\RequiredFieldException
     */
    public function toXML( XMLWriter $XMLWriter )
    {
        $XMLWriter->startElement( 'Telefone' );

        if (!is_null( $this->type )) {
            $XMLWriter->writeElement( 'Tipo', $this->type );
        } else {
            throw new RequiredFieldException( 'Field Type of the Phone object is required' );
        }

        if ($this->ddi) {
            $XMLWriter->writeElement( 'DDI', $this->ddi );
        }

        if ($this->ddd) {
            $XMLWriter->writeElement( 'DDD', $this->ddd );
        } else {
            throw new RequiredFieldException( 'Field DDD of the Phone object is required' );
        }

        if ($this->number) {
            $XMLWriter->writeElement( 'Numero', $this->number );
        } else {
            throw new RequiredFieldException( 'Field Number of the Phone object is required' );
        }

        if ($this->extension) {
            $XMLWriter->writeElement( 'Ramal', $this->extension );
        }

        $XMLWriter->endElement();
    }
}


<?php

namespace PhpOffice\PhpSpreadsheet\Worksheet;

use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;

class Drawing extends BaseDrawing
{
    /**
     * Path.
     *
     * @var string
     */
    private $path;

    /**
     * Create a new Drawing.
     */
    public function __construct()
    {
        // Initialise values
        $this->path = '';

        // Initialize parent
        parent::__construct();
    }

    /**
     * Get Filename.
     *
     * @return string
     */
    public function getFilename()
    {
        return basename($this->path);
    }

    /**
     * Get indexed filename (using image index).
     *
     * @return string
     */
    public function getIndexedFilename()
    {
        $fileName = $this->getFilename();
        $fileName = str_replace(' ', '_', $fileName);

        return str_replace('.' . $this->getExtension(), '', $fileName) . $this->getImageIndex() . '.' . $this->getExtension();
    }

    /**
     * Get Extension.
     *
     * @return string
     */
    public function getExtension()
    {
        $exploded = explode('.', basename($this->path));

        return $exploded[count($exploded) - 1];
    }

    /**
     * Get Path.
     *
     * @return string
     */
    public function getPath()
    {
        return $this->path;
    }

    /**
     * Set Path.
     *
     * @param string $pValue File path
     * @param bool $pVerifyFile Verify file
     *
     * @throws PhpSpreadsheetException
     *
     * @return Drawing
     */
    public function setPath($pValue, $pVerifyFile = true)
    {
        if ($pVerifyFile) {
            if (file_exists($pValue)) {
                $this->path = $pValue;

                if ($this->width == 0 && $this->height == 0) {
                    // Get width/height
                    list($this->width, $this->height) = getimagesize($pValue);
                }
            } else {
                throw new PhpSpreadsheetException("File $pValue not found!");
            }
        } else {
            $this->path = $pValue;
        }

        return $this;
    }

    /**
     * Get hash code.
     *
     * @return string Hash code
     */
    public function getHashCode()
    {
        return md5(
            $this->path .
            parent::getHashCode() .
            __CLASS__
        );
    }
}


<?php
namespace Psr6NullCache;

use Psr\Cache\CacheItemInterface;
use DateTimeInterface;
use DateInterval;
use DateTime;

final class CacheItem implements CacheItemInterface
{

    /**
     *
     * @var string
     */
    private $key;

    /**
     *
     * @var mixed
     */
    private $value;

    /**
     *
     * @var boolean
     */
    private $isHit;

    /**
     *
     * @var null DateTimeInterface
     */
    private $expires;

    public function __construct($key, $value, $isHit, DateTimeInterface $expires = null)
    {
        $this->key = $key;
        $this->value = $value;
        $this->isHit = (bool) $isHit;
        $this->expires = $expires;
    }

    /**
     * Returns the key for the current cache item.
     *
     * The key is loaded by the Implementing Library, but should be available to
     * the higher level callers when needed.
     *
     * @return string The key string for this cache item.
     */
    public function getKey()
    {
        return $this->key;
    }

    /**
     * Retrieves the value of the item from the cache associated with this object's key.
     *
     * The value returned must be identical to the value originally stored by set().
     *
     * If isHit() returns false, this method MUST return null. Note that null
     * is a legitimate cached value, so the isHit() method SHOULD be used to
     * differentiate between "null value was found" and "no value was found."
     *
     * @return mixed The value corresponding to this cache item's key, or null if not found.
     */
    public function get()
    {
        if ($this->isHit() !== true) {
            return null;
        }

        return $this->value;
    }

    public function setIsHit($mode = true)
    {
        $this->isHit = $mode;
    }

    /**
     * Confirms if the cache item lookup resulted in a cache hit.
     *
     * Note: This method MUST NOT have a race condition between calling isHit()
     * and calling get().
     *
     * @return bool True if the request resulted in a cache hit. False otherwise.
     */
    public function isHit()
    {
        return $this->isHit;
    }

    /**
     *
     * @return DateTimeInterface null
     */
    public function getExpires()
    {
        return $this->expires;
    }

    /**
     * Sets the value represented by this cache item.
     *
     * The $value argument may be any item that can be serialized by PHP,
     * although the method of serialization is left up to the Implementing
     * Library.
     *
     * @param mixed $value
     *            The serializable value to be stored.
     *
     * @return static The invoked object.
     */
    public function set($value)
    {
        $this->value = $value;

        return $this;
    }

    /**
     * Sets the expiration time for this cache item.
     *
     * @param \DateTimeInterface $expires
     *            The point in time after which the item MUST be considered expired.
     *            If null is passed explicitly, a default value MAY be used. If none is set,
     *            the value should be stored permanently or for as long as the
     *            implementation allows.
     *
     * @return static The called object.
     */
    public function expiresAt($expires)
    {
        if ($expires instanceof DateTimeInterface) {
            $this->expires = $expires;
        } else {
            $this->expires = null;
        }

        return $this;
    }

    /**
     * Sets the expiration time for this cache item.
     *
     * @param int|\DateInterval $time
     *            The period of time from the present after which the item MUST be considered
     *            expired. An integer parameter is understood to be the time in seconds until
     *            expiration. If null is passed explicitly, a default value MAY be used.
     *            If none is set, the value should be stored permanently or for as long as the
     *            implementation allows.
     *
     * @return static The called object.
     */
    public function expiresAfter($time)
    {
        if ($time instanceof DateInterval) {
            $expires = new DateTime();
            $expires->add($time);

            $this->expires = $expires;
        } elseif (is_numeric($time)) {
            $expires = new DateTime('now +' . $time . ' seconds');

            $this->expires = $expires;
        } else {
            $this->expires = null;
        }

        return $this;
    }
}


<?php

namespace PhpOffice\PhpSpreadsheet\Writer\Xls;

use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;

// Original file header of PEAR::Spreadsheet_Excel_Writer_BIFFwriter (used as the base for this class):
// -----------------------------------------------------------------------------------------
// *  Module written/ported by Xavier Noguer <xnoguer@rezebra.com>
// *
// *  The majority of this is _NOT_ my code.  I simply ported it from the
// *  PERL Spreadsheet::WriteExcel module.
// *
// *  The author of the Spreadsheet::WriteExcel module is John McNamara
// *  <jmcnamara@cpan.org>
// *
// *  I _DO_ maintain this code, and John McNamara has nothing to do with the
// *  porting of this code to PHP.  Any questions directly related to this
// *  class library should be directed to me.
// *
// *  License Information:
// *
// *    Spreadsheet_Excel_Writer:  A library for generating Excel Spreadsheets
// *    Copyright (c) 2002-2003 Xavier Noguer xnoguer@rezebra.com
// *
// *    This library is free software; you can redistribute it and/or
// *    modify it under the terms of the GNU Lesser General Public
// *    License as published by the Free Software Foundation; either
// *    version 2.1 of the License, or (at your option) any later version.
// *
// *    This library is distributed in the hope that it will be useful,
// *    but WITHOUT ANY WARRANTY; without even the implied warranty of
// *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// *    Lesser General Public License for more details.
// *
// *    You should have received a copy of the GNU Lesser General Public
// *    License along with this library; if not, write to the Free Software
// *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
// */
class BIFFwriter
{
    /**
     * The byte order of this architecture. 0 => little endian, 1 => big endian.
     *
     * @var int
     */
    private static $byteOrder;

    /**
     * The string containing the data of the BIFF stream.
     *
     * @var string
     */
    public $_data;

    /**
     * The size of the data in bytes. Should be the same as strlen($this->_data).
     *
     * @var int
     */
    public $_datasize;

    /**
     * The maximum length for a BIFF record (excluding record header and length field). See addContinue().
     *
     * @var int
     *
     * @see addContinue()
     */
    private $limit = 8224;

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->_data = '';
        $this->_datasize = 0;
    }

    /**
     * Determine the byte order and store it as class data to avoid
     * recalculating it for each call to new().
     *
     * @return int
     */
    public static function getByteOrder()
    {
        if (!isset(self::$byteOrder)) {
            // Check if "pack" gives the required IEEE 64bit float
            $teststr = pack('d', 1.2345);
            $number = pack('C8', 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F);
            if ($number == $teststr) {
                $byte_order = 0; // Little Endian
            } elseif ($number == strrev($teststr)) {
                $byte_order = 1; // Big Endian
            } else {
                // Give up. I'll fix this in a later version.
                throw new WriterException('Required floating point format not supported on this platform.');
            }
            self::$byteOrder = $byte_order;
        }

        return self::$byteOrder;
    }

    /**
     * General storage function.
     *
     * @param string $data binary data to append
     */
    protected function append($data)
    {
        if (strlen($data) - 4 > $this->limit) {
            $data = $this->addContinue($data);
        }
        $this->_data .= $data;
        $this->_datasize += strlen($data);
    }

    /**
     * General storage function like append, but returns string instead of modifying $this->_data.
     *
     * @param string $data binary data to write
     *
     * @return string
     */
    public function writeData($data)
    {
        if (strlen($data) - 4 > $this->limit) {
            $data = $this->addContinue($data);
        }
        $this->_datasize += strlen($data);

        return $data;
    }

    /**
     * Writes Excel BOF record to indicate the beginning of a stream or
     * sub-stream in the BIFF file.
     *
     * @param int $type type of BIFF file to write: 0x0005 Workbook,
     *                       0x0010 Worksheet
     */
    protected function storeBof($type)
    {
        $record = 0x0809; // Record identifier    (BIFF5-BIFF8)
        $length = 0x0010;

        // by inspection of real files, MS Office Excel 2007 writes the following
        $unknown = pack('VV', 0x000100D1, 0x00000406);

        $build = 0x0DBB; //    Excel 97
        $year = 0x07CC; //    Excel 97

        $version = 0x0600; //    BIFF8

        $header = pack('vv', $record, $length);
        $data = pack('vvvv', $version, $type, $build, $year);
        $this->append($header . $data . $unknown);
    }

    /**
     * Writes Excel EOF record to indicate the end of a BIFF stream.
     */
    protected function storeEof()
    {
        $record = 0x000A; // Record identifier
        $length = 0x0000; // Number of bytes to follow

        $header = pack('vv', $record, $length);
        $this->append($header);
    }

    /**
     * Writes Excel EOF record to indicate the end of a BIFF stream.
     */
    public function writeEof()
    {
        $record = 0x000A; // Record identifier
        $length = 0x0000; // Number of bytes to follow
        $header = pack('vv', $record, $length);

        return $this->writeData($header);
    }

    /**
     * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 bytes. In
     * Excel 97 the limit is 8228 bytes. Records that are longer than these limits
     * must be split up into CONTINUE blocks.
     *
     * This function takes a long BIFF record and inserts CONTINUE records as
     * necessary.
     *
     * @param string $data The original binary data to be written
     *
     * @return string A very convenient string of continue blocks
     */
    private function addContinue($data)
    {
        $limit = $this->limit;
        $record = 0x003C; // Record identifier

        // The first 2080/8224 bytes remain intact. However, we have to change
        // the length field of the record.
        $tmp = substr($data, 0, 2) . pack('v', $limit) . substr($data, 4, $limit);

        $header = pack('vv', $record, $limit); // Headers for continue records

        // Retrieve chunks of 2080/8224 bytes +4 for the header.
        $data_length = strlen($data);
        for ($i = $limit + 4; $i < ($data_length - $limit); $i += $limit) {
            $tmp .= $header;
            $tmp .= substr($data, $i, $limit);
        }

        // Retrieve the last chunk of data
        $header = pack('vv', $record, strlen($data) - $i);
        $tmp .= $header;
        $tmp .= substr($data, $i);

        return $tmp;
    }
}


<?php

namespace PhpOffice\PhpSpreadsheet\Cell;

use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Exception;

/**
 * Validate a cell value according to its validation rules.
 */
class DataValidator
{
    /**
     * Does this cell contain valid value?
     *
     * @param Cell $cell Cell to check the value
     *
     * @return bool
     */
    public function isValid(Cell $cell)
    {
        if (!$cell->hasDataValidation()) {
            return true;
        }

        $cellValue = $cell->getValue();
        $dataValidation = $cell->getDataValidation();

        if (!$dataValidation->getAllowBlank() && ($cellValue === null || $cellValue === '')) {
            return false;
        }

        // TODO: write check on all cases
        switch ($dataValidation->getType()) {
            case DataValidation::TYPE_LIST:
                return $this->isValueInList($cell);
        }

        return false;
    }

    /**
     * Does this cell contain valid value, based on list?
     *
     * @param Cell $cell Cell to check the value
     *
     * @return bool
     */
    private function isValueInList(Cell $cell)
    {
        $cellValue = $cell->getValue();
        $dataValidation = $cell->getDataValidation();

        $formula1 = $dataValidation->getFormula1();
        if (!empty($formula1)) {
            // inline values list
            if ($formula1[0] === '"') {
                return in_array(strtolower($cellValue), explode(',', strtolower(trim($formula1, '"'))), true);
            } elseif (strpos($formula1, ':') > 0) {
                // values list cells
                $matchFormula = '=MATCH(' . $cell->getCoordinate() . ', ' . $formula1 . ', 0)';
                $calculation = Calculation::getInstance($cell->getWorksheet()->getParent());

                try {
                    $result = $calculation->calculateFormula($matchFormula, $cell->getCoordinate(), $cell);

                    return $result !== Functions::NA();
                } catch (Exception $ex) {
                    return false;
                }
            }
        }

        return true;
    }
}


<?php

namespace PhpOffice\PhpSpreadsheet\Worksheet;

use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Exception as PhpSpreadsheetException;

class ColumnCellIterator extends CellIterator
{
    /**
     * Current iterator position.
     *
     * @var int
     */
    private $currentRow;

    /**
     * Column index.
     *
     * @var string
     */
    private $columnIndex;

    /**
     * Start position.
     *
     * @var int
     */
    private $startRow = 1;

    /**
     * End position.
     *
     * @var int
     */
    private $endRow = 1;

    /**
     * Create a new row iterator.
     *
     * @param Worksheet $subject The worksheet to iterate over
     * @param string $columnIndex The column that we want to iterate
     * @param int $startRow The row number at which to start iterating
     * @param int $endRow Optionally, the row number at which to stop iterating
     */
    public function __construct(Worksheet $subject = null, $columnIndex = 'A', $startRow = 1, $endRow = null)
    {
        // Set subject
        $this->worksheet = $subject;
        $this->columnIndex = Coordinate::columnIndexFromString($columnIndex);
        $this->resetEnd($endRow);
        $this->resetStart($startRow);
    }

    /**
     * (Re)Set the start row and the current row pointer.
     *
     * @param int $startRow The row number at which to start iterating
     *
     * @throws PhpSpreadsheetException
     *
     * @return ColumnCellIterator
     */
    public function resetStart($startRow = 1)
    {
        $this->startRow = $startRow;
        $this->adjustForExistingOnlyRange();
        $this->seek($startRow);

        return $this;
    }

    /**
     * (Re)Set the end row.
     *
     * @param int $endRow The row number at which to stop iterating
     *
     * @throws PhpSpreadsheetException
     *
     * @return ColumnCellIterator
     */
    public function resetEnd($endRow = null)
    {
        $this->endRow = ($endRow) ? $endRow : $this->worksheet->getHighestRow();
        $this->adjustForExistingOnlyRange();

        return $this;
    }

    /**
     * Set the row pointer to the selected row.
     *
     * @param int $row The row number to set the current pointer at
     *
     * @throws PhpSpreadsheetException
     *
     * @return ColumnCellIterator
     */
    public function seek($row = 1)
    {
        if (($row < $this->startRow) || ($row > $this->endRow)) {
            throw new PhpSpreadsheetException("Row $row is out of range ({$this->startRow} - {$this->endRow})");
        } elseif ($this->onlyExistingCells && !($this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $row))) {
            throw new PhpSpreadsheetException('In "IterateOnlyExistingCells" mode and Cell does not exist');
        }
        $this->currentRow = $row;

        return $this;
    }

    /**
     * Rewind the iterator to the starting row.
     */
    public function rewind()
    {
        $this->currentRow = $this->startRow;
    }

    /**
     * Return the current cell in this worksheet column.
     *
     * @return null|\PhpOffice\PhpSpreadsheet\Cell\Cell
     */
    public function current()
    {
        return $this->worksheet->getCellByColumnAndRow($this->columnIndex, $this->currentRow);
    }

    /**
     * Return the current iterator key.
     *
     * @return int
     */
    public function key()
    {
        return $this->currentRow;
    }

    /**
     * Set the iterator to its next value.
     */
    public function next()
    {
        do {
            ++$this->currentRow;
        } while (($this->onlyExistingCells) &&
            (!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->currentRow)) &&
            ($this->currentRow <= $this->endRow));
    }

    /**
     * Set the iterator to its previous value.
     */
    public function prev()
    {
        if ($this->currentRow <= $this->startRow) {
            throw new PhpSpreadsheetException("Row is already at the beginning of range ({$this->startRow} - {$this->endRow})");
        }

        do {
            --$this->currentRow;
        } while (($this->onlyExistingCells) &&
            (!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->currentRow)) &&
            ($this->currentRow >= $this->startRow));
    }

    /**
     * Indicate if more rows exist in the worksheet range of rows that we're iterating.
     *
     * @return bool
     */
    public function valid()
    {
        return $this->currentRow <= $this->endRow;
    }

    /**
     * Validate start/end values for "IterateOnlyExistingCells" mode, and adjust if necessary.
     *
     * @throws PhpSpreadsheetException
     */
    protected function adjustForExistingOnlyRange()
    {
        if ($this->onlyExistingCells) {
            while ((!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->startRow)) &&
                ($this->startRow <= $this->endRow)) {
                ++$this->startRow;
            }
            if ($this->startRow > $this->endRow) {
                throw new PhpSpreadsheetException('No cells exist within the specified range');
            }
            while ((!$this->worksheet->cellExistsByColumnAndRow($this->columnIndex, $this->endRow)) &&
                ($this->endRow >= $this->startRow)) {
                --$this->endRow;
            }
            if ($this->endRow < $this->startRow) {
                throw new PhpSpreadsheetException('No cells exist within the specified range');
            }
        }
    }
}


<?php

namespace RodrigoPedra\ClearSaleID\Entity\Request;

use DateTime;
use RodrigoPedra\ClearSaleID\Entity\XmlEntityInterface;
use XMLWriter;

class CustomerBillingData extends AbstractCustomer implements XmlEntityInterface
{
    /**
     * @param  string                                           $id
     * @param  string                                           $type
     * @param  string                                           $legalDocument
     * @param  string                                           $name
     * @param  \RodrigoPedra\ClearSaleID\Entity\Request\Address $address
     * @param  \RodrigoPedra\ClearSaleID\Entity\Request\Phone   $phone
     * @param  \DateTime                                        $birthDate
     *
     * @return \RodrigoPedra\ClearSaleID\Entity\Request\CustomerBillingData
     */
    public static function create(
        $id,
        $type,
        $legalDocument,
        $name,
        Address $address,
        $phone,
        DateTime $birthDate = null
    ) {
        $instance = new self;

        $instance->setId( $id );
        $instance->setType( $type );
        $instance->setLegalDocument1( $legalDocument );
        $instance->setName( $name );
        $instance->setAddress( $address );
        $instance->addPhone( $phone );

        if (!empty( $birthDate )) {
            $instance->setBirthDate( $birthDate );
        }

        return $instance;
    }

    /**
     * @param  \XMLWriter $XMLWriter
     *
     * @throws \RodrigoPedra\ClearSaleID\Exception\RequiredFieldException
     */
    public function toXML( XMLWriter $XMLWriter )
    {
        $XMLWriter->startElement( 'DadosCobranca' );

        parent::toXML( $XMLWriter );

        $XMLWriter->endElement();
    }
}


<?php

namespace PhpOffice\PhpSpreadsheet\Shared;

use PhpOffice\PhpSpreadsheet\Reader\Exception as ReaderException;

class OLERead
{
    private $data = '';

    // Size of a sector = 512 bytes
    const BIG_BLOCK_SIZE = 0x200;

    // Size of a short sector = 64 bytes
    const SMALL_BLOCK_SIZE = 0x40;

    // Size of a directory entry always = 128 bytes
    const PROPERTY_STORAGE_BLOCK_SIZE = 0x80;

    // Minimum size of a standard stream = 4096 bytes, streams smaller than this are stored as short streams
    const SMALL_BLOCK_THRESHOLD = 0x1000;

    // header offsets
    const NUM_BIG_BLOCK_DEPOT_BLOCKS_POS = 0x2c;
    const ROOT_START_BLOCK_POS = 0x30;
    const SMALL_BLOCK_DEPOT_BLOCK_POS = 0x3c;
    const EXTENSION_BLOCK_POS = 0x44;
    const NUM_EXTENSION_BLOCK_POS = 0x48;
    const BIG_BLOCK_DEPOT_BLOCKS_POS = 0x4c;

    // property storage offsets (directory offsets)
    const SIZE_OF_NAME_POS = 0x40;
    const TYPE_POS = 0x42;
    const START_BLOCK_POS = 0x74;
    const SIZE_POS = 0x78;

    public $wrkbook;

    public $summaryInformation;

    public $documentSummaryInformation;

    /**
     * @var int
     */
    private $numBigBlockDepotBlocks;

    /**
     * @var int
     */
    private $rootStartBlock;

    /**
     * @var int
     */
    private $sbdStartBlock;

    /**
     * @var int
     */
    private $extensionBlock;

    /**
     * @var int
     */
    private $numExtensionBlocks;

    /**
     * @var string
     */
    private $bigBlockChain;

    /**
     * @var string
     */
    private $smallBlockChain;

    /**
     * @var string
     */
    private $entry;

    /**
     * @var int
     */
    private $rootentry;

    /**
     * @var array
     */
    private $props = [];

    /**
     * Read the file.
     *
     * @param $pFilename string Filename
     *
     * @throws ReaderException
     */
    public function read($pFilename)
    {
        File::assertFile($pFilename);

        // Get the file identifier
        // Don't bother reading the whole file until we know it's a valid OLE file
        $this->data = file_get_contents($pFilename, false, null, 0, 8);

        // Check OLE identifier
        $identifierOle = pack('CCCCCCCC', 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1);
        if ($this->data != $identifierOle) {
            throw new ReaderException('The filename ' . $pFilename . ' is not recognised as an OLE file');
        }

        // Get the file data
        $this->data = file_get_contents($pFilename);

        // Total number of sectors used for the SAT
        $this->numBigBlockDepotBlocks = self::getInt4d($this->data, self::NUM_BIG_BLOCK_DEPOT_BLOCKS_POS);

        // SecID of the first sector of the directory stream
        $this->rootStartBlock = self::getInt4d($this->data, self::ROOT_START_BLOCK_POS);

        // SecID of the first sector of the SSAT (or -2 if not extant)
        $this->sbdStartBlock = self::getInt4d($this->data, self::SMALL_BLOCK_DEPOT_BLOCK_POS);

        // SecID of the first sector of the MSAT (or -2 if no additional sectors are used)
        $this->extensionBlock = self::getInt4d($this->data, self::EXTENSION_BLOCK_POS);

        // Total number of sectors used by MSAT
        $this->numExtensionBlocks = self::getInt4d($this->data, self::NUM_EXTENSION_BLOCK_POS);

        $bigBlockDepotBlocks = [];
        $pos = self::BIG_BLOCK_DEPOT_BLOCKS_POS;

        $bbdBlocks = $this->numBigBlockDepotBlocks;

        if ($this->numExtensionBlocks != 0) {
            $bbdBlocks = (self::BIG_BLOCK_SIZE - self::BIG_BLOCK_DEPOT_BLOCKS_POS) / 4;
        }

        for ($i = 0; $i < $bbdBlocks; ++$i) {
            $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);
            $pos += 4;
        }

        for ($j = 0; $j < $this->numExtensionBlocks; ++$j) {
            $pos = ($this->extensionBlock + 1) * self::BIG_BLOCK_SIZE;
            $blocksToRead = min($this->numBigBlockDepotBlocks - $bbdBlocks, self::BIG_BLOCK_SIZE / 4 - 1);

            for ($i = $bbdBlocks; $i < $bbdBlocks + $blocksToRead; ++$i) {
                $bigBlockDepotBlocks[$i] = self::getInt4d($this->data, $pos);
                $pos += 4;
            }

            $bbdBlocks += $blocksToRead;
            if ($bbdBlocks < $this->numBigBlockDepotBlocks) {
                $this->extensionBlock = self::getInt4d($this->data, $pos);
            }
        }

        $pos = 0;
        $this->bigBlockChain = '';
        $bbs = self::BIG_BLOCK_SIZE / 4;
        for ($i = 0; $i < $this->numBigBlockDepotBlocks; ++$i) {
            $pos = ($bigBlockDepotBlocks[$i] + 1) * self::BIG_BLOCK_SIZE;

            $this->bigBlockChain .= substr($this->data, $pos, 4 * $bbs);
            $pos += 4 * $bbs;
        }

        $pos = 0;
        $sbdBlock = $this->sbdStartBlock;
        $this->smallBlockChain = '';
        while ($sbdBlock != -2) {
            $pos = ($sbdBlock + 1) * self::BIG_BLOCK_SIZE;

            $this->smallBlockChain .= substr($this->data, $pos, 4 * $bbs);
            $pos += 4 * $bbs;

            $sbdBlock = self::getInt4d($this->bigBlockChain, $sbdBlock * 4);
        }

        // read the directory stream
        $block = $this->rootStartBlock;
        $this->entry = $this->_readData($block);

        $this->readPropertySets();
    }

    /**
     * Extract binary stream data.
     *
     * @param int $stream
     *
     * @return string
     */
    public function getStream($stream)
    {
        if ($stream === null) {
            return null;
        }

        $streamData = '';

        if ($this->props[$stream]['size'] < self::SMALL_BLOCK_THRESHOLD) {
            $rootdata = $this->_readData($this->props[$this->rootentry]['startBlock']);

            $block = $this->props[$stream]['startBlock'];

            while ($block != -2) {
                $pos = $block * self::SMALL_BLOCK_SIZE;
                $streamData .= substr($rootdata, $pos, self::SMALL_BLOCK_SIZE);

                $block = self::getInt4d($this->smallBlockChain, $block * 4);
            }

            return $streamData;
        }
        $numBlocks = $this->props[$stream]['size'] / self::BIG_BLOCK_SIZE;
        if ($this->props[$stream]['size'] % self::BIG_BLOCK_SIZE != 0) {
            ++$numBlocks;
        }

        if ($numBlocks == 0) {
            return '';
        }

        $block = $this->props[$stream]['startBlock'];

        while ($block != -2) {
            $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
            $streamData .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
            $block = self::getInt4d($this->bigBlockChain, $block * 4);
        }

        return $streamData;
    }

    /**
     * Read a standard stream (by joining sectors using information from SAT).
     *
     * @param int $bl Sector ID where the stream starts
     *
     * @return string Data for standard stream
     */
    private function _readData($bl)
    {
        $block = $bl;
        $data = '';

        while ($block != -2) {
            $pos = ($block + 1) * self::BIG_BLOCK_SIZE;
            $data .= substr($this->data, $pos, self::BIG_BLOCK_SIZE);
            $block = self::getInt4d($this->bigBlockChain, $block * 4);
        }

        return $data;
    }

    /**
     * Read entries in the directory stream.
     */
    private function readPropertySets()
    {
        $offset = 0;

        // loop through entires, each entry is 128 bytes
        $entryLen = strlen($this->entry);
        while ($offset < $entryLen) {
            // entry data (128 bytes)
            $d = substr($this->entry, $offset, self::PROPERTY_STORAGE_BLOCK_SIZE);

            // size in bytes of name
            $nameSize = ord($d[self::SIZE_OF_NAME_POS]) | (ord($d[self::SIZE_OF_NAME_POS + 1]) << 8);

            // type of entry
            $type = ord($d[self::TYPE_POS]);

            // sectorID of first sector or short sector, if this entry refers to a stream (the case with workbook)
            // sectorID of first sector of the short-stream container stream, if this entry is root entry
            $startBlock = self::getInt4d($d, self::START_BLOCK_POS);

            $size = self::getInt4d($d, self::SIZE_POS);

            $name = str_replace("\x00", '', substr($d, 0, $nameSize));

            $this->props[] = [
                'name' => $name,
                'type' => $type,
                'startBlock' => $startBlock,
                'size' => $size,
            ];

            // tmp helper to simplify checks
            $upName = strtoupper($name);

            // Workbook directory entry (BIFF5 uses Book, BIFF8 uses Workbook)
            if (($upName === 'WORKBOOK') || ($upName === 'BOOK')) {
                $this->wrkbook = count($this->props) - 1;
            } elseif ($upName === 'ROOT ENTRY' || $upName === 'R') {
                // Root entry
                $this->rootentry = count($this->props) - 1;
            }

            // Summary information
            if ($name == chr(5) . 'SummaryInformation') {
                $this->summaryInformation = count($this->props) - 1;
            }

            // Additional Document Summary information
            if ($name == chr(5) . 'DocumentSummaryInformation') {
                $this->documentSummaryInformation = count($this->props) - 1;
            }

            $offset += self::PROPERTY_STORAGE_BLOCK_SIZE;
        }
    }

    /**
     * Read 4 bytes of data at specified position.
     *
     * @param string $data
     * @param int $pos
     *
     * @return int
     */
    private static function getInt4d($data, $pos)
    {
        if (trim($data) == '') {
            // No data provided
            throw new ReaderException('Parameter data is empty.');
        } elseif ($pos < 0) {
            // Invalid position
            throw new ReaderException('Parameter pos=' . $pos . ' is invalid.');
        }

        $len = strlen($data);
        if ($len < $pos + 4) {
            $data .= str_repeat("\0", $pos + 4 - $len);
        }

        // FIX: represent numbers correctly on 64-bit system
        // http://sourceforge.net/tracker/index.php?func=detail&aid=1487372&group_id=99160&atid=623334
        // Changed by Andreas Rehm 2006 to ensure correct result of the <<24 block on 32 and 64bit systems
        $_or_24 = ord($data[$pos + 3]);
        if ($_or_24 >= 128) {
            // negative number
            $_ord_24 = -abs((256 - $_or_24) << 24);
        } else {
            $_ord_24 = ($_or_24 & 127) << 24;
        }

        return ord($data[$pos]) | (ord($data[$pos + 1]) << 8) | (ord($data[$pos + 2]) << 16) | $_ord_24;
    }
}


<?php

namespace XQueue\Maileon\API\Reports;

use XQueue\Maileon\API\XML\AbstractXMLWrapper;

/**
 * This class represents a block containing the timestamp, the contact, and some details.
 *
 * @author Jannik Jochem
 * @author Marcus Ständer | Trusted Mails GmbH | marcus.staender@trusted-mails.com
 */
class Block extends AbstractXMLWrapper
{
    /**
     * @var long
     */
    public $timestamp;

    /**
     * @var com_maileon_api_reports_ReportContact
     */
    public $contact;

    /**
     * @var long
     */
    public $oldStatus;

    /**
     * @var long
     */
    public $newStatus;

    /**
     * @var String
     */
    public $reason;

    /**
     * @return \em string
     *  containing a human-readable representation of this block
     */
    function toString()
    {
        return "Block [timestamp=" . $this->timestamp .
        ", contact=" . $this->contact->toString() .
        ", oldstatus=" . $this->oldStatus .
        ", newstatus=" . $this->newStatus .
        ", reason=" . $this->reason . "]";
    }

    /**
     * @return \em csv string
     *  containing a csv pepresentation of this block
     */
    function toCsvString()
    {
        return "block;" . $this->timestamp .
        ";" . $this->contact->toCsvString() .
        ";" . $this->oldStatus .
        ";" . $this->newStatus .
        ";" . $this->reason;
    }

    /**
     * Initializes this bounce from an XML representation.
     *
     * @param SimpleXMLElement $xmlElement
     *  the XML representation to use
     */
    function fromXML($xmlElement)
    {
        $this->contact = new com_maileon_api_reports_ReportContact();
        $this->contact->fromXML($xmlElement->contact);

        if (isset($xmlElement->timestamp)) $this->timestamp = $xmlElement->timestamp;
        if (isset($xmlElement->old_status)) $this->oldStatus = $xmlElement->old_status;
        if (isset($xmlElement->new_status)) $this->newStatus = $xmlElement->new_status;
        if (isset($xmlElement->reason)) $this->reason = $xmlElement->reason;
    }

    /**
     * For future use, not implemented yet.
     *
     * @return \em SimpleXMLElement
     *  containing the XML serialization of this object
     */
    function toXML()
    {
        // Not implemented yet.
    }
}


<?php

namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;

use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
use PhpOffice\PhpSpreadsheet\Shared\XMLWriter;
use PhpOffice\PhpSpreadsheet\Style\Conditional;
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column;
use PhpOffice\PhpSpreadsheet\Worksheet\AutoFilter\Column\Rule;
use PhpOffice\PhpSpreadsheet\Worksheet\SheetView;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet as PhpspreadsheetWorksheet;
use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;

/**
 * @category   PhpSpreadsheet
 *
 * @copyright  Copyright (c) 2006 - 2015 PhpSpreadsheet (https://github.com/PHPOffice/PhpSpreadsheet)
 */
class Worksheet extends WriterPart
{
    /**
     * Write worksheet to XML format.
     *
     * @param PhpspreadsheetWorksheet $pSheet
     * @param string[] $pStringTable
     * @param bool $includeCharts Flag indicating if we should write charts
     *
     * @throws WriterException
     *
     * @return string XML Output
     */
    public function writeWorksheet(PhpspreadsheetWorksheet $pSheet, $pStringTable = null, $includeCharts = false)
    {
        // Create XML writer
        $objWriter = null;
        if ($this->getParentWriter()->getUseDiskCaching()) {
            $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory());
        } else {
            $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
        }

        // XML header
        $objWriter->startDocument('1.0', 'UTF-8', 'yes');

        // Worksheet
        $objWriter->startElement('worksheet');
        $objWriter->writeAttribute('xml:space', 'preserve');
        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/spreadsheetml/2006/main');
        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');

        // sheetPr
        $this->writeSheetPr($objWriter, $pSheet);

        // Dimension
        $this->writeDimension($objWriter, $pSheet);

        // sheetViews
        $this->writeSheetViews($objWriter, $pSheet);

        // sheetFormatPr
        $this->writeSheetFormatPr($objWriter, $pSheet);

        // cols
        $this->writeCols($objWriter, $pSheet);

        // sheetData
        $this->writeSheetData($objWriter, $pSheet, $pStringTable);

        // sheetProtection
        $this->writeSheetProtection($objWriter, $pSheet);

        // protectedRanges
        $this->writeProtectedRanges($objWriter, $pSheet);

        // autoFilter
        $this->writeAutoFilter($objWriter, $pSheet);

        // mergeCells
        $this->writeMergeCells($objWriter, $pSheet);

        // conditionalFormatting
        $this->writeConditionalFormatting($objWriter, $pSheet);

        // dataValidations
        $this->writeDataValidations($objWriter, $pSheet);

        // hyperlinks
        $this->writeHyperlinks($objWriter, $pSheet);

        // Print options
        $this->writePrintOptions($objWriter, $pSheet);

        // Page margins
        $this->writePageMargins($objWriter, $pSheet);

        // Page setup
        $this->writePageSetup($objWriter, $pSheet);

        // Header / footer
        $this->writeHeaderFooter($objWriter, $pSheet);

        // Breaks
        $this->writeBreaks($objWriter, $pSheet);

        // Drawings and/or Charts
        $this->writeDrawings($objWriter, $pSheet, $includeCharts);

        // LegacyDrawing
        $this->writeLegacyDrawing($objWriter, $pSheet);

        // LegacyDrawingHF
        $this->writeLegacyDrawingHF($objWriter, $pSheet);

        $objWriter->endElement();

        // Return
        return $objWriter->getData();
    }

    /**
     * Write SheetPr.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeSheetPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // sheetPr
        $objWriter->startElement('sheetPr');
        if ($pSheet->getParent()->hasMacros()) {
            //if the workbook have macros, we need to have codeName for the sheet
            if ($pSheet->hasCodeName() == false) {
                $pSheet->setCodeName($pSheet->getTitle());
            }
            $objWriter->writeAttribute('codeName', $pSheet->getCodeName());
        }
        $autoFilterRange = $pSheet->getAutoFilter()->getRange();
        if (!empty($autoFilterRange)) {
            $objWriter->writeAttribute('filterMode', 1);
            $pSheet->getAutoFilter()->showHideRows();
        }

        // tabColor
        if ($pSheet->isTabColorSet()) {
            $objWriter->startElement('tabColor');
            $objWriter->writeAttribute('rgb', $pSheet->getTabColor()->getARGB());
            $objWriter->endElement();
        }

        // outlinePr
        $objWriter->startElement('outlinePr');
        $objWriter->writeAttribute('summaryBelow', ($pSheet->getShowSummaryBelow() ? '1' : '0'));
        $objWriter->writeAttribute('summaryRight', ($pSheet->getShowSummaryRight() ? '1' : '0'));
        $objWriter->endElement();

        // pageSetUpPr
        if ($pSheet->getPageSetup()->getFitToPage()) {
            $objWriter->startElement('pageSetUpPr');
            $objWriter->writeAttribute('fitToPage', '1');
            $objWriter->endElement();
        }

        $objWriter->endElement();
    }

    /**
     * Write Dimension.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeDimension(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // dimension
        $objWriter->startElement('dimension');
        $objWriter->writeAttribute('ref', $pSheet->calculateWorksheetDimension());
        $objWriter->endElement();
    }

    /**
     * Write SheetViews.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     *
     * @throws WriterException
     */
    private function writeSheetViews(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // sheetViews
        $objWriter->startElement('sheetViews');

        // Sheet selected?
        $sheetSelected = false;
        if ($this->getParentWriter()->getSpreadsheet()->getIndex($pSheet) == $this->getParentWriter()->getSpreadsheet()->getActiveSheetIndex()) {
            $sheetSelected = true;
        }

        // sheetView
        $objWriter->startElement('sheetView');
        $objWriter->writeAttribute('tabSelected', $sheetSelected ? '1' : '0');
        $objWriter->writeAttribute('workbookViewId', '0');

        // Zoom scales
        if ($pSheet->getSheetView()->getZoomScale() != 100) {
            $objWriter->writeAttribute('zoomScale', $pSheet->getSheetView()->getZoomScale());
        }
        if ($pSheet->getSheetView()->getZoomScaleNormal() != 100) {
            $objWriter->writeAttribute('zoomScaleNormal', $pSheet->getSheetView()->getZoomScaleNormal());
        }

        // View Layout Type
        if ($pSheet->getSheetView()->getView() !== SheetView::SHEETVIEW_NORMAL) {
            $objWriter->writeAttribute('view', $pSheet->getSheetView()->getView());
        }

        // Gridlines
        if ($pSheet->getShowGridlines()) {
            $objWriter->writeAttribute('showGridLines', 'true');
        } else {
            $objWriter->writeAttribute('showGridLines', 'false');
        }

        // Row and column headers
        if ($pSheet->getShowRowColHeaders()) {
            $objWriter->writeAttribute('showRowColHeaders', '1');
        } else {
            $objWriter->writeAttribute('showRowColHeaders', '0');
        }

        // Right-to-left
        if ($pSheet->getRightToLeft()) {
            $objWriter->writeAttribute('rightToLeft', 'true');
        }

        $activeCell = $pSheet->getActiveCell();

        // Pane
        $pane = '';
        if ($pSheet->getFreezePane()) {
            list($xSplit, $ySplit) = Coordinate::coordinateFromString($pSheet->getFreezePane());
            $xSplit = Coordinate::columnIndexFromString($xSplit);
            --$xSplit;
            --$ySplit;

            $topLeftCell = $pSheet->getTopLeftCell();
            $activeCell = $topLeftCell;

            // pane
            $pane = 'topRight';
            $objWriter->startElement('pane');
            if ($xSplit > 0) {
                $objWriter->writeAttribute('xSplit', $xSplit);
            }
            if ($ySplit > 0) {
                $objWriter->writeAttribute('ySplit', $ySplit);
                $pane = ($xSplit > 0) ? 'bottomRight' : 'bottomLeft';
            }
            $objWriter->writeAttribute('topLeftCell', $topLeftCell);
            $objWriter->writeAttribute('activePane', $pane);
            $objWriter->writeAttribute('state', 'frozen');
            $objWriter->endElement();

            if (($xSplit > 0) && ($ySplit > 0)) {
                //    Write additional selections if more than two panes (ie both an X and a Y split)
                $objWriter->startElement('selection');
                $objWriter->writeAttribute('pane', 'topRight');
                $objWriter->endElement();
                $objWriter->startElement('selection');
                $objWriter->writeAttribute('pane', 'bottomLeft');
                $objWriter->endElement();
            }
        }

        // Selection
        // Only need to write selection element if we have a split pane
        // We cheat a little by over-riding the active cell selection, setting it to the split cell
        $objWriter->startElement('selection');
        if ($pane != '') {
            $objWriter->writeAttribute('pane', $pane);
        }
        $objWriter->writeAttribute('activeCell', $activeCell);
        $objWriter->writeAttribute('sqref', $activeCell);
        $objWriter->endElement();

        $objWriter->endElement();

        $objWriter->endElement();
    }

    /**
     * Write SheetFormatPr.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeSheetFormatPr(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // sheetFormatPr
        $objWriter->startElement('sheetFormatPr');

        // Default row height
        if ($pSheet->getDefaultRowDimension()->getRowHeight() >= 0) {
            $objWriter->writeAttribute('customHeight', 'true');
            $objWriter->writeAttribute('defaultRowHeight', StringHelper::formatNumber($pSheet->getDefaultRowDimension()->getRowHeight()));
        } else {
            $objWriter->writeAttribute('defaultRowHeight', '14.4');
        }

        // Set Zero Height row
        if ((string) $pSheet->getDefaultRowDimension()->getZeroHeight() == '1' ||
            strtolower((string) $pSheet->getDefaultRowDimension()->getZeroHeight()) == 'true') {
            $objWriter->writeAttribute('zeroHeight', '1');
        }

        // Default column width
        if ($pSheet->getDefaultColumnDimension()->getWidth() >= 0) {
            $objWriter->writeAttribute('defaultColWidth', StringHelper::formatNumber($pSheet->getDefaultColumnDimension()->getWidth()));
        }

        // Outline level - row
        $outlineLevelRow = 0;
        foreach ($pSheet->getRowDimensions() as $dimension) {
            if ($dimension->getOutlineLevel() > $outlineLevelRow) {
                $outlineLevelRow = $dimension->getOutlineLevel();
            }
        }
        $objWriter->writeAttribute('outlineLevelRow', (int) $outlineLevelRow);

        // Outline level - column
        $outlineLevelCol = 0;
        foreach ($pSheet->getColumnDimensions() as $dimension) {
            if ($dimension->getOutlineLevel() > $outlineLevelCol) {
                $outlineLevelCol = $dimension->getOutlineLevel();
            }
        }
        $objWriter->writeAttribute('outlineLevelCol', (int) $outlineLevelCol);

        $objWriter->endElement();
    }

    /**
     * Write Cols.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeCols(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // cols
        if (count($pSheet->getColumnDimensions()) > 0) {
            $objWriter->startElement('cols');

            $pSheet->calculateColumnWidths();

            // Loop through column dimensions
            foreach ($pSheet->getColumnDimensions() as $colDimension) {
                // col
                $objWriter->startElement('col');
                $objWriter->writeAttribute('min', Coordinate::columnIndexFromString($colDimension->getColumnIndex()));
                $objWriter->writeAttribute('max', Coordinate::columnIndexFromString($colDimension->getColumnIndex()));

                if ($colDimension->getWidth() < 0) {
                    // No width set, apply default of 10
                    $objWriter->writeAttribute('width', '9.10');
                } else {
                    // Width set
                    $objWriter->writeAttribute('width', StringHelper::formatNumber($colDimension->getWidth()));
                }

                // Column visibility
                if ($colDimension->getVisible() == false) {
                    $objWriter->writeAttribute('hidden', 'true');
                }

                // Auto size?
                if ($colDimension->getAutoSize()) {
                    $objWriter->writeAttribute('bestFit', 'true');
                }

                // Custom width?
                if ($colDimension->getWidth() != $pSheet->getDefaultColumnDimension()->getWidth()) {
                    $objWriter->writeAttribute('customWidth', 'true');
                }

                // Collapsed
                if ($colDimension->getCollapsed() == true) {
                    $objWriter->writeAttribute('collapsed', 'true');
                }

                // Outline level
                if ($colDimension->getOutlineLevel() > 0) {
                    $objWriter->writeAttribute('outlineLevel', $colDimension->getOutlineLevel());
                }

                // Style
                $objWriter->writeAttribute('style', $colDimension->getXfIndex());

                $objWriter->endElement();
            }

            $objWriter->endElement();
        }
    }

    /**
     * Write SheetProtection.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeSheetProtection(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // sheetProtection
        $objWriter->startElement('sheetProtection');

        if ($pSheet->getProtection()->getPassword() != '') {
            $objWriter->writeAttribute('password', $pSheet->getProtection()->getPassword());
        }

        $objWriter->writeAttribute('sheet', ($pSheet->getProtection()->getSheet() ? 'true' : 'false'));
        $objWriter->writeAttribute('objects', ($pSheet->getProtection()->getObjects() ? 'true' : 'false'));
        $objWriter->writeAttribute('scenarios', ($pSheet->getProtection()->getScenarios() ? 'true' : 'false'));
        $objWriter->writeAttribute('formatCells', ($pSheet->getProtection()->getFormatCells() ? 'true' : 'false'));
        $objWriter->writeAttribute('formatColumns', ($pSheet->getProtection()->getFormatColumns() ? 'true' : 'false'));
        $objWriter->writeAttribute('formatRows', ($pSheet->getProtection()->getFormatRows() ? 'true' : 'false'));
        $objWriter->writeAttribute('insertColumns', ($pSheet->getProtection()->getInsertColumns() ? 'true' : 'false'));
        $objWriter->writeAttribute('insertRows', ($pSheet->getProtection()->getInsertRows() ? 'true' : 'false'));
        $objWriter->writeAttribute('insertHyperlinks', ($pSheet->getProtection()->getInsertHyperlinks() ? 'true' : 'false'));
        $objWriter->writeAttribute('deleteColumns', ($pSheet->getProtection()->getDeleteColumns() ? 'true' : 'false'));
        $objWriter->writeAttribute('deleteRows', ($pSheet->getProtection()->getDeleteRows() ? 'true' : 'false'));
        $objWriter->writeAttribute('selectLockedCells', ($pSheet->getProtection()->getSelectLockedCells() ? 'true' : 'false'));
        $objWriter->writeAttribute('sort', ($pSheet->getProtection()->getSort() ? 'true' : 'false'));
        $objWriter->writeAttribute('autoFilter', ($pSheet->getProtection()->getAutoFilter() ? 'true' : 'false'));
        $objWriter->writeAttribute('pivotTables', ($pSheet->getProtection()->getPivotTables() ? 'true' : 'false'));
        $objWriter->writeAttribute('selectUnlockedCells', ($pSheet->getProtection()->getSelectUnlockedCells() ? 'true' : 'false'));
        $objWriter->endElement();
    }

    /**
     * Write ConditionalFormatting.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     *
     * @throws WriterException
     */
    private function writeConditionalFormatting(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // Conditional id
        $id = 1;

        // Loop through styles in the current worksheet
        foreach ($pSheet->getConditionalStylesCollection() as $cellCoordinate => $conditionalStyles) {
            foreach ($conditionalStyles as $conditional) {
                // WHY was this again?
                // if ($this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()) == '') {
                //    continue;
                // }
                if ($conditional->getConditionType() != Conditional::CONDITION_NONE) {
                    // conditionalFormatting
                    $objWriter->startElement('conditionalFormatting');
                    $objWriter->writeAttribute('sqref', $cellCoordinate);

                    // cfRule
                    $objWriter->startElement('cfRule');
                    $objWriter->writeAttribute('type', $conditional->getConditionType());
                    $objWriter->writeAttribute('dxfId', $this->getParentWriter()->getStylesConditionalHashTable()->getIndexForHashCode($conditional->getHashCode()));
                    $objWriter->writeAttribute('priority', $id++);

                    if (($conditional->getConditionType() == Conditional::CONDITION_CELLIS || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT)
                        && $conditional->getOperatorType() != Conditional::OPERATOR_NONE) {
                        $objWriter->writeAttribute('operator', $conditional->getOperatorType());
                    }

                    if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
                        && $conditional->getText() !== null) {
                        $objWriter->writeAttribute('text', $conditional->getText());
                    }

                    if ($conditional->getStopIfTrue()) {
                        $objWriter->writeAttribute('stopIfTrue', '1');
                    }

                    if ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
                        && $conditional->getOperatorType() == Conditional::OPERATOR_CONTAINSTEXT
                        && $conditional->getText() !== null) {
                        $objWriter->writeElement('formula', 'NOT(ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . ')))');
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
                        && $conditional->getOperatorType() == Conditional::OPERATOR_BEGINSWITH
                        && $conditional->getText() !== null) {
                        $objWriter->writeElement('formula', 'LEFT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"');
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
                        && $conditional->getOperatorType() == Conditional::OPERATOR_ENDSWITH
                        && $conditional->getText() !== null) {
                        $objWriter->writeElement('formula', 'RIGHT(' . $cellCoordinate . ',' . strlen($conditional->getText()) . ')="' . $conditional->getText() . '"');
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
                        && $conditional->getOperatorType() == Conditional::OPERATOR_NOTCONTAINS
                        && $conditional->getText() !== null) {
                        $objWriter->writeElement('formula', 'ISERROR(SEARCH("' . $conditional->getText() . '",' . $cellCoordinate . '))');
                    } elseif ($conditional->getConditionType() == Conditional::CONDITION_CELLIS
                        || $conditional->getConditionType() == Conditional::CONDITION_CONTAINSTEXT
                        || $conditional->getConditionType() == Conditional::CONDITION_EXPRESSION) {
                        foreach ($conditional->getConditions() as $formula) {
                            // Formula
                            $objWriter->writeElement('formula', $formula);
                        }
                    }

                    $objWriter->endElement();

                    $objWriter->endElement();
                }
            }
        }
    }

    /**
     * Write DataValidations.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeDataValidations(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // Datavalidation collection
        $dataValidationCollection = $pSheet->getDataValidationCollection();

        // Write data validations?
        if (!empty($dataValidationCollection)) {
            $dataValidationCollection = Coordinate::mergeRangesInCollection($dataValidationCollection);
            $objWriter->startElement('dataValidations');
            $objWriter->writeAttribute('count', count($dataValidationCollection));

            foreach ($dataValidationCollection as $coordinate => $dv) {
                $objWriter->startElement('dataValidation');

                if ($dv->getType() != '') {
                    $objWriter->writeAttribute('type', $dv->getType());
                }

                if ($dv->getErrorStyle() != '') {
                    $objWriter->writeAttribute('errorStyle', $dv->getErrorStyle());
                }

                if ($dv->getOperator() != '') {
                    $objWriter->writeAttribute('operator', $dv->getOperator());
                }

                $objWriter->writeAttribute('allowBlank', ($dv->getAllowBlank() ? '1' : '0'));
                $objWriter->writeAttribute('showDropDown', (!$dv->getShowDropDown() ? '1' : '0'));
                $objWriter->writeAttribute('showInputMessage', ($dv->getShowInputMessage() ? '1' : '0'));
                $objWriter->writeAttribute('showErrorMessage', ($dv->getShowErrorMessage() ? '1' : '0'));

                if ($dv->getErrorTitle() !== '') {
                    $objWriter->writeAttribute('errorTitle', $dv->getErrorTitle());
                }
                if ($dv->getError() !== '') {
                    $objWriter->writeAttribute('error', $dv->getError());
                }
                if ($dv->getPromptTitle() !== '') {
                    $objWriter->writeAttribute('promptTitle', $dv->getPromptTitle());
                }
                if ($dv->getPrompt() !== '') {
                    $objWriter->writeAttribute('prompt', $dv->getPrompt());
                }

                $objWriter->writeAttribute('sqref', $coordinate);

                if ($dv->getFormula1() !== '') {
                    $objWriter->writeElement('formula1', $dv->getFormula1());
                }
                if ($dv->getFormula2() !== '') {
                    $objWriter->writeElement('formula2', $dv->getFormula2());
                }

                $objWriter->endElement();
            }

            $objWriter->endElement();
        }
    }

    /**
     * Write Hyperlinks.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeHyperlinks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // Hyperlink collection
        $hyperlinkCollection = $pSheet->getHyperlinkCollection();

        // Relation ID
        $relationId = 1;

        // Write hyperlinks?
        if (!empty($hyperlinkCollection)) {
            $objWriter->startElement('hyperlinks');

            foreach ($hyperlinkCollection as $coordinate => $hyperlink) {
                $objWriter->startElement('hyperlink');

                $objWriter->writeAttribute('ref', $coordinate);
                if (!$hyperlink->isInternal()) {
                    $objWriter->writeAttribute('r:id', 'rId_hyperlink_' . $relationId);
                    ++$relationId;
                } else {
                    $objWriter->writeAttribute('location', str_replace('sheet://', '', $hyperlink->getUrl()));
                }

                if ($hyperlink->getTooltip() != '') {
                    $objWriter->writeAttribute('tooltip', $hyperlink->getTooltip());
                }

                $objWriter->endElement();
            }

            $objWriter->endElement();
        }
    }

    /**
     * Write ProtectedRanges.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeProtectedRanges(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        if (count($pSheet->getProtectedCells()) > 0) {
            // protectedRanges
            $objWriter->startElement('protectedRanges');

            // Loop protectedRanges
            foreach ($pSheet->getProtectedCells() as $protectedCell => $passwordHash) {
                // protectedRange
                $objWriter->startElement('protectedRange');
                $objWriter->writeAttribute('name', 'p' . md5($protectedCell));
                $objWriter->writeAttribute('sqref', $protectedCell);
                if (!empty($passwordHash)) {
                    $objWriter->writeAttribute('password', $passwordHash);
                }
                $objWriter->endElement();
            }

            $objWriter->endElement();
        }
    }

    /**
     * Write MergeCells.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeMergeCells(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        if (count($pSheet->getMergeCells()) > 0) {
            // mergeCells
            $objWriter->startElement('mergeCells');

            // Loop mergeCells
            foreach ($pSheet->getMergeCells() as $mergeCell) {
                // mergeCell
                $objWriter->startElement('mergeCell');
                $objWriter->writeAttribute('ref', $mergeCell);
                $objWriter->endElement();
            }

            $objWriter->endElement();
        }
    }

    /**
     * Write PrintOptions.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writePrintOptions(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // printOptions
        $objWriter->startElement('printOptions');

        $objWriter->writeAttribute('gridLines', ($pSheet->getPrintGridlines() ? 'true' : 'false'));
        $objWriter->writeAttribute('gridLinesSet', 'true');

        if ($pSheet->getPageSetup()->getHorizontalCentered()) {
            $objWriter->writeAttribute('horizontalCentered', 'true');
        }

        if ($pSheet->getPageSetup()->getVerticalCentered()) {
            $objWriter->writeAttribute('verticalCentered', 'true');
        }

        $objWriter->endElement();
    }

    /**
     * Write PageMargins.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writePageMargins(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // pageMargins
        $objWriter->startElement('pageMargins');
        $objWriter->writeAttribute('left', StringHelper::formatNumber($pSheet->getPageMargins()->getLeft()));
        $objWriter->writeAttribute('right', StringHelper::formatNumber($pSheet->getPageMargins()->getRight()));
        $objWriter->writeAttribute('top', StringHelper::formatNumber($pSheet->getPageMargins()->getTop()));
        $objWriter->writeAttribute('bottom', StringHelper::formatNumber($pSheet->getPageMargins()->getBottom()));
        $objWriter->writeAttribute('header', StringHelper::formatNumber($pSheet->getPageMargins()->getHeader()));
        $objWriter->writeAttribute('footer', StringHelper::formatNumber($pSheet->getPageMargins()->getFooter()));
        $objWriter->endElement();
    }

    /**
     * Write AutoFilter.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeAutoFilter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        $autoFilterRange = $pSheet->getAutoFilter()->getRange();
        if (!empty($autoFilterRange)) {
            // autoFilter
            $objWriter->startElement('autoFilter');

            // Strip any worksheet reference from the filter coordinates
            $range = Coordinate::splitRange($autoFilterRange);
            $range = $range[0];
            //    Strip any worksheet ref
            if (strpos($range[0], '!') !== false) {
                list($ws, $range[0]) = explode('!', $range[0]);
            }
            $range = implode(':', $range);

            $objWriter->writeAttribute('ref', str_replace('$', '', $range));

            $columns = $pSheet->getAutoFilter()->getColumns();
            if (count($columns) > 0) {
                foreach ($columns as $columnID => $column) {
                    $rules = $column->getRules();
                    if (count($rules) > 0) {
                        $objWriter->startElement('filterColumn');
                        $objWriter->writeAttribute('colId', $pSheet->getAutoFilter()->getColumnOffset($columnID));

                        $objWriter->startElement($column->getFilterType());
                        if ($column->getJoin() == Column::AUTOFILTER_COLUMN_JOIN_AND) {
                            $objWriter->writeAttribute('and', 1);
                        }

                        foreach ($rules as $rule) {
                            if (($column->getFilterType() === Column::AUTOFILTER_FILTERTYPE_FILTER) &&
                                ($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_EQUAL) &&
                                ($rule->getValue() === '')) {
                                //    Filter rule for Blanks
                                $objWriter->writeAttribute('blank', 1);
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER) {
                                //    Dynamic Filter Rule
                                $objWriter->writeAttribute('type', $rule->getGrouping());
                                $val = $column->getAttribute('val');
                                if ($val !== null) {
                                    $objWriter->writeAttribute('val', $val);
                                }
                                $maxVal = $column->getAttribute('maxVal');
                                if ($maxVal !== null) {
                                    $objWriter->writeAttribute('maxVal', $maxVal);
                                }
                            } elseif ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_TOPTENFILTER) {
                                //    Top 10 Filter Rule
                                $objWriter->writeAttribute('val', $rule->getValue());
                                $objWriter->writeAttribute('percent', (($rule->getOperator() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_PERCENT) ? '1' : '0'));
                                $objWriter->writeAttribute('top', (($rule->getGrouping() === Rule::AUTOFILTER_COLUMN_RULE_TOPTEN_TOP) ? '1' : '0'));
                            } else {
                                //    Filter, DateGroupItem or CustomFilter
                                $objWriter->startElement($rule->getRuleType());

                                if ($rule->getOperator() !== Rule::AUTOFILTER_COLUMN_RULE_EQUAL) {
                                    $objWriter->writeAttribute('operator', $rule->getOperator());
                                }
                                if ($rule->getRuleType() === Rule::AUTOFILTER_RULETYPE_DATEGROUP) {
                                    // Date Group filters
                                    foreach ($rule->getValue() as $key => $value) {
                                        if ($value > '') {
                                            $objWriter->writeAttribute($key, $value);
                                        }
                                    }
                                    $objWriter->writeAttribute('dateTimeGrouping', $rule->getGrouping());
                                } else {
                                    $objWriter->writeAttribute('val', $rule->getValue());
                                }

                                $objWriter->endElement();
                            }
                        }

                        $objWriter->endElement();

                        $objWriter->endElement();
                    }
                }
            }
            $objWriter->endElement();
        }
    }

    /**
     * Write PageSetup.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writePageSetup(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // pageSetup
        $objWriter->startElement('pageSetup');
        $objWriter->writeAttribute('paperSize', $pSheet->getPageSetup()->getPaperSize());
        $objWriter->writeAttribute('orientation', $pSheet->getPageSetup()->getOrientation());

        if ($pSheet->getPageSetup()->getScale() !== null) {
            $objWriter->writeAttribute('scale', $pSheet->getPageSetup()->getScale());
        }
        if ($pSheet->getPageSetup()->getFitToHeight() !== null) {
            $objWriter->writeAttribute('fitToHeight', $pSheet->getPageSetup()->getFitToHeight());
        } else {
            $objWriter->writeAttribute('fitToHeight', '0');
        }
        if ($pSheet->getPageSetup()->getFitToWidth() !== null) {
            $objWriter->writeAttribute('fitToWidth', $pSheet->getPageSetup()->getFitToWidth());
        } else {
            $objWriter->writeAttribute('fitToWidth', '0');
        }
        if ($pSheet->getPageSetup()->getFirstPageNumber() !== null) {
            $objWriter->writeAttribute('firstPageNumber', $pSheet->getPageSetup()->getFirstPageNumber());
            $objWriter->writeAttribute('useFirstPageNumber', '1');
        }

        $objWriter->endElement();
    }

    /**
     * Write Header / Footer.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeHeaderFooter(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // headerFooter
        $objWriter->startElement('headerFooter');
        $objWriter->writeAttribute('differentOddEven', ($pSheet->getHeaderFooter()->getDifferentOddEven() ? 'true' : 'false'));
        $objWriter->writeAttribute('differentFirst', ($pSheet->getHeaderFooter()->getDifferentFirst() ? 'true' : 'false'));
        $objWriter->writeAttribute('scaleWithDoc', ($pSheet->getHeaderFooter()->getScaleWithDocument() ? 'true' : 'false'));
        $objWriter->writeAttribute('alignWithMargins', ($pSheet->getHeaderFooter()->getAlignWithMargins() ? 'true' : 'false'));

        $objWriter->writeElement('oddHeader', $pSheet->getHeaderFooter()->getOddHeader());
        $objWriter->writeElement('oddFooter', $pSheet->getHeaderFooter()->getOddFooter());
        $objWriter->writeElement('evenHeader', $pSheet->getHeaderFooter()->getEvenHeader());
        $objWriter->writeElement('evenFooter', $pSheet->getHeaderFooter()->getEvenFooter());
        $objWriter->writeElement('firstHeader', $pSheet->getHeaderFooter()->getFirstHeader());
        $objWriter->writeElement('firstFooter', $pSheet->getHeaderFooter()->getFirstFooter());
        $objWriter->endElement();
    }

    /**
     * Write Breaks.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeBreaks(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // Get row and column breaks
        $aRowBreaks = [];
        $aColumnBreaks = [];
        foreach ($pSheet->getBreaks() as $cell => $breakType) {
            if ($breakType == PhpspreadsheetWorksheet::BREAK_ROW) {
                $aRowBreaks[] = $cell;
            } elseif ($breakType == PhpspreadsheetWorksheet::BREAK_COLUMN) {
                $aColumnBreaks[] = $cell;
            }
        }

        // rowBreaks
        if (!empty($aRowBreaks)) {
            $objWriter->startElement('rowBreaks');
            $objWriter->writeAttribute('count', count($aRowBreaks));
            $objWriter->writeAttribute('manualBreakCount', count($aRowBreaks));

            foreach ($aRowBreaks as $cell) {
                $coords = Coordinate::coordinateFromString($cell);

                $objWriter->startElement('brk');
                $objWriter->writeAttribute('id', $coords[1]);
                $objWriter->writeAttribute('man', '1');
                $objWriter->endElement();
            }

            $objWriter->endElement();
        }

        // Second, write column breaks
        if (!empty($aColumnBreaks)) {
            $objWriter->startElement('colBreaks');
            $objWriter->writeAttribute('count', count($aColumnBreaks));
            $objWriter->writeAttribute('manualBreakCount', count($aColumnBreaks));

            foreach ($aColumnBreaks as $cell) {
                $coords = Coordinate::coordinateFromString($cell);

                $objWriter->startElement('brk');
                $objWriter->writeAttribute('id', Coordinate::columnIndexFromString($coords[0]) - 1);
                $objWriter->writeAttribute('man', '1');
                $objWriter->endElement();
            }

            $objWriter->endElement();
        }
    }

    /**
     * Write SheetData.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     * @param string[] $pStringTable String table
     *
     * @throws WriterException
     */
    private function writeSheetData(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, array $pStringTable)
    {
        // Flipped stringtable, for faster index searching
        $aFlippedStringTable = $this->getParentWriter()->getWriterPart('stringtable')->flipStringTable($pStringTable);

        // sheetData
        $objWriter->startElement('sheetData');

        // Get column count
        $colCount = Coordinate::columnIndexFromString($pSheet->getHighestColumn());

        // Highest row number
        $highestRow = $pSheet->getHighestRow();

        // Loop through cells
        $cellsByRow = [];
        foreach ($pSheet->getCoordinates() as $coordinate) {
            $cellAddress = Coordinate::coordinateFromString($coordinate);
            $cellsByRow[$cellAddress[1]][] = $coordinate;
        }

        $currentRow = 0;
        while ($currentRow++ < $highestRow) {
            // Get row dimension
            $rowDimension = $pSheet->getRowDimension($currentRow);

            // Write current row?
            $writeCurrentRow = isset($cellsByRow[$currentRow]) || $rowDimension->getRowHeight() >= 0 || $rowDimension->getVisible() == false || $rowDimension->getCollapsed() == true || $rowDimension->getOutlineLevel() > 0 || $rowDimension->getXfIndex() !== null;

            if ($writeCurrentRow) {
                // Start a new row
                $objWriter->startElement('row');
                $objWriter->writeAttribute('r', $currentRow);
                $objWriter->writeAttribute('spans', '1:' . $colCount);

                // Row dimensions
                if ($rowDimension->getRowHeight() >= 0) {
                    $objWriter->writeAttribute('customHeight', '1');
                    $objWriter->writeAttribute('ht', StringHelper::formatNumber($rowDimension->getRowHeight()));
                }

                // Row visibility
                if ($rowDimension->getVisible() == false) {
                    $objWriter->writeAttribute('hidden', 'true');
                }

                // Collapsed
                if ($rowDimension->getCollapsed() == true) {
                    $objWriter->writeAttribute('collapsed', 'true');
                }

                // Outline level
                if ($rowDimension->getOutlineLevel() > 0) {
                    $objWriter->writeAttribute('outlineLevel', $rowDimension->getOutlineLevel());
                }

                // Style
                if ($rowDimension->getXfIndex() !== null) {
                    $objWriter->writeAttribute('s', $rowDimension->getXfIndex());
                    $objWriter->writeAttribute('customFormat', '1');
                }

                // Write cells
                if (isset($cellsByRow[$currentRow])) {
                    foreach ($cellsByRow[$currentRow] as $cellAddress) {
                        // Write cell
                        $this->writeCell($objWriter, $pSheet, $cellAddress, $aFlippedStringTable);
                    }
                }

                // End row
                $objWriter->endElement();
            }
        }

        $objWriter->endElement();
    }

    /**
     * Write Cell.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     * @param Cell $pCellAddress Cell Address
     * @param string[] $pFlippedStringTable String table (flipped), for faster index searching
     *
     * @throws WriterException
     */
    private function writeCell(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet, $pCellAddress, array $pFlippedStringTable)
    {
        // Cell
        $pCell = $pSheet->getCell($pCellAddress);
        $objWriter->startElement('c');
        $objWriter->writeAttribute('r', $pCellAddress);

        // Sheet styles
        if ($pCell->getXfIndex() != '') {
            $objWriter->writeAttribute('s', $pCell->getXfIndex());
        }

        // If cell value is supplied, write cell value
        $cellValue = $pCell->getValue();
        if (is_object($cellValue) || $cellValue !== '') {
            // Map type
            $mappedType = $pCell->getDataType();

            // Write data type depending on its type
            switch (strtolower($mappedType)) {
                case 'inlinestr':    // Inline string
                case 's':            // String
                case 'b':            // Boolean
                    $objWriter->writeAttribute('t', $mappedType);

                    break;
                case 'f':            // Formula
                    $calculatedValue = ($this->getParentWriter()->getPreCalculateFormulas()) ?
                        $pCell->getCalculatedValue() : $cellValue;
                    if (is_string($calculatedValue)) {
                        $objWriter->writeAttribute('t', 'str');
                    } elseif (is_bool($calculatedValue)) {
                        $objWriter->writeAttribute('t', 'b');
                    }

                    break;
                case 'e':            // Error
                    $objWriter->writeAttribute('t', $mappedType);
            }

            // Write data depending on its type
            switch (strtolower($mappedType)) {
                case 'inlinestr':    // Inline string
                    if (!$cellValue instanceof RichText) {
                        $objWriter->writeElement('t', StringHelper::controlCharacterPHP2OOXML(htmlspecialchars($cellValue)));
                    } elseif ($cellValue instanceof RichText) {
                        $objWriter->startElement('is');
                        $this->getParentWriter()->getWriterPart('stringtable')->writeRichText($objWriter, $cellValue);
                        $objWriter->endElement();
                    }

                    break;
                case 's':            // String
                    if (!$cellValue instanceof RichText) {
                        if (isset($pFlippedStringTable[$cellValue])) {
                            $objWriter->writeElement('v', $pFlippedStringTable[$cellValue]);
                        }
                    } elseif ($cellValue instanceof RichText) {
                        $objWriter->writeElement('v', $pFlippedStringTable[$cellValue->getHashCode()]);
                    }

                    break;
                case 'f':            // Formula
                    $attributes = $pCell->getFormulaAttributes();
                    if ($attributes['t'] == 'array') {
                        $objWriter->startElement('f');
                        $objWriter->writeAttribute('t', 'array');
                        $objWriter->writeAttribute('ref', $pCellAddress);
                        $objWriter->writeAttribute('aca', '1');
                        $objWriter->writeAttribute('ca', '1');
                        $objWriter->text(substr($cellValue, 1));
                        $objWriter->endElement();
                    } else {
                        $objWriter->writeElement('f', substr($cellValue, 1));
                    }
                    if ($this->getParentWriter()->getOffice2003Compatibility() === false) {
                        if ($this->getParentWriter()->getPreCalculateFormulas()) {
                            if (!is_array($calculatedValue) && substr($calculatedValue, 0, 1) != '#') {
                                $objWriter->writeElement('v', StringHelper::formatNumber($calculatedValue));
                            } else {
                                $objWriter->writeElement('v', '0');
                            }
                        } else {
                            $objWriter->writeElement('v', '0');
                        }
                    }

                    break;
                case 'n':            // Numeric
                    // force point as decimal separator in case current locale uses comma
                    $objWriter->writeElement('v', str_replace(',', '.', $cellValue));

                    break;
                case 'b':            // Boolean
                    $objWriter->writeElement('v', ($cellValue ? '1' : '0'));

                    break;
                case 'e':            // Error
                    if (substr($cellValue, 0, 1) == '=') {
                        $objWriter->writeElement('f', substr($cellValue, 1));
                        $objWriter->writeElement('v', substr($cellValue, 1));
                    } else {
                        $objWriter->writeElement('v', $cellValue);
                    }

                    break;
            }
        }

        $objWriter->endElement();
    }

    /**
     * Write Drawings.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     * @param bool $includeCharts Flag indicating if we should include drawing details for charts
     */
    private function writeDrawings(XMLWriter $objWriter = null, PhpspreadsheetWorksheet $pSheet = null, $includeCharts = false)
    {
        $chartCount = ($includeCharts) ? $pSheet->getChartCollection()->count() : 0;
        // If sheet contains drawings, add the relationships
        if (($pSheet->getDrawingCollection()->count() > 0) ||
            ($chartCount > 0)) {
            $objWriter->startElement('drawing');
            $objWriter->writeAttribute('r:id', 'rId1');
            $objWriter->endElement();
        }
    }

    /**
     * Write LegacyDrawing.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeLegacyDrawing(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // If sheet contains comments, add the relationships
        if (count($pSheet->getComments()) > 0) {
            $objWriter->startElement('legacyDrawing');
            $objWriter->writeAttribute('r:id', 'rId_comments_vml1');
            $objWriter->endElement();
        }
    }

    /**
     * Write LegacyDrawingHF.
     *
     * @param XMLWriter $objWriter XML Writer
     * @param PhpspreadsheetWorksheet $pSheet Worksheet
     */
    private function writeLegacyDrawingHF(XMLWriter $objWriter, PhpspreadsheetWorksheet $pSheet)
    {
        // If sheet contains images, add the relationships
        if (count($pSheet->getHeaderFooter()->getImages()) > 0) {
            $objWriter->startElement('legacyDrawingHF');
            $objWriter->writeAttribute('r:id', 'rId_headerfooter_vml1');
            $objWriter->endElement();
        }
    }
}


<?php

namespace XQueue\Maileon\API\XML;

/**
 * Utility class for XML elements
 *
 * @author Felix Heinrichs | Trusted Mails GmbH | felix.heinrichs@trusted-mails.com
 * @author Marcus Ständer | Trusted Mails GmbH | marcus.staender@trusted-mails.com
 */
abstract class XMLUtils
{

    /**
     * This function appends one SimpleXMLElement to another one as addChild does not support deep copies
     * @param \SimpleXMLElement $to
     * @param \SimpleXMLElement $from
     */
    static function appendChild(SimpleXMLElement $to, SimpleXMLElement $from)
    {
        $toDom = dom_import_simplexml($to);
        $fromDom = dom_import_simplexml($from);
        $toDom->appendChild($toDom->ownerDocument->importNode($fromDom, true));
    }

    /**
     * Adds a child with $value inside CDATA
     * @param unknown $name
     * @param unknown $value
     */
    static public function addChildAsCDATA($parent, $name, $value = NULL)
    {
        $new_child = $parent->addChild($name);

        if ($new_child !== NULL) {
            $node = dom_import_simplexml($new_child);
            $no = $node->ownerDocument;
            $node->appendChild($no->createCDATASection($value));
        }

        return $new_child;
    }
}