49 private $exceptionCallback;
55 $this->store = $store;
62 return $this->exceptionCallback;
69 $this->exceptionCallback = $exceptionCallback;
76 $xml = file_get_contents( $file );
78 if ( $xml ===
false ) {
79 throw new RuntimeException(
'Failed to read ' . $file .
'!' );
91 $document =
new DOMDocument();
93 $oldLibXmlErrors = libxml_use_internal_errors(
true );
95 $oldDisable = @libxml_disable_entity_loader(
true );
96 $ok = $document->loadXML( $xml, LIBXML_NONET );
99 $errors = libxml_get_errors();
100 libxml_use_internal_errors( $oldLibXmlErrors );
102 @libxml_disable_entity_loader( $oldDisable );
104 foreach ( $errors as $error ) {
106 throw new InvalidArgumentException(
107 'Malformed XML: ' . $error->message .
' in line ' . $error->line
111 throw new InvalidArgumentException(
'Malformed XML!' );
114 libxml_use_internal_errors( $oldLibXmlErrors );
116 @libxml_disable_entity_loader( $oldDisable );
117 $sites = $this->makeSiteList( $document->documentElement );
118 $this->store->saveSites( $sites );
126 private function makeSiteList( DOMElement $root ) {
131 $oldSites = $this->store->getSites();
133 $current = $root->firstChild;
135 if ( $current instanceof DOMElement && $current->tagName ===
'site' ) {
137 $site = $this->
makeSite( $current );
138 $key = $site->getGlobalId();
140 if ( $oldSites->hasSite( $key ) ) {
141 $oldSite = $oldSites->getSite( $key );
142 $site->setInternalId( $oldSite->getInternalId() );
145 $sites[$key] = $site;
146 }
catch ( TimeoutException $e ) {
148 }
catch ( Exception $ex ) {
149 $this->handleException( $ex );
153 $current = $current->nextSibling;
164 public function makeSite( DOMElement $siteElement ) {
165 if ( $siteElement->tagName !==
'site' ) {
166 throw new InvalidArgumentException(
'Expected <site> tag, found ' . $siteElement->tagName );
172 $site->setForward( $this->hasChild( $siteElement,
'forward' ) );
173 $site->setGlobalId( $this->getChildText( $siteElement,
'globalid' ) );
174 $site->setGroup( $this->getChildText( $siteElement,
'group',
Site::GROUP_NONE ) );
175 $site->setSource( $this->getChildText( $siteElement,
'source',
Site::SOURCE_LOCAL ) );
177 $pathTags = $siteElement->getElementsByTagName(
'path' );
178 for ( $i = 0; $i < $pathTags->length; $i++ ) {
179 $pathElement = $pathTags->item( $i );
180 '@phan-var DOMElement $pathElement';
181 $pathType = $this->getAttributeValue( $pathElement,
'type' );
182 $path = $pathElement->textContent;
184 $site->setPath( $pathType,
$path );
187 $idTags = $siteElement->getElementsByTagName(
'localid' );
188 for ( $i = 0; $i < $idTags->length; $i++ ) {
189 $idElement = $idTags->item( $i );
190 '@phan-var DOMElement $idElement';
191 $idType = $this->getAttributeValue( $idElement,
'type' );
192 $id = $idElement->textContent;
194 $site->addLocalId( $idType, $id );
210 private function getAttributeValue( DOMElement $element, $name, $default =
false ) {
211 $node = $element->getAttributeNode( $name );
214 if ( $default !==
false ) {
217 throw new RuntimeException(
218 'Required ' . $name .
' attribute not found in <' . $element->tagName .
'> tag'
223 return $node->textContent;
233 private function getChildText( DOMElement $element, $name, $default =
false ) {
234 $elements = $element->getElementsByTagName( $name );
236 if ( $elements->length < 1 ) {
237 if ( $default !==
false ) {
240 throw new RuntimeException(
241 'Required <' . $name .
'> tag not found inside <' . $element->tagName .
'> tag'
246 $node = $elements->item( 0 );
247 return $node->textContent;
256 private function hasChild( DOMElement $element, $name ) {
257 return $this->getChildText( $element, $name,
null ) !==
null;
263 private function handleException( Exception $ex ) {
264 if ( $this->exceptionCallback ) {
265 call_user_func( $this->exceptionCallback, $ex );