PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Monday, March 7, 2022

[FIXED] How can I sync differing primary key values on replicating execute?

 March 07, 2022     cakephp-3.0, database-replication, php     No comments   

Issue

I have two connections, d and c. Basically, whatever changes I do on certain models of d, it needs to be replicated at c as well. This is the code doing it:

    public function execute()
    {
        if ($this->isReplicate()) {
            $primaryKey = $this->_repository->getPrimaryKey();
            $replica = clone $this;
            $replica->setConnection(ConnectionManager::get('c'));
            $replica->execute();
            //$this->_repository->{$primaryKey} = $replica->getRepository()->{$primaryKey};
        }
        $result = parent::execute();
        return $result;
    }

The commented line would be responsible for syncing the primary keys, but of course this is not working, because _repository represents a table, yet, I need to apply row-level changes. How could I ensure that all new records created by this query will be synced?

This code is located in the App\ORM\Query namespace, which extends Cake\ORM\Query.


Solution

I have managed to resolve the issue with the code that follows (the logic is explained in the comments):

    /**
     * Overrides a method with the same name to handle synchronizations with c
     */
    public function execute()
    {
        //Some tables need replication. If this is such a table, then we need to perform some extra steps. Otherwise we would just call the parent
        //Method
        if ($this->isReplicate()) {
            //Getting the table
            $table = $this->_repository->getTable();
            //Replicating the query
            $replica = clone $this;
            //Setting the connection of the replica to c, because we need to apply the district changes to central
            $replica->setConnection(ConnectionManager::get('c'));
            //We execute the replica first, because we will need to refer c IDs and not the other way around
            $replica->execute();
            //If this is an insert, then we need to handle the ids as well
            if (!empty($this->clause('insert'))) {
                //We load the primary key's name to use it later to find the maximum value
                $primaryKey = $this->_repository->getPrimaryKey();
                //We get the highest ID value, which will always be a positive number, because we have already executed the query at the replica
                $maxID = $this->getConnection()
                              ->execute("SELECT {$primaryKey} FROM {$table} ORDER BY {$primaryKey} DESC LIMIT 0, 1")
                              ->fetchAll('assoc')[0][$primaryKey];

                //We get the columns
                $columns = $this->clause('values')->getColumns();
                //In order to add the primary key
                $columns[] = $primaryKey;
                //And then override the insert clause with this adjusted array
                $this->insert($columns);
                //We get the values
                $values = $this->clause('values')->getValues();
                //And their count
                $count = count($values);
                //There could be multiple rows inserted already into the replica as part of this query, we need to replicate all their IDs, without
                //assuming that there is a single inserted record
                for ($index = 0; $index < $count; $index++) {
                    $values[$index][$primaryKey] = $maxID - $count + $index + 1;
                }
                //We override the values clause with this adjusted array, which contains PK values as well
                $this->clause('values')->values($values);
            }
            //We nevertheless execute the query in any case, independently of whether it was a replicate table
            //If it was a replicate table, then we have already made adjustments to the query in the if block
            return parent::execute();
        }
    }


Answered By - Lajos Arpad
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home
View mobile version

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing