Zend TableGateway can't execute 2 consecutive query - zend-framework

It's been weeks since I start learning Slim using Zend TableGateway from slim-api-skeleton.
It seems I can't run 2 consecutive query using TableGateway. It's always produce (not just UPDATE):
"Statement couldn't be produced with sql: UPDATE `users` SET `last_access` = NOW() WHERE `id` = ?"
Here's the code inside ZendUserRepository class:
public function __construct(array $config) {
$adapter = new Adapter($config);
$this->table = new TableGateway("users", $adapter);
}
...
public function footprint(int $id): void {
$data = ['last_access' => new Predicate\Expression('NOW()')];
$where = ['id' => $id];
$this->table->update($data, $where);
}
public function authenticate(string $username, string $password): bool {
$where = [
'username' => $username,
new Predicate\IsNotNull('roles')
];
$rowset = $this->table->select($where);
if (null === $row = $rowset->current()) {
return false;
}
$data = (array) $row;
if(password_verify($password, $data['password'])) {
$this->footprint($data['id']);
return true;
}
return false;
}
This frustrate me for days. Since the update function also use 2 consecutive query.
public function update(User $user): void {
$data = $this->hydrator->extract($user);
if (!$this->contains($user)) {
throw new UserNotFoundException;
}
$where = ["id" => $user->getId()];
$this->table->update($data, $where);
}
public function contains(User $user): bool {
try {
$this->get($user->getId());
} catch (UserNotFoundException $exception) {
return false;
}
return true;
}
Thank you.

Using PHPUnit test, I got the following result:
Zend\Db\Adapter\Exception\InvalidQueryException: Statement couldn't be produced with sql: UPDATE `users` SET `last_access` = NOW() WHERE `id` = ?
/vagrant/vendor/zendframework/zend-db/src/Adapter/Driver/Mysqli/Statement.php:208
/vagrant/vendor/zendframework/zend-db/src/Adapter/Driver/Mysqli/Statement.php:229
/vagrant/vendor/zendframework/zend-db/src/TableGateway/AbstractTableGateway.php:391
/vagrant/vendor/zendframework/zend-db/src/TableGateway/AbstractTableGateway.php:349
/vagrant/src/Infrastructure/ZendUserRepository.php:90
/vagrant/src/Infrastructure/ZendUserRepository.php:104
/vagrant/src/Application/User/UserAuthenticationHandler.php:19
/vagrant/tests/Application/User/UserAuthenticationHandlerTest.php:41
Caused by
Zend\Db\Adapter\Exception\ErrorException: Commands out of sync; you can't run this command now
And from google lead to https://stackoverflow.com/a/614741/3164944
You can't have two simultaneous queries because mysqli uses unbuffered queries by
default (for prepared statements; it's the opposite for vanilla
mysql_query). You can either fetch the first one into an array and
loop through that, or tell mysqli to buffer the queries (using $stmt->store_result()).
Solved with additional configuration:
[
"driver" => "Mysqli",
"database" => getenv("DB_NAME"),
"username" => getenv("DB_USER"),
"password" => getenv("DB_PASSWORD"),
"hostname" => getenv("DB_HOST"),
"charset" => "utf8",
'options' => ['buffer_results' => true],
]
From https://stackoverflow.com/a/43863554/3164944

Related

Codeigniter Call to a member function where() on bool

I tried to set seen to any contact data in database, but when i try that:
public function showMessage($id){
$this->load->model('Message_Model');
$messageData = $this->Message_Model->selectMessage($id);
if($messageData[0]->messageIsSeen == 0){
$this->Message_Model->setSeenToMessage($id);
}
$data = array('messageData' => $messageData[0]);
$this->load->view('Back/MessageDetail', $data);
}
Model:
function setSeenToMessage($id){
$this->db->update('messages', array('messageIsSeen' => 1))->where('messageId', $id);
return 1;
}
It throws that error
i solved it like this change
function setSeenToMessage($id){
$this->db
->where('messageId', $id);
->update('messages', array('messageIsSeen' => 1))
return 1;
}
nevertheless, still i don't know how did it works

or condition in findByUsername() in yii2 with mongoDB

