See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 39 and 401]
1 <?php 2 3 namespace Box\Spout\Reader\XLSX\Manager; 4 5 use Box\Spout\Common\Exception\IOException; 6 use Box\Spout\Reader\Wrapper\XMLReader; 7 use Box\Spout\Reader\XLSX\Creator\InternalEntityFactory; 8 9 /** 10 * Class WorkbookRelationshipsManager 11 * This class manages the workbook relationships defined in the associated XML file 12 */ 13 class WorkbookRelationshipsManager 14 { 15 const BASE_PATH = 'xl/'; 16 17 /** Path of workbook relationships XML file inside the XLSX file */ 18 const WORKBOOK_RELS_XML_FILE_PATH = 'xl/_rels/workbook.xml.rels'; 19 20 /** Relationships types - For Transitional and Strict OOXML */ 21 const RELATIONSHIP_TYPE_SHARED_STRINGS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings'; 22 const RELATIONSHIP_TYPE_STYLES = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles'; 23 const RELATIONSHIP_TYPE_SHARED_STRINGS_STRICT = 'http://purl.oclc.org/ooxml/officeDocument/relationships/sharedStrings'; 24 const RELATIONSHIP_TYPE_STYLES_STRICT = 'http://purl.oclc.org/ooxml/officeDocument/relationships/styles'; 25 26 /** Nodes and attributes used to find relevant information in the workbook relationships XML file */ 27 const XML_NODE_RELATIONSHIP = 'Relationship'; 28 const XML_ATTRIBUTE_TYPE = 'Type'; 29 const XML_ATTRIBUTE_TARGET = 'Target'; 30 31 /** @var string Path of the XLSX file being read */ 32 private $filePath; 33 34 /** @var InternalEntityFactory Factory to create entities */ 35 private $entityFactory; 36 37 /** @var array Cache of the already read workbook relationships: [TYPE] => [FILE_NAME] */ 38 private $cachedWorkbookRelationships; 39 40 /** 41 * @param string $filePath Path of the XLSX file being read 42 * @param InternalEntityFactory $entityFactory Factory to create entities 43 */ 44 public function __construct($filePath, $entityFactory) 45 { 46 $this->filePath = $filePath; 47 $this->entityFactory = $entityFactory; 48 } 49 50 /** 51 * @return string The path of the shared string XML file 52 */ 53 public function getSharedStringsXMLFilePath() 54 { 55 $workbookRelationships = $this->getWorkbookRelationships(); 56 $sharedStringsXMLFilePath = $workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS] 57 ?? $workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS_STRICT]; 58 59 // the file path can be relative (e.g. "styles.xml") or absolute (e.g. "/xl/styles.xml") 60 $doesContainBasePath = (\strpos($sharedStringsXMLFilePath, self::BASE_PATH) !== false); 61 if (!$doesContainBasePath) { 62 // make sure we return an absolute file path 63 $sharedStringsXMLFilePath = self::BASE_PATH . $sharedStringsXMLFilePath; 64 } 65 66 return $sharedStringsXMLFilePath; 67 } 68 69 /** 70 * @return bool Whether the XLSX file contains a shared string XML file 71 */ 72 public function hasSharedStringsXMLFile() 73 { 74 $workbookRelationships = $this->getWorkbookRelationships(); 75 76 return isset($workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS]) 77 || isset($workbookRelationships[self::RELATIONSHIP_TYPE_SHARED_STRINGS_STRICT]); 78 } 79 80 /** 81 * @return bool Whether the XLSX file contains a styles XML file 82 */ 83 public function hasStylesXMLFile() 84 { 85 $workbookRelationships = $this->getWorkbookRelationships(); 86 87 return isset($workbookRelationships[self::RELATIONSHIP_TYPE_STYLES]) 88 || isset($workbookRelationships[self::RELATIONSHIP_TYPE_STYLES_STRICT]); 89 } 90 91 /** 92 * @return string The path of the styles XML file 93 */ 94 public function getStylesXMLFilePath() 95 { 96 $workbookRelationships = $this->getWorkbookRelationships(); 97 $stylesXMLFilePath = $workbookRelationships[self::RELATIONSHIP_TYPE_STYLES] 98 ?? $workbookRelationships[self::RELATIONSHIP_TYPE_STYLES_STRICT]; 99 100 // the file path can be relative (e.g. "styles.xml") or absolute (e.g. "/xl/styles.xml") 101 $doesContainBasePath = (\strpos($stylesXMLFilePath, self::BASE_PATH) !== false); 102 if (!$doesContainBasePath) { 103 // make sure we return a full path 104 $stylesXMLFilePath = self::BASE_PATH . $stylesXMLFilePath; 105 } 106 107 return $stylesXMLFilePath; 108 } 109 110 /** 111 * Reads the workbook.xml.rels and extracts the filename associated to the different types. 112 * It caches the result so that the file is read only once. 113 * 114 * @throws \Box\Spout\Common\Exception\IOException If workbook.xml.rels can't be read 115 * @return array 116 */ 117 private function getWorkbookRelationships() 118 { 119 if (!isset($this->cachedWorkbookRelationships)) { 120 $xmlReader = $this->entityFactory->createXMLReader(); 121 122 if ($xmlReader->openFileInZip($this->filePath, self::WORKBOOK_RELS_XML_FILE_PATH) === false) { 123 throw new IOException('Could not open "' . self::WORKBOOK_RELS_XML_FILE_PATH . '".'); 124 } 125 126 $this->cachedWorkbookRelationships = []; 127 128 while ($xmlReader->readUntilNodeFound(self::XML_NODE_RELATIONSHIP)) { 129 $this->processWorkbookRelationship($xmlReader); 130 } 131 } 132 133 return $this->cachedWorkbookRelationships; 134 } 135 136 /** 137 * Extracts and store the data of the current workbook relationship. 138 * 139 * @param XMLReader $xmlReader 140 * @return void 141 */ 142 private function processWorkbookRelationship($xmlReader) 143 { 144 $type = $xmlReader->getAttribute(self::XML_ATTRIBUTE_TYPE); 145 $target = $xmlReader->getAttribute(self::XML_ATTRIBUTE_TARGET); 146 147 // @NOTE: if a type is defined more than once, we overwrite the previous value 148 // To be changed if we want to get the file paths of sheet XML files for instance. 149 $this->cachedWorkbookRelationships[$type] = $target; 150 } 151 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body