I am using this statement to SELECT and UPDATE contract approvals. While the statement selects data from multiple tables it only updates one table called contract_has_rfa. The two key tables are contract and contract_has_rfa. There can be multiple rfa's for one contract, but only one for a contract and one user (unique index on contract_has_rfa.contract_id and contract_has_rfa.approver_id). The link to the contract table is through contract.id as a foreign key (contract_has_rfa.contract_id.
Contract_has_rfa is also linked to the user table with user.id which is contract_has_rfa.approver_id in contract_has_rfa.
The statement selects all contracts that are assigned to the respective user ($_SESSION['id']) for approval. This works fine. Only the assigned contracts are selected not all of them. When making the update (setting contract_has_rfa.status to 'W', 'N' or 'A') there is a bug: The UPDATE statement does NOT contain the approver_id in its WHERE clause. It only has the respective contract.id in its WHERE clause. Hence all rfa's get updated for the respective contract - even those assigned to a different user!
The bug is that the UPDATE statement generated by Editor ignores this WHERE clause in my PHP statement below:
->where( 'contract_has_rfa.approver_id', $_SESSION['id'] )
while the SELECT statement uses it. I used the debug option to check the UPDATE statement generated by Editor to verify this.
Is there a fix for this bug? I would like to avoid a work around if possible.
<?php
Editor::inst( $db, 'contract' )
->field(
Field::inst( 'gov.name' )->set( false ),
Field::inst( 'govdept.name' )->set( false ),
Field::inst( 'creditor.name' )->set( false ),
Field::inst( 'contract.id' )->set( false ),
Field::inst( 'contract.description' )->set( false ),
Field::inst( 'contract_has_rfa.status' )
->setFormatter( function ( $val, $data, $opts ) {
if ($val === 'W' && $data['contractStatusAlias'] === 'N') {
$val = 'N';
}
return $val;
} ),
Field::inst( 'contract_has_rfa.status AS contractStatusAlias' )->set( false ),
Field::inst( 'contract_has_rfa.update_time' )->set(Field::SET_BOTH)
->setValue( date("Y-m-d H:i:s") ),
Field::inst( 'contract_has_rfa.updater_id' )->set(Field::SET_BOTH)
->setValue( $_SESSION['id'] )
)
// show approvals if any
->join(
Mjoin::inst( 'user' )
->link( 'contract.id', 'contract_has_rfa.contract_id')
->link( 'user.id', 'contract_has_rfa.approver_id' )
->order( 'contract_has_rfa.status DESC, user.lastname ASC' )
->fields(
Field::inst( 'user.firstname AS userFirstName' )->set( false ),
Field::inst( 'user.lastname AS userLastName' )->set( false ),
Field::inst( 'contract_has_rfa.status AS approvalStatus' )->set( false ),
Field::inst( 'contract_has_rfa.update_time AS updateTime' )->set( false )
->getFormatter( function ( $val, $data, $opts ) {
return getFormatterDateTime($val);
} )
)
)
->join(
Mjoin::inst( 'file' )
->link( 'contract.id', 'contract_has_file.contract_id' )
->link( 'file.id', 'contract_has_file.file_id' )
->fields(
Field::inst( 'web_path' )->set( false ),
Field::inst( 'name' )->set( false )
)
)
->leftJoin( 'govdept', 'contract.govdept_id', '=', 'govdept.id')
->leftJoin( 'gov', 'govdept.gov_id', '=', 'gov.id')
->leftJoin( 'creditor', 'contract.creditor_id', '=', 'creditor.id')
->leftJoin( 'contract_has_rfa', 'contract.id', '=', 'contract_has_rfa.contract_id')
->leftJoin( 'user', 'contract_has_rfa.approver_id', '=', 'user.id')
->where( 'contract_has_rfa.approver_id', $_SESSION['id'] )
->debug(true)
->process($_POST)
->json();
This is the SQL for the UPDATE generated by Editor:
bindings: [{name: ":status", value: "A", type: null},…]
0:{name: ":status", value: "A", type: null}
name:":status"
type:null
value:"A"
1:{name: ":update_time", value: "2017-05-07 16:16:59", type: null}
name:":update_time"
type:null
value:"2017-05-07 16:16:59"
2:{name: ":updater_id", value: "37", type: null}
name:":updater_id"
type:null
value:"37"
3:{name: ":where_0", value: "25", type: null}
name:":where_0"
type:null
value:"25"
query:"UPDATE `contract_has_rfa`
SET `status` = :status, `update_time` = :update_time, `updater_id` = :updater_id
WHERE `contract_id` = :where_0 "
And this is the result in the table contract_has_rfa:
CONTRACT_HAS_RFA after update:
-
id contract_id approver_id who status update_time updater_id creator_id
1 25 37 G A 07.05.2017 16:16 37 6
2 25 12 G A 07.05.2017 16:16 37 6
As you can see both rows where updated while only the first row should have been updated.