Save multiple records based on user input in Cakephp - php

What I'm using:
cakephp version 2.4.1
What I have:
table channel_settings with attributes (id, mask_id, provider_id, servicetype_id, channel_id, created, modified)
table channel_alert_defaults with attributes (id, provider_id, servicetype_id, channel_id)
In page add new channel_setting user can insert each provider to each servicetype to it's channel.
Now what I need is when user choose servicetype to --Any-- then besides this one record, there will be some multiple insert into database for some servicetype because some servicetype need different channel. Amount of multiple insert depent on how many a provider has servicetype setting and channel in table channel_alert_defaults
Here's existing system:
What I want now:
Here's what I'm trying, but I still don't get any idea how multiple insert code is
public function add() {
if ($this->request->is('post')) {
Controller::loadModel('Servicetype');
$this->Servicetype->recursive = -1;
$servicetype = $this->Servicetype->find('all');
$this->request->data['ChannelSetting']['mask_id'] = $this->Session->read('current_mask_id');
$maskid = $this->request->data['ChannelSetting']['mask_id'];
$providerid = $this->request->data['ChannelSetting']['provider_id'];
$servicetypeid = $this->request->data['ChannelSetting']['servicetype_id'];
$this->ChannelSetting->create();
if ($this->request->data['ChannelSetting']['servicetype_id'] == 0) {
Controller::loadModel('ChannelAlertDefaults');
$this->ChannelAlertDefault->recursive = -1;
$channelalertdefault = $this->ChannelAlertDefaults->findByProviderId($providerid);
// loop insert goes here, I think...
if ($this->ChannelSetting->save($this->request->data)) {
$this->Session->setFlash(__('The channel setting has been saved'), 'success');
return $this->redirect(array('action' => 'add'));
}
else {
$this->Session->setFlash(__('The channel setting failed to save'));
}
} else {
if ($this->ChannelSetting->save($this->request->data)) {
$this->Session->setFlash(__('The channel setting has been saved'), 'success');
return $this->redirect(array('action' => 'add'));
}
else {
$this->Session->setFlash(__('The channel setting failed to save'));
}
}
if ($this->ChannelSetting->save($this->request->data)) {
$this->Session->setFlash(__('The channel setting has been saved'), 'success');
return $this->redirect(array('action' => 'add'));
}
else {
$this->Session->setFlash(__('The channel setting failed to save'));
}
}
}
PS: why I want this? So that I don't have to insert data one by one for each provider. Thank you

I can't test now but maybe you can try something like this:
$data = array(
[0] => array(
'MASK' => $this->request->data['ChannelSetting']['mask_id'],
'PROVIDER' => $this->request->data['ChannelSetting']['provider_id'],
'SERVICE_TYPE' => *all*
),
[1] => array(
'MASK' => $this->request->data['ChannelSetting']['mask_id'],
'PROVIDER' => $this->request->data['ChannelSetting']['provider_id'],
'SERVICE_TYPE' => *otp*
),
[2] => array(
'MASK' => $this->request->data['ChannelSetting']['mask_id'],
'PROVIDER' => $this->request->data['ChannelSetting']['provider_id'],
'SERVICE_TYPE' => *httpalert*
)
);
$this->ChannelSetting->saveAll($data, array('deep' => true));