How can i use or condition in yii2 advanced template with mongoDB:
what i want:
$sql = "SELECT * FROM admin WHERE (username = '$username' OR email = '$username');
How can i put this condition in following function:
public static function findByUsername($username)
{
return static::findOne(['username' => $username]);
}
I have solved like this:
public static function findByUsername($username)
{
$con = array('$or' => array(array('username' => $username),array('email' => $username)));
return static::findOne($con);
}

Zend update/insert (Zend_Db_Table_Abstract) doesn't work

I've got a problem with insert and update queries in Zend (Select is ok).
Definition of table:
class Application_Model_DbTable_Kpr1Data extends Zend_Db_Table_Abstract
{
protected $_name = 'kpr_kpr1_data';
}
Here is my data mapper (model)
class Application_Model_Kpr1DataMapper
{
protected $_dbTable;
public function setdbTable($dbTable) {
if(is_string($dbTable)){
$dbTable = new $dbTable();
}
if(!$dbTable instanceof Zend_Db_Table_Abstract ){
throw new Exception ('Invalid table data gateway provided.');
}
$this->_dbTable = $dbTable;
return $this;
}
public function getdbTable() {
if (null === $this->_dbTable){
$this->setdbTable('Application_Model_DbTable_Kpr1Data');
}
return $this->_dbTable;
}
public function save(Application_Model_Kpr1Data $kpr1data){
$data = array('id' => (int) $kpr1data->getId(),
'kpr1_plaza_id' => (int) $kpr1data->getPlaza(),
'kpr1_data' => new Zend_db_Expr("STR_TO_DATE('".$kpr1data->getDate()."', '%Y-%m-%d')"),
'kpr1_money_delivered' => (float) $kpr1data->getDelivered(),
'kpr1_money_transactions' => (float) $kpr1data->getTransactions(),
'kpr1_created' => new Zend_Db_Expr('CURDATE()')
);
$id = (int) $kpr1data->getId();
$table = $this->getdbTable();
if (is_null($id) && $id != 0) {
unset($data['id']);
$table->insert($data);
} else {
$table->update($data, array('id => ?', $id));
}
}
The last one is save function that should insert and update the data!
And this save is called from save action:
public function saveAction()
{
$plazaid = (int) $this->getRequest()->getParam('plaza');
$date = (string) $this->getRequest()->getParam('date');
$delivered = (string) $this->getRequest()->getParam('delivered');
$transactions = (string) $this->getRequest()->getParam('transactions');
$kpr1data = new Application_Model_Kpr1Data();
if ($plazaid && $date) {
$kpr1datamapper = new Application_Model_Kpr1DataMapper();
if($kpr1datamapper->findDatePlaza($date, $plazaid, $kpr1data)){
$kpr1data->setDelivered($delivered)
->setTransactions($transactions);
$kpr1datamapper->save($kpr1data);
$this->_helper->layout->disableLayout();
$this->view->result = json_encode(array("success"=>"true"));
} else {
$kpr1data->setDate($date);
$kpr1data->setDelivered($delivered);
$kpr1data->setTransactions($transactions);
$kpr1data->setPlaza($plazaid);
$kpr1datamapper->save($kpr1data);
$this->_helper->layout->disableLayout();
$this->view->result = json_encode(array("success"=>"true"));
}
$this->_helper->layout->disableLayout();
$this->view->result = json_encode(array(
//"success"=>"false",
"errorMsg"=>"Saving error"
));
} else {
$this->_helper->layout->disableLayout();
$this->view->result = json_encode(array(
//"success"=>"false",
"errorMsg"=>"Saving error"
));
}
return true;
}
Save action is called via JS, but even called directly through webbrowser it fails.
Behaviour: Application is running, and when debugger runs into update/insert line:
if (is_null($id) && $id != 0) {
unset($data['id']);
$table->insert($data);
} else {
$table->update($data, array('id => ?', $id));
}
it's redirecting to ErrorController.
I've check that:
1. firePHP is not showing this statements
2. MySQL database doesn't log this statement (I've checked via general_log feature).
I'm stucked. Help me please.
edit
$data=
array(6) (
[id] => (int) 0
[kpr1_plaza_id] => (int) 116
[kpr1_data] => Zend_Db_Expr object {
_expression => (string) STR_TO_DATE('2013-03-01', '%Y-%m-%d')
}
[kpr1_money_delivered] => (float) 120
[kpr1_money_transactions] => (float) 122
[kpr1_created] => Zend_Db_Expr object...
$kpr1data=
Application_Model_Kpr1Data object {
_plaza => (string) 116
_date => (string) 2013-03-01
_delivered => (string) 120.00
_transactions => (string) 122.00
_created => null
_id => null
_plazaname => null
}
This one should do insert.
And next one update:
Application_Model_Kpr1Data object {
_plaza => (string) 117
_date => (string) 2013-03-01
_delivered => (string) 120.00
_transactions => (string) 122.00
_created => (string) 2013-03-06 12:42:13
_id => (string) 79
_plazaname => (string) SPO Kraj...
in your saveAction() $this->view->result gets overwritten after if/else statement since your function does not return anything after (initially) setting $this->view->result.
Furthermore setting the first Saving error seems to be needless.
Try this:
public function saveAction()
{
$plazaid = (int) $this->getRequest()->getParam('plaza');
$date = (string) $this->getRequest()->getParam('date');
$delivered = (string) $this->getRequest()->getParam('delivered');
$transactions = (string) $this->getRequest()->getParam('transactions');
$kpr1data = new Application_Model_Kpr1Data();
if ($plazaid && $date) {
$kpr1datamapper = new Application_Model_Kpr1DataMapper();
if($kpr1datamapper->findDatePlaza($date, $plazaid, $kpr1data)){
$kpr1data->setDelivered($delivered)
->setTransactions($transactions);
$kpr1datamapper->save($kpr1data);
$this->_helper->layout->disableLayout();
$this->view->result = json_encode(array("success"=>"true"));
} else {
$kpr1data->setDate($date);
$kpr1data->setDelivered($delivered);
$kpr1data->setTransactions($transactions);
$kpr1data->setPlaza($plazaid);
$kpr1datamapper->save($kpr1data);
$this->_helper->layout->disableLayout();
$this->view->result = json_encode(array("success"=>"true"));
}
} else {
$this->_helper->layout->disableLayout();
$this->view->result = json_encode(array(
//"success"=>"false",
"errorMsg"=>"Saving error"
));
}
return true;
}
EDIT:
Try this as your save action:
public function save(Application_Model_Kpr1Data $kpr1data){
$table = $this->getdbTable();
if ($id == $kpr1data->getId()) {
$data = array('id' => (int) $id,
'kpr1_plaza_id' => (int) $kpr1data->getPlaza(),
'kpr1_data' => new Zend_Db_Expr("STR_TO_DATE('".$kpr1data->getDate()."', '%Y-%m-%d')"),
'kpr1_money_delivered' => (float) $kpr1data->getDelivered(),
'kpr1_money_transactions' => (float) $kpr1data->getTransactions(),
'kpr1_created' => new Zend_Db_Expr('CURDATE()')
);
$table->update($data, array('id => ?', $id));
} else {
[...]
$table->insert($data);
}
}

Magento and salesforce integration to create opportunity as closed won inside salesfore once order become complete in magento store

I had implemented a salesforce integration with magento orders. To achieve this , i had followed the steps given below. I am doing something wrong in 4th step while inserting salesforce_company_id and salesforce_contact_id in user account.
1)Add custom option 'closed' in admin to make any order complete.
public function massCompleteAction(){
$orderIds = $this->getRequest()->getPost('order_ids', array());
$countCompleteOrder = 0;
foreach ($orderIds as $orderId) {
$order = Mage::getModel('sales/order')->load($orderId);
if ($order->canComplete()) {
$order->complete()->save();
$countCompleteOrder++;
}
}
if ($countCompleteOrder>0) {
$this->_getSession()->addSuccess($this->__('%s order(s) successfully put on complete', $countCompleteOrder));
}else {
// selected orders is not available for hold
}
$this->_redirect('*/*/');
}
2)Add two additional fields for user account, Salesforce Company and Salesforce Contact.
I had followed following link http://www.excellencemagentoblog.com/customer-registration-fields-magento1-6
3)Create a custom reseller registration form that will create a simple user in magento
public function createResellerAction()
{
$params = $this->getRequest()->getParams();
$customer = Mage::getModel('customer/customer');
$password = $params["password"];
$email = $params["email"];
$customer->setWebsiteId(Mage::app()->getWebsite()->getId());
$customer->loadByEmail($email);
//Zend_Debug::dump($customer->debug()); exit;
if(!$customer->getId()) {
$customer->setEmail($email);
$customer->setFirstname($params["firstname"]);
$customer->setLastname($params["lastname"]);
$customer->setPassword($password);
try {
$customer->save();
$customer->setConfirmation(null);
$customer->save();
Mage::getSingleton('customer/session')->loginById($customer->getId());
}
catch (Exception $ex) {
//Zend_Debug::dump($ex->getMessage());
}
$_custom_address = array (
'firstname' => $params["firstname"],
'lastname' => $params["lastname"],
'street' => array (
'0' => $params["add1"],
'1' => $params["add2"],
),
'city' => $params["city"],
'region_id' => '',
'region' => '',
'postcode' => $params["zipcode"],
'country_id' => '', /* Croatia */
'telephone' => $params["phone"],
);
$customAddress = Mage::getModel('customer/address');
$customAddress->setData($_custom_address)
->setCustomerId($customer->getId())
->setIsDefaultBilling('1')
->setIsDefaultShipping('1')
->setSaveInAddressBook('1');
try {
$customAddress->save();
}
catch (Exception $ex) {
//Zend_Debug::dump($ex->getMessage());
}
4) Create company and contact in salesforce during reseller action
$sObject1 = new stdclass();
$sObject1->Name = $params["company"];
$createResponse1 = $mySforceConnection->create(array($sObject1), 'Account');
foreach ($createResponse1 as $createResult1) {
$compid = $createResult1->id;
}
$sObject3 = new stdclass();
$sObject3->FirstName = $params["firstname"];
$sObject3->LastName = $params["lastname"];
$sObject3->Email = $params["email"];
$sObject3->AccountId = $compid;
$createResponse2 = $mySforceConnection->create(array($sObject3), 'Contact');
foreach ($createResponse2 as $createResult2) {
$contid = $createResult2->id;
}
$saledata = array (
'salesforce_company_id' => $compid,
'salesforce_contact_id' => $contid,
);
$customersale = Mage::getModel('customer/customer');
$customersale->setWebsiteId(Mage::app()->getWebsite()->getId());
$customersale->loadByEmail($email);
//Zend_Debug::dump($customer->debug()); exit;
if($customersale->getId()) {
$customersale->setData($saledata);
try {
$customersale->save();
$customersale->setConfirmation(null);
$customersale->save();
}
catch (Exception $ex) {
$message = $this->__($customer);
//Zend_Debug::dump($ex->getMessage());
Mage::getSingleton('core/session')->addError($message);
}
}
Please check the code where i am wrong at the bottem of 4th step
$saledata = array (
'salesforce_company_id' => $compid,
'salesforce_contact_id' => $contid,
);
$customersale = Mage::getModel('customer/customer');
$customersale->setWebsiteId(Mage::app()->getWebsite()->getId());
$customersale->loadByEmail($email);
//Zend_Debug::dump($customer->debug()); exit;
if($customersale->getId()) {
$customersale->setData($saledata);
try {
$customersale->save();
$customersale->setConfirmation(null);
$customersale->save();
}
catch (Exception $ex) {
$message = $this->__($customer);
//Zend_Debug::dump($ex->getMessage());
Mage::getSingleton('core/session')->addError($message);
}
}
I await your responses.
There is a great extension for magento which does that all for you and even more: https://products.crunchyconsulting.com/crunchy-products/crunchy-magforce.html
Take a look at help & docs tab where you can find even movies with use case scenarios
https://www.youtube.com/watch?v=TjxvjGcAGqY
https://www.youtube.com/watch?v=cmf4Ksv3uRM

Yii form model validation- either one is required

I have two fields on the form ( forgotpassword form ) username and email Id . User should enter one of them . I mean to retrieve the password user can enter user name or the email id . Could some one point me the validation rule for this ?
Is there any inbuilt rule I can use ?
( Sorry if it is already discussed or if I missed)
Thanks for your help
Regards
Kiran
I was trying to solve same problem today. What I've got is the code below.
public function rules()
{
return array(
// array('username, email', 'required'), // Remove these fields from required!!
array('email', 'email'),
array('username, email', 'my_equired'), // do it below any validation of username and email field
);
}
public function my_required($attribute_name, $params)
{
if (empty($this->username)
&& empty($this->email)
) {
$this->addError($attribute_name, Yii::t('user', 'At least 1 of the field must be filled up properly'));
return false;
}
return true;
}
General idea is to move 'required' validation to custom my_required() method which can check if any of field is filled up.
I see this post is from 2011 however I couldn't find any other solution for it. I Hope it will work for you or other in the future.
Enjoy.
Something like this is a bit more generic and can be reused.
public function rules() {
return array(
array('username','either','other'=>'email'),
);
}
public function either($attribute_name, $params)
{
$field1 = $this->getAttributeLabel($attribute_name);
$field2 = $this->getAttributeLabel($params['other']);
if (empty($this->$attribute_name) && empty($this->$params['other'])) {
$this->addError($attribute_name, Yii::t('user', "either {$field1} or {$field2} is required."));
return false;
}
return true;
}
Yii2
namespace common\components;
use yii\validators\Validator;
class EitherValidator extends Validator
{
/**
* #inheritdoc
*/
public function validateAttributes($model, $attributes = null)
{
$labels = [];
$values = [];
$attributes = $this->attributes;
foreach($attributes as $attribute) {
$labels[] = $model->getAttributeLabel($attribute);
if(!empty($model->$attribute)) {
$values[] = $model->$attribute;
}
}
if (empty($values)) {
$labels = '«' . implode('» or «', $labels) . '»';
foreach($attributes as $attribute) {
$this->addError($model, $attribute, "Fill {$labels}.");
}
return false;
}
return true;
}
}
in model:
public function rules()
{
return [
[['attribute1', 'attribute2', 'attribute3', ...], EitherValidator::className()],
];
}
I don't think there is a predefined rule that would work in that case, but it would be easy enough to define your own where for username and password fields the rule was "if empty($username . $password) { return error }" - you might want to check for a min length or other field-level requirements as well.
This works for me:
['clientGroupId', 'required', 'when' => function($model) {
return empty($model->clientId);
}, 'message' => 'Client group or client selection is required'],
You can use private property inside model class for preventing displays errors two times (do not assign error to model's attribute, but only add to model without specifying it):
class CustomModel extends CFormModel
{
public $username;
public $email;
private $_addOtherOneOfTwoValidationError = true;
public function rules()
{
return array(
array('username, email', 'requiredOneOfTwo'),
);
}
public function requiredOneOfTwo($attribute, $params)
{
if(empty($this->username) && empty($this->email))
{
// if error is not already added to model, add it!
if($this->_addOtherOneOfTwoValidationError)
{
$this->addErrors(array('Please enter your username or emailId.'));
// after first error adding, make error addition impossible
$this->_addOtherOneOfTwoValidationError = false;
}
return false;
}
return true;
}
}
don't forget "skipOnEmpty" attr. It cost me some hours.
protected function customRules()
{
return [
[['name', 'surname', 'phone'], 'compositeRequired', 'skipOnEmpty' => false,],
];
}
public function compositeRequired($attribute_name, $params)
{
if (empty($this->name)
&& empty($this->surname)
&& empty($this->phone)
) {
$this->addError($attribute_name, Yii::t('error', 'At least 1 of the field must be filled up properly'));
return false;
}
return true;
}
Yii 1
It can be optimized of course but may help someone
class OneOfThemRequiredValidator extends \CValidator
{
public function validateAttribute($object, $attribute)
{
$all_empty = true;
foreach($this->attributes as $_attribute) {
if (!$this->isEmpty($object->{$_attribute})) {
$all_empty = false;
break;
}
}
if ($all_empty) {
$message = "Either of the following attributes are required: ";
$attributes_labels = array_map(function($a) use ($object) {
return $object->getAttributeLabel($a);
}, $this->attributes);
$this->addError($object, $_attribute, $message . implode(',',
$attributes_labels));
}
}
}
yii1
public function rules(): array
{
return [
[
'id', // attribute for error
'requiredOneOf', // validator func
'id', // to params array
'name', // to params array
],
];
}
public function requiredOneOf($attribute, $params): void
{
$arr = array_filter($params, function ($key) {
return isset($this->$key);
});
if (empty($arr)) {
$this->addError(
$attribute,
Yii::t('yii', 'Required one of: [{attributes}]', [
'{attributes}' => implode(', ', $params),
])
);
}
}