specials/SpecialRDFImport.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

class RDFImport extends RDFIOSpecialPage {

    function __construct() {
        parent::__construct( 'RDFImport', 'rdfio-import' );
    }

    /**
     * The main code goes here
     * @param string $par (unused)
     */
    function execute( $par ) {
        unset( $par ); // Needed to suppress warning about unused variable which we include just for consistency.

        // Require rdfio-import permission for the current user
        if ( !$this->userCanExecute( $this->getUser() ) ) {
            throw new PermissionsError( 'rdfio-import', array( 'rdfio-specialpage-access-permission-missing' ) );
        }

        $wOut = $this->getOutput();

        // Set HTML headers sent to the browser
        $this->setHeaders();

        // The main code
        $requestData = $this->getRequestData();
        if ( $requestData->action === 'import' ) {
            if ( !$requestData->hasWriteAccess ) {
                $this->errorMsg( "The current user does not have write access in the wiki" );
                return;
            }

            try {
                $importInfo = $this->importData( $requestData );
                $triples = $importInfo['triples'];
                if ( $triples ) {
                    $this->showHTMLFormAndInfo( $requestData );

                    $this->successMsg('Successfully imported ' . count( $triples ) . ' triples!' );

                    // Show imported triples
                    $rdfImporter = new RDFIORDFImporter();
                    $wOut->addHTML( $rdfImporter->showImportedTriples( $triples ) );

                    if ( $requestData->externalRdfUrl ) {
                        $rdfImporter->addDataSource( $requestData->externalRdfUrl, 'RDF' );
                    }
                    return;

                } else if ( !$triples ) {
                    $this->errorMsg( 'No new triples to import, in in-data' );
                }
            } catch ( MWException $e ) {
                $this->errorMsg( $e->getMessage() );
            }
        }
        $this->showHTMLFormAndInfo( $requestData );
    }

    /**
     * Import data into wiki pages
     */
    function importData( RDFIORequestData $requestData ) {
        $rdfImporter = new RDFIORDFImporter();
        if ( $requestData->importSource === 'url' ) {
            if ( $requestData->externalRdfUrl === '' ) {
                throw new RDFIOException( 'URL field is empty!' );
            } else if ( substr( $requestData->externalRdfUrl, 0, 4 ) !== 'http' ) {
                throw new RDFIOException( 'Invalid URL provided!' );
            }
            $rdfData = file_get_contents( $requestData->externalRdfUrl );
        } else if ( $requestData->importSource === 'textfield' ) {
            if ( $requestData->importData === '' )
                throw new RDFIOException( 'RDF field is empty!' );
            $rdfData = $requestData->importData;
        } else {
            throw new RDFIOException( 'Import source is not selected!' );
        }

        switch ( $requestData->dataFormat ) {
            case 'rdfxml':
                $importInfo = $rdfImporter->importRdfXml( $rdfData );
                $triples = $importInfo['triples'];
                break;
            case 'turtle':
                $importInfo = $rdfImporter->importTurtle( $rdfData );
                $triples = $importInfo['triples'];
                break;
        }

        $output = array( 'triples' => $triples );
        return $output;
    }

    /**
     * Get data from the request object and store it in class variables
     */
    function getRequestData() {
        global $wgRequest, $wgArticlePath;

        $requestData = new RDFIORequestData();
        $requestData->action = $wgRequest->getText( 'action' );
        $requestData->editToken = $wgRequest->getText( 'token' );
        $requestData->importSource = $wgRequest->getText( 'importsrc' );
        $requestData->externalRdfUrl = $wgRequest->getText( 'extrdfurl' );
        $requestData->importData = $wgRequest->getText( 'importdata' );
        $requestData->dataFormat = $wgRequest->getText( 'dataformat' );
        $requestData->hasWriteAccess = $this->allowInsert( $this->getUser(), $wgRequest );
        $requestData->articlePath = $wgArticlePath;

        return $requestData;
    }

    /**
     * Show the RDF Import Form HTML, and some additional info HTML
     */
    function showHTMLFormAndInfo( $requestData ) {
        $wOut = $this->getOutput();
        $wUser = $this->getUser();

        $wOut->addHTML( $this->getHTMLForm( $requestData, $wUser ) );
        $wOut->addHTML( '<div id=sources style="display:none">' );
        $wOut->addWikiText( '{{#ask: [[Category:RDFIO Data Source]] [[RDFIO Import Type::RDF]] |format=list }}' );
        $wOut->addHTML( '</div>' );
    }

    /**
     * Output the HTML for the form, to the user
     */
    function getHTMLForm( $requestData, $user ) {
        $formText = "";
        $formText .= $this->getJsCode();
        $formText .= $this->getHTMLFormContent( $requestData, $user );
        return $formText;
    }

