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 .
'!' );
90 $document =
new DOMDocument();
92 $oldLibXmlErrors = libxml_use_internal_errors(
true );
94 $oldDisable = @libxml_disable_entity_loader(
true );
95 $ok = $document->loadXML( $xml, LIBXML_NONET );
98 $errors = libxml_get_errors();
99 libxml_use_internal_errors( $oldLibXmlErrors );
101 @libxml_disable_entity_loader( $oldDisable );
103 foreach ( $errors as $error ) {
105 throw new InvalidArgumentException(
106 'Malformed XML: ' . $error->message .
' in line ' . $error->line
110 throw new InvalidArgumentException(
'Malformed XML!' );
113 libxml_use_internal_errors( $oldLibXmlErrors );
115 @libxml_disable_entity_loader( $oldDisable );
116 $sites = $this->makeSiteList( $document->documentElement );
117 $this->store->saveSites( $sites );
125 private function makeSiteList( DOMElement $root ) {
130 $oldSites = $this->store->getSites();
132 $current = $root->firstChild;
134 if ( $current instanceof DOMElement && $current->tagName ===
'site' ) {
136 $site = $this->
makeSite( $current );
137 $key = $site->getGlobalId();
139 if ( $oldSites->hasSite( $key ) ) {
140 $oldSite = $oldSites->getSite( $key );
141 $site->setInternalId( $oldSite->getInternalId() );
144 $sites[$key] = $site;
145 }
catch ( TimeoutException $e ) {
147 }
catch ( Exception $ex ) {
148 $this->handleException( $ex );
152 $current = $current->nextSibling;
163 public function makeSite( DOMElement $siteElement ) {
164 if ( $siteElement->tagName !==
'site' ) {
165 throw new InvalidArgumentException(
'Expected <site> tag, found ' . $siteElement->tagName );
171 $site->setForward( $this->hasChild( $siteElement,
'forward' ) );
172 $site->setGlobalId( $this->getChildText( $siteElement,
'globalid' ) );
173 $site->setGroup( $this->getChildText( $siteElement,
'group',
Site::GROUP_NONE ) );
174 $site->setSource( $this->getChildText( $siteElement,
'source',
Site::SOURCE_LOCAL ) );
176 $pathTags = $siteElement->getElementsByTagName(
'path' );
177 for ( $i = 0; $i < $pathTags->length; $i++ ) {
178 $pathElement = $pathTags->item( $i );
179 '@phan-var DOMElement $pathElement';
180 $pathType = $this->getAttributeValue( $pathElement,
'type' );
181 $path = $pathElement->textContent;
183 $site->setPath( $pathType,
$path );
186 $idTags = $siteElement->getElementsByTagName(
'localid' );
187 for ( $i = 0; $i < $idTags->length; $i++ ) {
188 $idElement = $idTags->item( $i );
189 '@phan-var DOMElement $idElement';
190 $idType = $this->getAttributeValue( $idElement,
'type' );
191 $id = $idElement->textContent;
193 $site->addLocalId( $idType, $id );
209 private function getAttributeValue( DOMElement $element, $name, $default =
false ) {
210 $node = $element->getAttributeNode( $name );
213 if ( $default !==
false ) {
216 throw new RuntimeException(
217 'Required ' . $name .
' attribute not found in <' . $element->tagName .
'> tag'
222 return $node->textContent;
232 private function getChildText( DOMElement $element, $name, $default =
false ) {
233 $elements = $element->getElementsByTagName( $name );
235 if ( $elements->length < 1 ) {
236 if ( $default !==
false ) {
239 throw new RuntimeException(
240 'Required <' . $name .
'> tag not found inside <' . $element->tagName .
'> tag'
245 $node = $elements->item( 0 );
246 return $node->textContent;
255 private function hasChild( DOMElement $element, $name ) {
256 return $this->getChildText( $element, $name,
null ) !==
null;
262 private function handleException( Exception $ex ) {
263 if ( $this->exceptionCallback ) {
264 call_user_func( $this->exceptionCallback, $ex );