I created a transaction like this :
$this->db->begin();
$topic = new Topic();
$topic->assign( $data );
$topic->save();
var_dump( $this->db->isUnderTransaction() ); // bool(true)
$this->db->rollback();
var_dump( $this->db->isUnderTransaction() ); // bool(false)
But, the database still changed and inserted a new line. The rollback method is not working.
$di->set method will only be shared if been called with the second parameter is "TRUE".
$di->set( 'db', function() use( $conf ) {
return new DbAdapter( [
'host' => $conf->db->host,
'username' => $conf->db->username,
'password' => $conf->db->password,
'dbname' => $conf->db->dbname,
'options' => [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_PERSISTENT => true
]
] );
}, true );
Related
I'm trying to implement a multiple models form using the form-wizard widget, with Profile as main model and few others as linked ones. When I select the entity type field for the main model, I would like to change the linked model for the next step, basing on the value of entity type field.
I have tried with this code:
Create Form Code
$modelUrlReletedModelsCreate = Profile::urlRelatedModelCreate();
$urlLinkedProfile = Url::to(['create']);
echo FormWizard::widget([
'formOptions'=>[
'id'=>'profile_form',
'enableClientValidation'=>true,
'enableAjaxValidation'=>true,
'validationUrl' => Url::to(['profile-models-validation'])
],
'theme' => FormWizard::THEME_MATERIAL_V,
'steps' => [
//step 1
[
'model' => $model,
'title' => \Yii::t('app', 'Profile'),
'fieldConfig' => [
'only' => ['entity_type_id', 'profile_type_id'],
'entity_type_id' => [
'widget' => Select2::class,
'options' => [
'data' => EntityType::arrayNamesList(),
'options' => ['placeholder' => \Yii::t('app','Select an element')],
'pluginEvents' => ['select2:select'=>'function(e){;'
. 'var type = $("#pr-ty-sel").val();'
. 'var profile= "'.($model->profile_id ? : "no").'";'
. '$.ajax({ method: "GET",'
. 'url:"'.$urlLinkedProfile.'",'
. 'data:{ entity_text : e.params.data.text,'
. 'entity_id : e.params.data.id,'
. 'profile_type_id : type,'
. 'profile_id : profile},'
. 'success: function(data){'
. '$("#profile_form").html(data);'
. '}'
. '});}'],
],
],
'profile_type_id' =>[
'widget' => Select2::class,
'options' => [
'data' => \app\models\ProfileType::arrayNamesList(),
'options' => ['placeholder' => \Yii::t('app','Select an element'),'id'=>'pr-ty-sel'],
],
]
],
'description' => \Yii::t('app', 'Add Profile Type Data'),
'formInfoText' => \Yii::t('app', 'Fill all fields'),
],
//step 2 I want ot change here $linkedModel
[
'model' => [$model,$linkedModel],
'title' => \Yii::t('app', 'Personal Data'),
'description' => \Yii::t('app', 'Insert Personal Data'),
],
]
]);
Controller Action Create Code
public function actionCreate($profileId = NULL)
{
if($profileId AND $profileId !== 'no'){
$model = $this->findModel($profileId);
}else{
$model = new Profile();
}
$profileLinkedModel = new ProfilePrivate();
$renderMethod = 'render';
if (Yii::$app->request->isAjax) {
$entityText = \Yii::$app->request->get('entity_text');
$entity_id = \Yii::$app->request->get('entity_id');
$profileTypeId = \Yii::$app->request->get('profile_type_id');
$profileId = \Yii::$app->request->get('profile_id');
//Utility function to clean the entity text (remove number and special characters)
$entityTextCleaned = \app\components\Utility::cleanString($entityText);
if ($entityTextCleaned == 'private') {
$profileLinkedModel = new ProfilePrivate();
} elseif ($entityText == 'company') {
$profileLinkedModel = new ProfileCompany();
} else {
//#TODO
return FALSE;
}
$model->entity_type_id = $entity_id;
$model->profile_type_id = $profileTypeId;
$profileLinkedModel->profile_id = $model->profile_id;
Yii::$app->response->format = Response::FORMAT_JSON;
$renderMethod = 'renderAjax';
}
//extra table field used to enable custom rule in model
$model->createFullProfile = TRUE;
if ($model->load(Yii::$app->request->post())) {
return $this->redirect(['view', 'id' => $model->profile_id]);
}
return $this->$renderMethod('create', [
'model' => $model,
'profileLinkedModel' => $profileLinkedModel,
]);
}
When I select a field for entity type field, the server runs the ajax request on select event, but when it ends the other form field is not more selectable. So, in other words, after the ajax request I'm unable to select the profile type field. If I try to select the profile type field before the entity type field I can go to next step, but load always the default model.
I am trying to call a custom action by ajax, but the response returned is 404, I am pretty sure its a routing issue, but I can't figure how to solve it.
here is my code:
action
public function actionGetOne($id){
$model = Driver::findOne($id);
if(!empty($model)){
$data = [];
$row = [
'id'=>$model->id,
'full_name'=>$model->full_name,
'email'=>$model->email,
'nationality_id'=>$model->nationality_id,
'current_location'=>$model->current_location,
'medical_check_id'=>$model->medical_check_id,
'img'=>$model->img,
'current_fleet_id'=>$model->current_fleet_id,
'availability'=>$model->availability
];
$data[] = $row;
echo json_encode(['driver-getOne'=>'success','data'=>$data]);
} else{
echo json_encode(['driver-getOne'=>'failure']);
}
}
ajax
$.ajax({
url:'<?= urldecode(Url::toRoute(['driver/get-one'])); ?>?id=<?= $id; ?>',
method:'post',
dataType:'json',
success:function(response){}
error:function(){
alert('target action is not found!');
}
}
backend/config/params.php
<?php
return [
'adminEmail' => 'admin#example.com',
'urlRules' => [
'' => 'site/index',
'login/' => 'site/login',
'signup/' => 'site/signup',
'<controller:[\w-]+>/<action:\w+>' => '<controller>/<action>',
'<controller:[\w-]+>/<action:\w+>/<id:\d+>' => '<controller>/<action>',
'<controller:[\w-]+>/<id:\d+>' => '<controller>/view',
'<controller:[\w-]+>/create' => '<controller>/create',
'<controller:[\w-]+>/update/<id:\d+>' => '<controller>/update',
'<controller:[\w-]+>/delete/<id:\d+>' => '<controller>/delete',
'<controller:[\w-]+>/get-all' => '<controller>/get-all',
'<controller:[\w-]+>/get-one' => '<controller>/get-one',
'<controller:[\w-]+>/update-status' => '<controller>/update-status',
]
];
Change few things and try again.
Action:
public function actionGetOne($id)
{
\Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
$model = Driver::findOne($id);
if (empty($model)) {
return ['driver-getOne' => 'failure'];
}
return [
'driver-getOne' => 'success',
'data' => [[
'id' => $model->id,
'full_name' => $model->full_name,
'email' => $model->email,
'nationality_id' => $model->nationality_id,
'current_location' => $model->current_location,
'medical_check_id' => $model->medical_check_id,
'img' => $model->img,
'current_fleet_id' => $model->current_fleet_id,
'availability' => $model->availability
]],
];
}
Action should return something to properly finish response sequence otherwise unwanted things can happen. By setting response format you can get JSON encoded array automatically.
AJAX:
$.ajax({
url:'<?= Url::to(['driver/get-one', 'id' => $id]) ?>',
method:'post',
dataType:'json',
success:function(response){}
error:function(){
alert('target action is not found!');
}
}
Get your URL using proper syntax.
Params:
'urlRules' => [
'' => 'site/index',
'login' => 'site/login',
'signup' => 'site/signup',
'<controller:[\w-]+>/<id:\d+>' => '<controller>/view',
'<controller:[\w-]+>/<action:[\w-]+>/<id:\d+>' => '<controller>/<action>',
'<controller:[\w-]+>/<action:[\w-]+>' => '<controller>/<action>',
]
I'm assuming you are passing urlRules to components > urlManager > rules otherwise URL rules won't work.
I removed redundant rules. In general add general rules last and specific rules first.
Okay I have been to almost all threads but I couldn't find the answer what I want.
Controller: RegistersController
namespace App\Controller;
use App\Controller\AppController;
use Cake\Auth\DefaultPasswordHasher;
use Cake\Event\Event;
use Cake\Mailer\Email;
use Cake\Routing\Router;
class RegistersController extends AppController
{
public function add()
{
$this->loadModel('Tbusers');
$tbusers = $this->Tbusers->newEntity();
if ($this->request->is('post'))
{
$tbusers = $this->Tbusers->patchEntity($tbusers, $this->request->data);
if ($this->Tbusers->save($tbusers)) {
$this->Flash->success(__('Yayie! You have been registered.'));
$baseurl = Router::url('/', true);
$email = base64_encode($this->request->data['email']);
$first_name = $this->request->data['fname'];
$last_name = $this->request->data['lname'];
$username = $first_name.' '.$last_name;
//$confirmation_link = $baseurl.'users/confirm/'.$email;
$email = new Email();
$email->template('email')
->subject('Student Portal - Signup')
->emailFormat('html')
->to($this->request->data['email'])
//->viewVars(['confirmation_link' => $confirmation_link,'username'=>$username])
->viewVars(['username'=>$username])
->from('dotnetdev555#gmail.com')
->send();
if ($email->send())
{
// Success
echo "mail sent";
}
else
{
echo "Mail not sent";
// Failure
}
return $this->redirect(['action' => 'add']);
}
}
Inside Template->Email->html I have file called
email.ctp
Hello <?php echo $username; ?>,<br/>
Thanks,<br/>
Jaymin Sejpal Founder at Student Portal
app.php
'EmailTransport' => [
'default' => [
'className' => 'Mail',
// The following keys are used in SMTP transports
'host' => 'smtp.elasticemail.com',
'port' => 2525,
'timeout' => 30,
'username' => 'dotnetdev555#gmail.com',
'password' => 'secret',
'client' => null,
'tls' => null,
'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null),
],
],
I don't know what I am missing to it. I am refferring this
http://book.cakephp.org/3.0/en/core-libraries/email.html for now.
The email host that you are using might be using smtp protocol , so in your app.php . Try editing you className parameter to 'Smtp'
'EmailTransport' => [
'default' => [
'className' => 'Smtp',
// The following keys are used in SMTP transports
'host' => 'smtp.elasticemail.com',
'port' => 2525,
'timeout' => 30,
'username' => 'dotnetdev555#gmail.com',
'password' => 'secret',
'client' => null,
'tls' => null,
'url' => env('EMAIL_TRANSPORT_DEFAULT_URL', null),
],
],
It nearly took me a whole day to resolve the problems about transactions, but I failed.
My requirement is INSERT a new record both in table topic and table topic_data in one transaction.
I have my code like this :
// database connection
$di->set( 'db', function() use( $conf ) {
return new \Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter( [
'host' => $conf->db->host,
'username' => $conf->db->username,
'password' => $conf->db->password,
'dbname' => $conf->db->dbname,
'options' => [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_PERSISTENT => true,
\PDO::ATTR_AUTOCOMMIT => false
]
] );
} );
// transaction code
public function create( $params ) {
$this->db->begin();
$id = \Idalloc::next();
$topic = new Topic();
$topic->id = $id;
$topic->ctime = $_SERVER[ 'REQUEST_TIME' ];
$tags = $params[ 'tags' ];
$params[ 'tags' ] = implode( ',', $tags );
$topic->assign( $params );
if( $topic->save() === false ) {
$this->db->rollback();
return false;
}
for( $i = 0, $l = count( $tags ); $i < $l; ++$i ) {
$topicTag = new TopicTag();
$topicTag->tag_id = $tags[ $i ];
$topicTag->topic_id = $id;
$topicTag->type = $params[ 'type' ];
if( $topicTag->save() === false ) {
$this->db->rollback();
return false;
}
}
var_dump( $this->db->isUnderTransaction() );
$this->db->commit();
return $id;
}
The fails with :
If I don't set \PDO::ATTR_PERSISTENT => true, method "create" with return $id and var_dump( $this->db->isUnderTransaction() ) is TRUE but NO DATA been inserted into both table topic and table topic_tag
If I set \PDO::ATTR_PERSISTENT => true, I will get Exception with :
[Tue, 21 Jun 16 02:16:21 +0800][ERROR] PDOException: There is no active transaction
And still failed to insert data into table topic, but new record appearing in table topic_tag.
If I only keep one of the two parts, it will be working well.
How can I resolve this problem and is there a simple way to create Manual Transactions ?
I found out the solution for this question. The 'db' set in DI must be shared. So there need another parameter "TRUE" :
// database connection
$di->set( 'db', function() use( $conf ) {
return new \Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter( [
'host' => $conf->db->host,
'username' => $conf->db->username,
'password' => $conf->db->password,
'dbname' => $conf->db->dbname,
'options' => [
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_PERSISTENT => true,
\PDO::ATTR_AUTOCOMMIT => false
]
] );
}, true );
I have a 2 DB connection, db and db2. I want to get all data from table claim in db2 connection. Below is my sql and it did not read from db2 connection. How to solved this?
$sql = "SELECT * FROM claim where provider_id = xx ";
$sql_count = "SELECT COUNT FROM ( $sql ) AS count ";
$totalCount = Yii::$app->db2->createCommand($sql_count)->queryScalar();
$dataProvider = new SqlDataProvider([
'sql' => $sql,
'totalCount' => $totalCount,
'sort' =>false,
'pagination' => [
'pageSize' => 10,
],
]);
return $dataProvider;
First you need to configure your databases like below:
return [
'components' => [
'db1' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=db1name', //maybe other dbms such as psql,...
'username' => 'db1username',
'password' => 'db1password',
],
'db2' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=db2name', //maybe other dbms such as psql,...
'username' => 'db2username',
'password' => 'db2password',
],
],
];
Then you can simply :
//to get from db1
Yii::$app->db1->createCommand((new \yii\db\Query)->select('*')->from('tbl_name'))->queryAll()
//to get from db2
Yii::$app->db2->createCommand((new \yii\db\Query)->select('*')->from('tbl_name'))->queryAll()
If you are using an active record model, in your model you can define:
public function getDb() {
return Yii::$app->db1;
}
//Or db2
public function getDb() {
return Yii::$app->db2;
}
Then:
if you have set db1 in getDb() method, result will be fetched from db1 and so on.
ModelName::find()->select('*')->all();