    /**
     * Get RDF/XML stub for for the import form, including namespace definitions
     * @return string
     */
    public function getExampleRDFXMLData() {
        return '<rdf:RDF\\n\
xmlns:rdf=\\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\\"\\n\
xmlns:cd=\\"http://www.recshop.fake/cd#\\"\\n\
xmlns:countries=\\"http://www.countries.org/onto/\\"\\n\
xmlns:rdfs=\\"http://www.w3.org/2000/01/rdf-schema#\\"\\n\
xmlns:cat=\\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\\"\\n\
>\\n\
\\n\
<rdf:Description\\n\
rdf:about=\\"http://www.recshop.fake/cd/Empire Burlesque\\">\\n\
<cd:artist>Bob Dylan</cd:artist>\\n\
<cd:country rdf:resource=\\"http://www.countries.org/onto/USA\\"/>\\n\
<cd:company>Columbia</cd:company>\\n\
<cd:price>10.90</cd:price>\\n\
<cd:year>1985</cd:year>\\n\
<cat:type>Album</cat:type>\\n\
</rdf:Description>\\n\
\\n\
<rdf:Description\\n\
rdf:about=\\"http://www.recshop.fake/cd/Hide your heart\\">\\n\
<cd:artist>Bonnie Tyler</cd:artist>\\n\
<cd:country>UK</cd:country>\\n\
<cd:company>CBS Records</cd:company>\\n\
<cd:price>9.90</cd:price>\\n\
<cd:year>1988</cd:year>\\n\
<cat:type>Album</cat:type>\\n\
</rdf:Description>\\n\
\\n\
<rdf:Description\\n\
rdf:about=\\"http://www.countries.org/onto/USA\\">\\n\
<rdfs:label>USA</rdfs:label>\\n\
</rdf:Description>\\n\
\\n\
<rdf:Description rdf:about=\\"http://www.countries.org/onto/Albums\\">\\n\
<rdfs:subClassOf rdf:resource=\\"http://www.countries.org/onto/MediaCollections\\"/>\\n\
</rdf:Description>\\n\
</rdf:RDF>';
    }

    /**
     * Get Turtle stub for for the import form, including namespace definitions
     * @return string
     */
    public function getExampleTurtleData() {
        $exampleData = <<<EOT
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\\n\
@prefix cd: <http://www.recshop.fake/cd#> .\\n\
@prefix countries: <http://www.countries.org/onto/> .\\n\
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\\n\
@prefix cat: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\\n\
\\n\
<http://www.recshop.fake/cd/Empire Burlesque>\\n\
    cd:artist \\"Bob Dylan\\" ;\\n\
    cd:country countries:USA ;\\n\
    cd:company \\"Columbia\\" ;\\n\
    cd:price \\"10.90\\" ;\\n\
    cd:year \\"1985\\" ;\\n\
    cat:type \\"Album\\" .\\n\
\\n\
<http://www.recshop.fake/cd/Hide your heart>\\n\
    cd:artist \\"Bonnie Tyler\\" ;\\n\
    cd:country \\"UK\\" ;\\n\
    cd:company \\"CBS Records\\" ;\\n\
    cd:price \\"9.90\\" ;\\n\
    cd:year \\"1988\\" ;\\n\
    cat:type \\"Album\\" .\\n\
\\n\
countries:USA\\n\
    rdfs:label \\"USA\\" .\\n\
\\n\
countries:Albums\\n\
    rdfs:subClassOf countries:MediaCollections .';
EOT;
        return $exampleData;
    }

