/** * @param $root Response root element. * * @throws OLAPException */ private function createMetaData(DOMElement $root) { $olapInfo = XMLAUtil::findChild($root, XMLAUtil::MDDATASET_NS, "OlapInfo"); $cubeInfo = XMLAUtil::findChild($olapInfo, XMLAUtil::MDDATASET_NS, "CubeInfo"); $cubeNode = XMLAUtil::findChild($cubeInfo, XMLAUtil::MDDATASET_NS, "Cube"); $cubeNameNode = XMLAUtil::findChild($cubeNode, XMLAUtil::MDDATASET_NS, "CubeName"); $cubeName = XMLAUtil::gatherText($cubeNameNode); // REVIEW: If there are multiple cubes with the same name, we should // qualify by catalog and schema. Currently we just take the first. $cube = $this->lookupCube($this->statement->getConnection()->getMetadata(), $cubeName); if ($cube == null) { throw new OLAPException("Internal error: cube '{$cubeName}' not found."); } // REVIEW: We should not modify the connection. It is not safe, because // connection might be shared between multiple statements with different // cubes. Caller should call // // connection.setCatalog( // cellSet.getMetaData().getCube().getSchema().getCatalog().getName()) // // before doing metadata queries. $this->statement->getConnection()->setCatalog($cube->getSchema()->getCatalog()->getName()); $axesInfo = XMLAUtil::findChild($olapInfo, XMLAUtil::MDDATASET_NS, "AxesInfo"); $axisInfos = XMLAUtil::findChildren($axesInfo, XMLAUtil::MDDATASET_NS, "AxisInfo"); $axisMetaDataList = array(); $filterAxisMetaData = null; foreach ($axisInfos as $axisInfo) { $axisName = $axisInfo->getAttribute('name'); $axis = $this->lookupAxis($axisName); $hierarchyInfos = XMLAUtil::findChildren($axisInfo, XMLAUtil::MDDATASET_NS, 'HierarchyInfo'); $hierarchyList = array(); /* <OlapInfo> <AxesInfo> <AxisInfo name="Axis0"> <HierarchyInfo name="Customers"> <UName name="[Customers].[MEMBER_UNIQUE_NAME]"/> <Caption name="[Customers].[MEMBER_CAPTION]"/> <LName name="[Customers].[LEVEL_UNIQUE_NAME]"/> <LNum name="[Customers].[LEVEL_NUMBER]"/> <DisplayInfo name="[Customers].[DISPLAY_INFO]"/> </HierarchyInfo> </AxisInfo> ... </AxesInfo> <CellInfo> <Value name="VALUE"/> <FmtValue name="FORMATTED_VALUE"/> <FormatString name="FORMAT_STRING"/> </CellInfo> </OlapInfo> */ $propertyList = array(); foreach ($hierarchyInfos as $hierarchyInfo) { $hierarchyName = $hierarchyInfo->getAttribute('name'); $hierarchy = $this->lookupHierarchy($cube, $hierarchyName); $hierarchyList[] = $hierarchy; foreach (XMLAUtil::childElements($hierarchyInfo) as $childNode) { $tag = $childNode->localName; if (in_array($tag, self::$standardProperties)) { continue; } $propertyUniqueName = $childNode->getAttribute('name'); $property = new XMLACellSetMemberProperty($propertyUniqueName, $hierarchy, $tag); $propertyList[] = $property; } } $axisMetaData = new XMLACellSetAxisMetaData($this->statement->getConnection(), $axis, $hierarchyList, $propertyList); if ($axis->isFilter()) { $filterAxisMetaData = $axisMetaData; } else { $axisMetaDataList[] = $axisMetaData; } } if ($filterAxisMetaData == null) { $filterAxisMetaData = new XMLACellSetAxisMetaData($this->statement->getConnection(), Axis::getEnum(Axis::FILTER), array(), array()); } $cellInfo = XMLAUtil::findChild($olapInfo, XMLAUtil::MDDATASET_NS, 'CellInfo'); $cellProperties = array(); foreach (XMLAUtil::childElements($cellInfo) as $element) { $cellProperties[] = new XMLACellProperty($element->localName, $element->getAttribute('name')); } return new XMLACellSetMetaData($this->statement, $cube, $filterAxisMetaData, $axisMetaDataList, $cellProperties); }
/** * Executes an XMLA metadata request and returns the root element of the * response. * * @param $request XMLA request string * * @return DOMElement Root element of the response * @throws OLAPException on error */ public function executeMetadataRequest($request, $cachable = true) { // check the cache for data before executing the meta data request $requestHash = crc32($request); if (array_key_exists($requestHash, $this->localCache)) { return $this->localCache[$requestHash]; } else { if ($cachable && $this->cache != null && ($cachedResponseXML = $this->cache->get($requestHash)) != false) { if ($this->logger && $this->debug) { $this->logger->debug(__CLASS__, '********************** Cache hit **********************'); } $doc = new \DOMDocument(); $doc->loadXML($cachedResponseXML); } else { if ($this->logger && $this->debug) { $this->logger->debug(__CLASS__, '********************** SENDING REQUEST **********************'); $this->logger->debug(__CLASS__, $request); } $doc = $this->sendXMLA($request); if ($this->logger && $this->debug) { $this->logger->debug(__CLASS__, '******* RECEIVED RESPONSE *******'); $this->logger->debug(__CLASS__, $doc->saveXML()); } $cachableXML = $doc->saveXML(); if ($cachable && $this->cache != null) { $this->cache->set($requestHash, $cachableXML); } } } // <SOAP-ENV:Envelope> // <SOAP-ENV:Header/> // <SOAP-ENV:Body> // <xmla:DiscoverResponse> // <xmla:return> // <root> // (see below) // </root> // <xmla:return> // </xmla:DiscoverResponse> // </SOAP-ENV:Body> // </SOAP-ENV:Envelope> $envelope = $doc->documentElement; //if (DEBUG) { // System.out.println("** SERVER RESPONSE :"); // System.out.println(XmlaOlap4jUtil.toString(doc, true)); //} assert($envelope->localName == 'Envelope'); assert($envelope->namespaceURI == XMLAUtil::SOAP_NS); $body = XMLAUtil::findChild($envelope, XMLAUtil::SOAP_NS, 'Body'); $fault = XMLAUtil::findChild($body, XMLAUtil::SOAP_NS, 'Fault'); if ($fault != null) { // had an error, need to invalidate the cached item so we don't end up // caching invalid data if ($cachable && $this->cache != null) { $this->cache->delete($requestHash); } /* <SOAP-ENV:Fault> <faultcode>SOAP-ENV:Client.00HSBC01</faultcode> <faultstring>XMLA connection datasource not found</faultstring> <faultactor>Mondrian</faultactor> <detail> <XA:error xmlns:XA="http://mondrian.sourceforge.net"> <code>00HSBC01</code> <desc>The Mondrian XML: Mondrian Error:Internal error: no catalog named 'LOCALDB'</desc> </XA:error> </detail> </SOAP-ENV:Fault> */ // TODO: log doc to logfile $fault = $fault->ownerDocument->saveXML($fault); //$request = $request->ownerDocument->saveXML ( $request ); throw new OLAPException('XMLA provider gave exception: ' . $fault . ' Request [' . $request . ']'); //throw getHelper().createException( // "XMLA provider gave exception: " // + XmlaOlap4jUtil.prettyPrint(fault) // + "\n" // + "Request was:\n" // + request); } $discoverResponse = XMLAUtil::findChild($body, XMLAUtil::XMLA_NS, 'DiscoverResponse'); $returnElement = XMLAUtil::findChild($discoverResponse, XMLAUtil::XMLA_NS, 'return'); $rootElement = XMLAUtil::findChild($returnElement, XMLAUtil::ROWSET_NS, 'root'); // cache this element locally for future retrieval $this->localCache[$requestHash] = $rootElement; return $rootElement; }