#Javi thank you for give me inspiration on how I should solve the problem.
What I've done:
1. count how many data from table channel_alert_defaults than correspondent to provider_id from user input
2. Make a loop insert into table channel_setting using saveAll
Here is my code:
Controller::loadModel('ChannelAlertDefault');
$this->ChannelAlertDefault->recursive = 1;
$channelalertdefault = $this->ChannelAlertDefault->findAllByProviderId($providerid);
$amount = count($channelalertdefault); // to count how many array
// Here is the loop...
if ($this->ChannelSetting->save($this->request->data)) {
for($i=0;$i<$amount;$i++) {
$this->request->data['ChannelSetting']['mask_id'] = $this->Session->read('current_mask_id');
$this->request->data['ChannelSetting']['provider_id'] = $channelalertdefault[$i]['ChannelAlertDefault']['provider_id'];
$this->request->data['ChannelSetting']['servicetype_id'] = $channelalertdefault[$i]['ChannelAlertDefault']['servicetype_id'];
$this->request->data['ChannelSetting']['channel_id'] = $channelalertdefault[$i]['ChannelAlertDefault']['channel_id'];
$this->ChannelSetting->saveAll($this->request->data);
}

Related

How to add and update in one api in laravel

I am trying to add and update using the same API, currently, I can add but I am not clear about how to update using the same API.
I am adding folders against id and my body response looks like this:
{
"id": "2",
"folder_detail": [1,3,4]
}
I can add folders with id 1,3 and 4 against id 2 but next time when I hit the same API with folder[1,3,5] it should update folders details not should add again, I can do that by making separate API but I want to do that in one API.
My Controller code:
try {
$folder = Doctor::where('id', $request->get('id'))->first();
$folder->doctor()->attach($request->get('folder_detail', []));
DB::commit();
return response([
'status' => true,
'message' => 'Folder detail added',
], 200);
} catch (\Exception $ex) {
DB::rollback();
return response([
'status' => false,
'message' => __('messages.validation_errors'),
'errors' => $ex->getMessage(),
], 500);
}
}
public function doctor()
{
return $this->belongsToMany('App\Folder', 'folder_details');
}
Your help will be highly appreciated?
Okay so after our back and forth in the comments I think you are looking for something like this:
$folders = $request->get('folder_detail', []);
foreach($folders as $folder) {
$record = Folder::firstOrNew(['id', $folder]);
$record->doctor_id = $request->id;
// You can add your own records here, or use the 'fill' function
}
So, this way, you loop through all your folders. Check if the folder with the specific ID already exists, if it does not, it creates a new one. The doctor is linked through the doctor_id on your record.
Find record if exist then update otherwise create
$post = $request->all();
$doctor = Doctor::find($post['id']);
if($doctor){
$doctor->update([
//your data for update doctor model
]);
//remove old folders which is related with this doctor
Folder::where('doctor_id', $doctor->id)->delete();
//add current data of folder
if(!empty($post['folder_detail'])){
foreach($post['folder_detail'] as $folder){
Folder::create([
'doctor_id' => $doctor->id,
'folder_detail' => $folder
]);
}
}
//return your response here
} else {
$doctor = Doctor::create([
//data for create doctore
]);
//add current data of folder
if(!empty($post['folder_detail'])){
foreach($post['folder_detail'] as $folder){
Folder::create([
'doctor_id' => $doctor->id,
'folder_detail' => $folder
]);
}
}
//return your response here
}

How to insert data in 2 table

i have 2 tables 'userlogin' and 'user' and then 1 have a form which is 1 form inserting into 2 tables, so far i manage to insert the data but when it has to do with "primary key" and "foreign key" it has problem, as u can see from code below id_login from table userlogin is a primary key and id_login from table user is a foreign key the problem is when i inserting the data, id_login from userlogin has it value while in table user it has no value, below are my code, is there any simple way or am i doing something wrong?
Controller
function add()
{
$this->form_validation->set_rules('nama','Nama Lengkap','required');
$this->form_validation->set_rules('username','Username','required');
$this->form_validation->set_rules('password','Password','required');
$this->form_validation->set_rules('jenis_user','Jenis User','required');
$this->form_validation->set_rules('alamat','alamat','required');
$this->form_validation->set_rules('hp','hp','required');
$this->form_validation->set_rules('email','email','required');
if($this->form_validation->run()==TRUE)
{
$username=$this->input->post('username',TRUE);
$params = array(
'nama' => $this->input->post('nama',TRUE),
'username' => $this->input->post('nama',TRUE),
'password' => md5($this->input->post('password',TRUE)),
'jenis_user' => $this->input->post('jenis_user',TRUE),
'alamat' => $this->input->post('alamat',TRUE),
'hp' => $this->input->post('hp',TRUE),
'email' => $this->input->post('email',TRUE),
);
if($this->Admin_model->cek_username($username)){
if($this->Admin_model->user_daftar($username,$params))
{
set_header_message('success','Tambah Pengguna','Berhasil menambahkan pengguna');
redirect(base_url(akses().'/pengguna'));
} else {
set_header_message('danger','Tambah Pengguna','Gagal menambahkan pengguna');
redirect(base_url(akses().'/pengguna/add'));
}
} else {
set_header_message('danger','Oops.. Maaf','Username sudah ada yang menggunakan');
redirect(base_url(akses().'/pengguna/add'));
}
} else {
$meta['judul']="Tambah Pengguna";
$this->load->view('tema/header',$meta);
$d['jenis_user']=$this->Admin_model->user_akses_data();
$this->load->view(akses().'/pengguna/penggunaadd',$d);
$this->load->view('tema/footer');
}
}
Model
function user_daftar($username,$params)
{
if($this->db->insert('userlogin', $params)) {
return true;
} else{
return false;
}
}
thank you
Use two different arrays and two different functions in model to insert different data in two different tables.
I think following code will work, if same data for both tables otherwise you need to make two arrays.
function user_daftar($username,$params)
{
if($this->db->insert("userlogin", $params)) {
$id_login=$this->db->insert_id(); // user login id
$params["id_login"]=$id_login;
$this->db->insert("user", $params);
return true;
} else{
return false;
}
}
first separate the data if based on Table attribute then pass two the model
$params = array(
'nama' => $this->input->post('nama',TRUE),
'username' => $this->input->post('nama',TRUE),
'password' => md5($this->input->post('password',TRUE)),
);
$params2 = array(
'jenis_user' => $this->input->post('jenis_user',TRUE),
'alamat' => $this->input->post('alamat',TRUE),
'hp' => $this->input->post('hp',TRUE),
'email' => $this->input->post('email',TRUE),
);
$this->Admin_model->modelXXX($$params1,$params2)
one function on the model side with two param but one thing you have to consider that first, insert a data to the reference table $id_login=$this->db->insert_id(); then insert the second table
function modelXXX($params1,$params2)
{
if($this->db->insert("userlogin", $params1)) {
$id_login=$this->db->insert_id(); // user login id
$params["id_login"]=$id_login;
$this->db->insert("user", $params2);
return true;
} else{
return false;
}
}

cakephp 2.x edit field for comparing old and new records

Question : I want to compare the different records before and after edit.
1) i find that it will generate different id to get the corresponding fields ***** $this->set( compact('brands', 'imageTypes')); *****
and auto write into view's fields. But how can i get all input field names ( I want to auto find all the fields record by these two id automatically in case there are some fields change in the future. )
Controller :
function admin_edit(){
$this->BrandImage->id = $id;
if (!$this->BrandImage->exists($id)) {
throw new NotFoundException(__('Invalid brand image'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->BrandImage->save($this->request->data)) {
// $this->Session->setFlash(__('The brand image has been saved'), 'flash/success');
// $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The brand image could not be saved. Please, try again.'), 'flash/error');
}
} else {
$options = array('conditions' => array('BrandImage.' . $this->BrandImage->primaryKey => $id));
$this->request->data = $this->BrandImage->find('first', $options);
debug( $this->request->data['BrandImage']['path']);
}
$brands = $this->BrandImage->Brand->find('list');
$imageTypes = $this->BrandImage->ImageType->find('list');
$this->set( compact('brands', 'imageTypes'));
}

How to set multi select value from array object in yii2 while updating

I have table which have multiple reference to ohter tables like
user
id name email
categories
id title
user_categories
user_id category_id
Here a user will have multiple category associated with him/her
I am able to save these successfully with new records like following
View File:
echo $form->field($package_categories, 'category_id')->dropDownList( ArrayHelper::map(
StudyMaterialCategories::find()->all(), 'id', 'title'),
['multiple' => true]
);
Save New record:
$model = new Packages();
$package_categories = new PackageCategories();
$request = Yii::$app->request;
if ($request->isPost) {
$transaction = Yii::$app->db->beginTransaction();
try {
$post = $request->post();
$model->load($post);
$model->save();
foreach ($post['PackageCategories']['category_id'] as $key => $value) {
$package_categories = new PackageCategories();
$package_categories->category_id = $value;
$package_categories->package_id = $model->id;
$package_categories->save();
}
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
} catch (Exception $ex) {
$transaction->rolback();
Yii::$app->session->setFlash("error", $ex->getMessage());
}
}
Till now It's running successfully.
But I'm stuck when going to update the table. The problem part is dropdown list. How to set multiple selected option as per database if I'm coming with array of object.
Have a look on the following code
$package_categories = PackageCategories::find()
->where('package_id=:package_id', ['package_id' => $id])->all();
if (count($package_categories) < 1) {
$package_categories = new PackageCategories();
}
$request = Yii::$app->request;
if ($request->isPost) {
$transaction = Yii::$app->db->beginTransaction();
try {
$post = $request->post();
$model->load($post);
$model->save();
$package_categories = new PackageCategories();
$package_categories->deleteAll(
"package_id=:package_id",
[':package_id' => $model->id]
);
foreach ($post['PackageCategories']['category_id'] as $key => $value) {
$package_categories = new PackageCategories();
$package_categories->category_id = $value;
$package_categories->package_id = $model->id;
$package_categories->save();
}
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
} catch (Exception $ex) {
$transaction->rolback();
Yii::$app->session->setFlash("error", $ex->getMessage());
}
}
if I try to get first object of the array $package_categories of only able to set selected one option
This is an example code of a model class Permit which has a many to many relationship with Activity through PermitActivity (pivot table model).
Model Class Activity
public class Permit extends \yii\db\ActiveRecord {
public $activities_ids;
...
public function rules() {
return [
...
[['activities_ids'], 'safe'],
...
];
}
...
// Method called after record is saved, be it insert or update.
public function afterSave($insert, $changedAttributes) {
// If this is not a new record, unlink all records related through relationship 'activities'
if(!$this->isNewRecord) {
// We unlink all related records from the 'activities' relationship.
$this->unlinkAll('activities', true);
// NOTE: because this is a many to many relationship, we send 'true' as second parameter
// so the records in the pivot table are deleted. However on a one to many relationship
// if we send true, this method will delete the records on the related table. Because of this,
// send false on one to many relationships if you don't want the related records deleted.
}
foreach($this->activities_ids as $activity_id) {
// Find and link every model from the array of ids we got from the user.
$activity = Activity::findOne($activity_id);
$this->link('activities', $activity);
}
parent::afterSave($insert, $changedAttributes);
}
...
// Declare relationship with Activity through the pivot table permitActivity
public function getActivities(){
return $this->hasMany(Activitiy::className(), ['id' => 'activity_id'])
->viaTable('permitActivity',['permit_id' => 'id']);
}
...
public function afterFind(){
parent::afterFind();
$this->activities_id = ArrayHelper::getColumn($this->activities, 'id');
}
}
This way the model class is the one responsible for creating and updating the relationship using the pivot table.
The most important thing is to have the relationship method declared correctly.
Edit
This is an example of the view using kartikv\widgets\Select2. I don't really know if dropDownList supports multiple select, however Select2 has so many useful features i usually use it over other options.
echo $form->field($model, 'activities')->widget(Select2::classname(), [
'data' => $data,
'options' => [
'placeholder' => '...'
],
'pluginOptions' => [
'allowClear' => true,
'multiple' => true,
],
]);

Show data only to selected user in Quiz activity

I am using Moodle 2.7 and in the Quiz activity there is the overview page for all attempts of the learners.
The table is under mymoodle/mod/quiz/report.php?id=50&mode=overview
Right now only admin users or users with the capability 'mod/quiz:viewreports' can see the table.
How to add users, without using any capability, who will be able to see this report?
Right now every user, without the capability gets the error from report.php:
$reportlist = quiz_report_list($context);
if (empty($reportlist) !totara_is_manager($userid)) {
print_error('erroraccessingreport', 'quiz');
}
// Validate the requested report name.
if ($mode == '') {
// Default to first accessible report and redirect.
$url->param('mode', reset($reportlist));
redirect($url);
} else if (!in_array($mode, $reportlist)) {
print_error('erroraccessingreport', 'quiz');
}
if (!is_readable("report/$mode/report.php")) {
print_error('reportnotfound', 'quiz', '', $mode);
}
The table function is under reportlib.php:
function quiz_report_list($context) {
global $DB;
static $reportlist = null;
if (!is_null($reportlist)) {
return $reportlist;
}
$reports = $DB->get_records('quiz_reports', null, 'displayorder DESC', 'name, capability');
$reportdirs = core_component::get_plugin_list('quiz');
// Order the reports tab in descending order of displayorder.
$reportcaps = array();
foreach ($reports as $key => $report) {
if (array_key_exists($report->name, $reportdirs)) {
$reportcaps[$report->name] = $report->capability;
}
}
// Add any other reports, which are on disc but not in the DB, on the end.
foreach ($reportdirs as $reportname => $notused) {
if (!isset($reportcaps[$reportname])) {
$reportcaps[$reportname] = null;
}
}
$reportlist = array();
foreach ($reportcaps as $name => $capability) {
if (empty($capability)) {
$capability = 'mod/quiz:viewreports';
}
if (has_capability($capability, $context)) {
$reportlist[] = $name;
}
}
return $reportlist;
}
I want to add designated people by their id, who will act as managers.
If you want to completely bypass the capabilities' mechanism for viewing reports, then you could always comment the array values in access.php corresponding to the key 'mod/quiz:viewreports'. In other words, you can go to /mod/quiz/db/access.php and substitute
// View the quiz reports.
'mod/quiz:viewreports' => array(
'riskbitmask' => RISK_PERSONAL,
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'teacher' => CAP_ALLOW,
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
)
),
with
// View the quiz reports.
'mod/quiz:viewreports' => array(
// 'riskbitmask' => RISK_PERSONAL,
// 'captype' => 'read',
// 'contextlevel' => CONTEXT_MODULE,
// 'archetypes' => array(
// 'teacher' => CAP_ALLOW,
// 'editingteacher' => CAP_ALLOW,
// 'manager' => CAP_ALLOW
)
),
or, alternatively, you can tune or turn on the entries according to your necessities. For more information see:
https://docs.moodle.org/dev/Access_API
Then you can
check the ID of the current user ($USER->id) and
write some custom function to decide if this user can or cannot see the report.
Note: I would not bypass the capabilities mechanism, though, because it is reliable and safe. You could however tune it in order to allow only user groups defined by you.

Categories