Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
72.73% covered (warning)
72.73%
48 / 66
40.00% covered (danger)
40.00%
2 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
UpdateTable
80.00% covered (warning)
80.00%
48 / 60
40.00% covered (danger)
40.00%
2 / 5
14.35
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 normaliseStreamPath
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
3.03
 execute
81.82% covered (warning)
81.82%
18 / 22
0.00% covered (danger)
0.00%
0 / 1
4.10
 createImportContext
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 clearTable
61.11% covered (warning)
61.11%
11 / 18
0.00% covered (danger)
0.00%
0 / 1
4.94
1<?php
2
3namespace PropertySuggester\Maintenance;
4
5use MediaWiki\Maintenance\Maintenance;
6use PropertySuggester\UpdateTable\ImportContext;
7use PropertySuggester\UpdateTable\Importer\BasicImporter;
8use UnexpectedValueException;
9use Wikimedia\Rdbms\IDatabase;
10use Wikimedia\Rdbms\ILBFactory;
11
12$basePath = getenv( 'MW_INSTALL_PATH' ) !== false
13    ? getenv( 'MW_INSTALL_PATH' )
14    : __DIR__ . '/../../..';
15require_once $basePath . '/maintenance/Maintenance.php';
16
17/**
18 * Maintenance script to load property pair occurrence probability table from given csv file
19 *
20 * @author BP2013N2
21 * @license GPL-2.0-or-later
22 */
23class UpdateTable extends Maintenance {
24
25    public function __construct() {
26        parent::__construct();
27
28        $this->addDescription( "Read CSV Dump and refill probability table" );
29        $this->addOption( 'file', 'CSV table to be loaded (relative path)', true, true );
30        $this->setBatchSize( 10000 );
31        $this->requireExtension( 'PropertySuggester' );
32    }
33
34    /**
35     * If passed a filename, find the absolute path and convert to unix format.
36     *
37     * @param string $uriOrFilePath
38     * @return string
39     */
40    private function normaliseStreamPath( string $uriOrFilePath ): string {
41        if ( str_contains( $uriOrFilePath, '://' ) ) {
42            // Path is a stream - not attempt to normalise / verify
43            return $uriOrFilePath;
44        }
45        $fullPath = realpath( $uriOrFilePath );
46        $fullPath = str_replace( '\\', '/', $fullPath );
47
48        if ( !file_exists( $fullPath ) ) {
49            $this->fatalError( "Cant find $uriOrFilePath \n" );
50        }
51        return $fullPath;
52    }
53
54    /**
55     * loads property pair occurrence probability table from given csv file
56     */
57    public function execute() {
58        if ( substr( $this->getOption( 'file' ), 0, 2 ) === "--" ) {
59            $this->fatalError( "The --file option requires a file as an argument.\n" );
60        }
61        $path = $this->getOption( 'file' );
62        $fullPath = $this->normaliseStreamPath( $path );
63
64        $tableName = 'wbs_propertypairs';
65
66        $lbFactory = $this->getServiceContainer()->getDBLoadBalancerFactory();
67        $lbFactory->waitForReplication();
68
69        $this->clearTable( $lbFactory, $tableName );
70
71        $this->output( "loading new entries from file\n" );
72
73        $importContext = $this->createImportContext(
74            $lbFactory,
75            $tableName,
76            $fullPath,
77            $this->isQuiet()
78        );
79        $importStrategy = new BasicImporter();
80
81        try {
82            $success = $importStrategy->importFromCsvFileToDb( $importContext );
83        } catch ( UnexpectedValueException $e ) {
84            $this->fatalError( "Import failed: " . $e->getMessage() );
85        }
86
87        if ( !$success ) {
88            $this->fatalError( "Failed to run import to db" );
89        }
90        $this->output( "... Done loading\n" );
91    }
92
93    /**
94     * @param ILBFactory $lbFactory
95     * @param string $tableName
96     * @param string $wholePath
97     * @param bool $quiet
98     * @return ImportContext
99     */
100    private function createImportContext( ILBFactory $lbFactory, $tableName, $wholePath, $quiet ) {
101        $importContext = new ImportContext();
102        $importContext->setLbFactory( $lbFactory );
103        $importContext->setTargetTableName( $tableName );
104        $importContext->setCsvFilePath( $wholePath );
105        $importContext->setCsvDelimiter( ',' );
106        $importContext->setBatchSize( $this->mBatchSize );
107        $importContext->setQuiet( $quiet );
108
109        return $importContext;
110    }
111
112    /**
113     * @param ILBFactory $lbFactory
114     * @param string $tableName
115     */
116    private function clearTable( ILBFactory $lbFactory, $tableName ) {
117        global $wgDBtype;
118
119        $lb = $lbFactory->getMainLB();
120        $db = $lb->getMaintenanceConnectionRef( DB_PRIMARY );
121        if ( !$db->tableExists( $tableName, __METHOD__ ) ) {
122            $this->fatalError( "$tableName table does not exist.\n" .
123                "Executing core/maintenance/update.php may help.\n" );
124        }
125        $this->output( "Removing old entries\n" );
126        if ( $wgDBtype === 'sqlite' || $wgDBtype === 'postgres' ) {
127            $db->newDeleteQueryBuilder()
128                ->deleteFrom( $tableName )
129                ->where( IDatabase::ALL_ROWS )
130                ->caller( __METHOD__ )
131                ->execute();
132        } else {
133            do {
134                $db->commit( __METHOD__, 'flush' );
135                $lbFactory->waitForReplication();
136                $this->output( "Deleting a batch\n" );
137                $table = $db->tableName( $tableName );
138                $db->query( "DELETE FROM $table LIMIT $this->mBatchSize", __METHOD__ );
139            } while ( $db->affectedRows() > 0 );
140        }
141    }
142
143}
144
145$maintClass = UpdateTable::class;
146require_once RUN_MAINTENANCE_IF_MAIN;