349 lines
No EOL
10 KiB
PHP
349 lines
No EOL
10 KiB
PHP
<?php if ( ! defined( 'ABSPATH' ) ) exit;
|
|
|
|
/**
|
|
* Class NF_Updates_CacheFieldReconcilliation
|
|
*
|
|
* This allows us to make sure that the data being saved to the database is in the fields table.
|
|
*/
|
|
class NF_Updates_CacheFieldReconcilliation extends NF_Abstracts_RequiredUpdate
|
|
{
|
|
|
|
private $data = array();
|
|
|
|
private $running = array();
|
|
|
|
/**
|
|
* Non-associatve array of field ids from the cache.
|
|
* @var array
|
|
*/
|
|
private $field_ids = array();
|
|
|
|
/**
|
|
* columns to retrieve from meta table
|
|
*/
|
|
private $meta_keys = array(
|
|
'label',
|
|
'key',
|
|
'order',
|
|
'required',
|
|
'default',
|
|
'label_pos',
|
|
'personally_identifiable'
|
|
);
|
|
|
|
/**
|
|
* The denominator object for calculating our steps.
|
|
* @var Integer
|
|
*/
|
|
private $divisor = 200;
|
|
|
|
/**
|
|
* The table names for our database queries.
|
|
*/
|
|
private $table;
|
|
private $meta_table;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param $data (Array) The data object passed in by the AJAX call.
|
|
* @param $running (Array) The array of required updates being run.
|
|
*
|
|
* @since 3.4.0
|
|
*/
|
|
public function __construct( $data = array(), $running )
|
|
{
|
|
// Build our arguments array.
|
|
$args = array(
|
|
'slug' => 'CacheFieldReconcilliation',
|
|
'class_name' => 'NF_Updates_CacheFieldReconcilliation',
|
|
'debug' => false,
|
|
);
|
|
$this->data = $data;
|
|
$this->running = $running;
|
|
|
|
// Call the parent constructor.
|
|
parent::__construct( $args );
|
|
|
|
// Set our table names.
|
|
$this->table = $this->db->prefix . 'nf3_fields';
|
|
$this->meta_table = $this->db->prefix . 'nf3_field_meta';
|
|
|
|
// Begin processing.
|
|
$this->process();
|
|
}
|
|
|
|
/**
|
|
* Function to loop over the batch.
|
|
*
|
|
* @since 3.4.0
|
|
*/
|
|
public function process()
|
|
{
|
|
// If we've not already started...
|
|
if ( ! isset( $this->running[ 0 ][ 'running' ] ) ) {
|
|
// Run our startup method.
|
|
$this->startup();
|
|
}
|
|
|
|
/**
|
|
* Get the next round of fields to update
|
|
*/
|
|
$this->get_fields_this_step();
|
|
|
|
/**
|
|
* Update fields
|
|
*/
|
|
$this->update_fields();
|
|
|
|
/**
|
|
* Saves our current location, along with any processing data we may need for the next step.
|
|
* If we're done with our step, runs cleanup instead.
|
|
*/
|
|
$this->end_of_step();
|
|
|
|
/**
|
|
* Respond to the AJAX call.
|
|
*/
|
|
$this->respond();
|
|
}
|
|
|
|
/**
|
|
* Function to run any setup steps necessary to begin processing.
|
|
*
|
|
* @since 3.4.0
|
|
*/
|
|
public function startup()
|
|
{
|
|
// Record that we're processing the update.
|
|
$this->running[ 0 ][ 'running' ] = true;
|
|
|
|
$sql = "SELECT `id` FROM `{$this->table}`";
|
|
$fields = $this->db->get_results( $sql, 'ARRAY_A' );
|
|
// Record the total number of steps in this batch.
|
|
$this->running[ 0 ][ 'steps' ] = ceil(count( $fields ) / $this->divisor);
|
|
// Record our current step (defaulted to 0 here).
|
|
$this->running[ 0 ][ 'current' ] = 0;
|
|
}
|
|
|
|
public function get_fields_this_step() {
|
|
|
|
$offset = 0;
|
|
|
|
if( 0 < $this->running[ 0 ][ 'current' ] ) {
|
|
$offset = $this->running[ 0 ][ 'current' ] * $this->divisor;
|
|
}
|
|
|
|
// Get a list of our fields...
|
|
$sql = "SELECT `id` FROM `{$this->table}` LIMIT {$offset}, {$this->divisor}";
|
|
$this->field_ids = $this->db->get_results( $sql, 'ARRAY_A' );
|
|
$this->field_ids = $this->array_squash( $this->field_ids );
|
|
// $this->running[ 0 ][ 'fields' ] = $this->field_ids;
|
|
}
|
|
|
|
/**
|
|
* Update field table records with data from field meta
|
|
*/
|
|
public function update_fields() {
|
|
$field_meta = $this->get_field_meta();
|
|
|
|
if($field_meta) {
|
|
$update_query = $this->get_update_query( $field_meta );
|
|
|
|
if( $update_query ) {
|
|
$this->query($update_query);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get meta data to use for updating
|
|
*/
|
|
public function get_field_meta() {
|
|
|
|
if(0 === count($this->field_ids)) return false;
|
|
|
|
$in_fields = implode( ', ', $this->field_ids );
|
|
$meta_keys = "'" . implode( "' , '", $this->meta_keys ) . "'";
|
|
|
|
$meta_query = $this->get_field_meta_query();
|
|
|
|
$results = $this->db->get_results( $meta_query, 'ARRAY_A');
|
|
|
|
$meta_data = $this->format_field_meta($results);
|
|
|
|
return $meta_data;
|
|
}
|
|
|
|
/**
|
|
* Construct the query to get meta data
|
|
*
|
|
* return String $meta_query
|
|
*/
|
|
public function get_field_meta_query() {
|
|
$in_fields = implode( ', ', $this->field_ids );
|
|
$meta_keys = "'" . implode( "' , '", $this->meta_keys ) . "'";
|
|
|
|
$meta_query = "SELECT `parent_id`, `key`, `meta_key`, `meta_value`, `value` FROM `{$this->meta_table}` WHERE `parent_id` IN ({$in_fields}) AND `key` IN ({$meta_keys}) ORDER BY `parent_id` ASC";
|
|
|
|
return $meta_query;
|
|
}
|
|
|
|
/**
|
|
* Format the data into format that helps us construct the insert/update query
|
|
*
|
|
* @param Array $metadata
|
|
*
|
|
* @return Array $meta_data
|
|
*/
|
|
public function format_field_meta( $metadata ) {
|
|
$meta_data = array();
|
|
|
|
foreach( $metadata as $meta ) {
|
|
$parent_id = $meta['parent_id'];
|
|
foreach( $meta as $key => $val ) {
|
|
|
|
if( 'parent_id' !== $key ) {
|
|
$meta_data[ $parent_id ][ $meta['key'] ] = $meta['value'];
|
|
$meta_data[ $parent_id ][ 'meta_' . $meta['meta_key'] ] = $meta['meta_value'];
|
|
}
|
|
}
|
|
}
|
|
|
|
return $meta_data;
|
|
}
|
|
|
|
/**
|
|
* Construct field update query
|
|
*/
|
|
public function get_update_query( $field_data ) {
|
|
if( 0 === count( $field_data) ) return false;
|
|
|
|
$sql = "INSERT INTO {$this->table}
|
|
(`id`, `label`, `key`, `field_label`, `field_key`, `order`, `required`, `default_value`, `label_pos`, `personally_identifiable`)
|
|
VALUES";
|
|
|
|
foreach( $field_data as $field_id => $meta ) {
|
|
$sql .= "({$field_id}, '{$this->db->_real_escape($meta['label'])}', '{$this->db->_real_escape($meta['key'])}', '{$this->db->_real_escape($meta['meta_label'])}', '{$this->db->_real_escape($meta['meta_key'])}', {$meta['order']},";
|
|
|
|
if( isset( $meta[ 'required' ] ) && '' !== $meta[ 'required' ]) {
|
|
$sql .= "{$meta['required']},";
|
|
} else {
|
|
$sql .= "0,";
|
|
}
|
|
|
|
if(isset( $meta[ 'meta_default' ] ) ) {
|
|
$sql .= "'{$this->db->_real_escape($meta['meta_default'])}',";
|
|
} else {
|
|
$sql .= "'',";
|
|
}
|
|
|
|
if( isset( $meta[ 'meta_label_pos' ] ) ) {
|
|
$sql .= "'{$meta['meta_label_pos']}',";
|
|
} else {
|
|
$sql .= "'',";
|
|
}
|
|
|
|
if(isset($meta['personally_identifiable'])) {
|
|
$sql .= "{$meta['personally_identifiable']}";
|
|
} else {
|
|
$sql .= "0";
|
|
}
|
|
|
|
$sql .= "),";
|
|
}
|
|
|
|
$sql = rtrim( $sql, ',' );
|
|
|
|
$sql .= "ON DUPLICATE KEY
|
|
UPDATE
|
|
`label` = VALUES(`label`),
|
|
`key` = VALUES(`key`),
|
|
`field_label` = VALUES(`field_label`),
|
|
`field_key` = VALUES(`field_key`),
|
|
`order` = VALUES(`order`),
|
|
`required` = VALUES(`required`),
|
|
`required` = VALUES(`required`),
|
|
`default_value` = VALUES(`default_value`),
|
|
`label_pos` = VALUES(`label_pos`),
|
|
`personally_identifiable` = VALUES(`personally_identifiable`)";
|
|
|
|
return $sql;
|
|
}
|
|
|
|
/**
|
|
* Function to cleanup any lingering temporary elements of a required update after completion.
|
|
*
|
|
* @since 3.4.0
|
|
*/
|
|
public function cleanup()
|
|
{
|
|
// Remove the current process from the array.
|
|
array_shift( $this->running );
|
|
// Record to our updates setting that this update is complete.
|
|
$this->confirm_complete();
|
|
// If we have no updates left to process...
|
|
if ( empty( $this->running ) ) {
|
|
// Call the parent cleanup method.
|
|
parent::cleanup();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* After we've done our processing, but before we get to step cleanup, we need to store process information.
|
|
*
|
|
* This method updates our form class var so that it can be passed to the next step.
|
|
* If we've completed this step, it calls the cleanup method.
|
|
*
|
|
* @since 3.4.0
|
|
* @return void
|
|
*/
|
|
private function end_of_step()
|
|
{
|
|
$this->running[ 0 ][ 'current' ] = intval( $this->running[ 0 ][ 'current' ] ) + 1;
|
|
|
|
// Prepare to output our number of steps and current step.
|
|
$this->response[ 'stepsTotal' ] = $this->running[ 0 ][ 'steps' ];
|
|
$this->response[ 'currentStep' ] = $this->running[ 0 ][ 'current' ];
|
|
|
|
if ( $this->divisor > count($this->field_ids)) {
|
|
// Run our cleanup method.
|
|
$this->cleanup();
|
|
}
|
|
|
|
// Record our current location in the process.
|
|
update_option( 'ninja_forms_doing_required_updates', $this->running );
|
|
// Prepare to output the number of updates remaining.
|
|
$this->response[ 'updatesRemaining' ] = count( $this->running );
|
|
}
|
|
|
|
/**
|
|
* Function to compress our db results into a more useful format.
|
|
*
|
|
* @param $data (Array) The result to be compressed.
|
|
*
|
|
* @return (Array) Associative if our data was complex.
|
|
* Non-associative if our data was a single item.
|
|
*
|
|
* @since UPDATE_VERSION_ON_MERGE
|
|
*/
|
|
private function array_squash( $data )
|
|
{
|
|
$response = array();
|
|
// For each item in the array...
|
|
foreach ( $data as $row ) {
|
|
// If the item has more than 1 attribute...
|
|
if ( 1 < count( $row ) ) {
|
|
// Assign the data to an associated result.
|
|
$response[] = intval($row['id']);
|
|
// Unset the id setting, as that will be the key.
|
|
unset( $response[ $row[ 'id' ] ][ '' ] );
|
|
} // Otherwise... (We only have 1 attribute.)
|
|
else {
|
|
// Add the id to the stack in a non-associated result.
|
|
$response[] = intval( $row[ 'id' ] );
|
|
}
|
|
}
|
|
return $response;
|
|
}
|
|
} |