    /**
     * Generate the main HTML form, if the variable $extraFormContent is set, the
     * content of it will be prepended before the form
     * @param RDFIORequestData $requestData
     * @param string $extraFormContent
     * @return string $htmlFormContent
     */
    public function getHTMLFormContent( $requestData, $user, $extraFormContent = '' ) {
        $textfieldHiddenHTML = '';
        $urlChecked = ( $requestData->importSource === 'url' );
        $textfieldChecked = ( $requestData->importSource === 'textfield' );

        // Show (and pre-select) the URL field, as default
        if ( !$urlChecked && !$textfieldChecked ) {
            $urlChecked = true;
        }
        if ( !$textfieldChecked ) {
            $textfieldHiddenHTML = 'style="display: none"';
        }

        $urlCheckedContent = $urlChecked ? 'checked="true"' : '';
        $textfieldCheckedHTML = $textfieldChecked ? 'checked="true"' : '';

        // Create the HTML form for RDF/XML Import
        $htmlFormContent = '<script type="text/javascript">
                function showUrlFields() {
                    document.getElementById("urlfields").style.display = "";
                    document.getElementById("datafields").style.display = "none";
                }
                function showDataFields() {
                    document.getElementById("urlfields").style.display = "none";
                    document.getElementById("datafields").style.display = "";
                }
                </script>
                <form method="post" action=""
                name="createEditQuery"><input type="hidden" name="action" value="import">
                ' . $extraFormContent . '
                    <table border="0">
                        <tbody>
                            <tr>
                                <td colspan="3">
                                Action:
                                <input type="radio" name="importsrc" value="url" ' . $urlCheckedContent . ' onclick="javascript:showUrlFields();" />' . wfMessage( 'rdfio-import-rdf-from-url' )->parse() . '
                                <input type="radio" name="importsrc" value="textfield" ' . $textfieldCheckedHTML . ' onclick="javascript:showDataFields();" />' . wfMessage( 'rdfio-paste-rdf' )->parse() . '
                                </td>
                            </tr>
                        </tbody>
                    </table>
                        
                    <div id="urlfields">
                        External URL:
                        <input type="text" size="100" name="extrdfurl" id="extrdfurl">
                        <a href="#" onClick="addSourcesToMenu();">' . wfMessage( 'rdfio-use-previous-source' )->parse() . '</a>
                    </div>
                        
                    <div id="datafields" ' . $textfieldHiddenHTML . '>
                        <table style="border: none"><tbody>
                            <tr>
                                <td colspan="3">' . wfMessage( 'rdfio-data-to-import' )->parse() . ':</td>
                            </tr>
                            <tr>
                                <td colspan="3"><textarea cols="80" rows="16" name="importdata" id="importdata">' . $requestData->importData . '</textarea></td>
                            </tr>
                            <tr>
                                <td style="width: 100px;">' . wfMessage( 'rdfio-data-format' )->parse() . ':</td>
                                <td>
                                    <select id="dataformat" name="dataformat">
                                        <option value="turtle" selected="selected">Turtle</option>
                                        <option value="rdfxml">RDF/XML</option>
                                    </select>
                                </td>
                                <td style="text-align: right; font-size: 10px;">' . wfMessage( 'rdfio-paste-example-data' )->parse() . '
                                    [<a href="#" onClick="pasteExampleRDFXMLData(\'importdata\');">' . wfMessage( 'rdfio-rdfxml-format' )->parse() . '</a>]
                                    [<a href="#" onClick="pasteExampleTurtleData(\'importdata\');">' . wfMessage( 'rdfio-turtle-format' )->parse() . '</a>]
                                    [<a href="#" onClick="document.getElementById(\'importdata\').value = \'\';">' . wfMessage( 'rdfio-clear' )->parse() . '</a>]
                                </td>
                            </tr>
                        </tbody></table>
                    </div>
                    <input type="submit" value="Submit">
                    <input type="hidden" name="token" value="' . $user->getEditToken() . '">
                </form>';

        return $htmlFormContent;
    }

    /**
     * Generate the javascript code used in the main HTML form for
     * loading example data into the main textarea
     * also set the dataformat to the correct one
     * @return string $exampleDataJs
     */
    public function getJsCode() {
        $jsCode = '
<script type="text/javascript">
function pasteExampleRDFXMLData(textFieldId) {
    var textfield = document.getElementById(textFieldId);
    var exampledata = "' . $this->getExampleRDFXMLData() . '";
    textfield.value = exampledata;
    document.getElementById("dataformat").options[1].selected = true;
    
}    
function pasteExampleTurtleData(textFieldId) {
    var textfield = document.getElementById(textFieldId);
    var exampledata = "' . $this->getExampleTurtleData() . '";
    textfield.value = exampledata;
    document.getElementById("dataformat").options[0].selected = true;
}

function addSourcesToMenu() {
    var sourceList = document.getElementById("sources").getElementsByTagName("p")[0];
    var sources = sourceList.getElementsByTagName("a");
    var urlForm = document.getElementById("urlfields");
    var urlTextField = document.getElementById("extrdfurl");
    var selectList = document.createElement("select");
    selectList.id = "sourceSelect";
    urlForm.appendChild(selectList);
    for (var i = 0; i < sources.length; i++) {
        var option = document.createElement("option");
        option.value = sources[i].innerHTML;
        option.text = sources[i].innerHTML;
        selectList.appendChild(option);
    }
    selectList.onchange = function() {selectedUrl = selectList.options[selectList.selectedIndex].value; selectedUrl1 = selectedUrl.substring(0,1).toLowerCase(); selectedUrl2 = selectedUrl.substring(1); selectedUrl = selectedUrl1.concat(selectedUrl2); urlTextField.value = selectedUrl};
}
</script>
                        ';
        return $jsCode;
    }

}

class RDFIORequestData {
    public $action;
    public $editToken;
    public $importSource;
    public $externalRdfUrl;
    public $importData;
    public $dataFormat;
    public $hasWriteAccess;
    public $articlePath;

    public function __construct() {
    }
}