prefix 拼出、值走 prepare()。 // 进度随每次翻译变动,缓存会让「全部翻译」重复领到同一批页面,故不接对象缓存。 // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery // phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared // phpcs:disable WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber // phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter /** * Class APGT_Progress */ class APGT_Progress { /** * 取数据表名。 * * @return string */ public static function table() { return APGT_Install::progress_table_name(); } /** * 写入 / 更新某页面在某语言下的进度。 * * @param string $path 站内路径。 * @param string $to 目标语言。 * @param int $total 该页面提取到的文本条数。 * @param int $done 其中已有译文的条数。 * @return bool */ public static function save( $path, $to, $total, $done ) { global $wpdb; $path = (string) $path; if ( '' === $path || '' === (string) $to ) { return false; } $table = self::table(); $sql = $wpdb->prepare( "INSERT INTO {$table} (page_path, path_md5, language_to, total, done, updated_at) VALUES (%s, %s, %s, %d, %d, %s) ON DUPLICATE KEY UPDATE page_path = VALUES(page_path), total = VALUES(total), done = VALUES(done), updated_at = VALUES(updated_at)", // phpcs:ignore WordPress.DB.PreparedSQL $path, md5( $path ), (string) $to, max( 0, (int) $total ), max( 0, (int) $done ), current_time( 'mysql' ) ); return false !== $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL } /** * 取指定语言下所有页面的进度。 * * @param string $to 目标语言。 * @return array 路径 => [ 'total'=>int, 'done'=>int, 'updated_at'=>string ] */ public static function map( $to ) { global $wpdb; $table = self::table(); $rows = $wpdb->get_results( $wpdb->prepare( "SELECT page_path, total, done, updated_at FROM {$table} WHERE language_to = %s", // phpcs:ignore WordPress.DB.PreparedSQL (string) $to ), ARRAY_A ); // phpcs:ignore WordPress.DB.PreparedSQL $out = array(); foreach ( (array) $rows as $r ) { $out[ (string) $r['page_path'] ] = array( 'total' => (int) $r['total'], 'done' => (int) $r['done'], 'updated_at' => (string) $r['updated_at'], ); } return $out; } /** * 判断一条进度是否算「已完成」。 * * @param array|null $row map() 里的一项。 * @return bool */ public static function is_complete( $row ) { // 没有记录 = 没处理过。total 为 0(页面没有可翻译文本)也算完成, // 否则这种页面会永远留在待办里被反复抓取。 return is_array( $row ) && $row['done'] >= $row['total']; } /** * 删除某页面的进度记录(重置后会被重新统计)。 * * @param string $path 站内路径。 * @param string $to 目标语言;留空表示所有语言。 * @return int 删除条数。 */ public static function delete( $path, $to = '' ) { global $wpdb; $where = array( 'path_md5' => md5( (string) $path ) ); $format = array( '%s' ); if ( '' !== $to ) { $where['language_to'] = (string) $to; $format[] = '%s'; } return (int) $wpdb->delete( self::table(), $where, $format ); } /** * 清空全部进度。 * * @return void */ public static function clear() { global $wpdb; $table = self::table(); $wpdb->query( "TRUNCATE TABLE {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL } }