Pre-populate update form with data from the database - php

UPDATE:
If, in the view, I do <?php echo $customer->first_name; ?> it outputs the first-name correctly.
On the same view file 'value' => set_value($customer->first_name) outputs nothing.
I am making a "Customers" CRUD application in CodeIgniter 3. I have an update form that I want to pre-populate with the data corresponding to the customer, already existent in he database.
The model looks like this:
class Customer extends CI_Model {
/*Lots
of
code*/
public function getAllCustomers($customer_id) {
$query = $this->db->get_where('customers', array('id' => $customer_id));
if ($query->num_rows() > 0) {
return $query->row();
}
}
}
The controller looks like this:
class Home extends CI_Controller {
/*Lots
of
code*/
public function edit($customer_id){
$this->load->model('Customer');
$customer = $this->Customer->getAllCustomers($customer_id);
$this->load->view('update', ['customer'=>$customer]);
}
}
In the view file (update.php) I have:
<?php echo form_input('first_name', '', [
'type' => 'text',
'id' => 'first_name',
'class' => 'form-control',
'value' => set_value($customer->first_name),
'placeholder' => 'First name',
]);
?>
The customer's first_name, although existent in the the database column called "first_name" does not pre-populate the form.
Why is this?

always debug using$this->db->last_query() to check your query executing correctly
if last_query() doesnot return nothing make sure your set 'save_queries' => TRUE in app/config/database.php
your query might return more than one result
change your model like this
public function getAllCustomers($customer_id) {
$q = $this->db->get_where('customers', array('id' => $customer_id));
log_message("error",$this->db->last_query()); //use this to get the complied query for debugging purpose
if ($q->num_rows() > 0) {
foreach (($q->result()) as $row) {
$data[] = $row;
}
return $data;
}
return FALSE;
}
if you are sure that your query might return only one result then check $customer_id has data in it
public function getAllCustomers($customer_id) {
if($customer_id){
$q = $this->db->get_where('customers', array('id' => $customer_id),1); //specify the limit if you want to get only one row
log_message("error",$this->db->last_query()); //use this to get the complied query for debugging purpose
if ($q->num_rows() > 0) {
return $q->row();
}
}
return FALSE;
}

That's how to do it:
<?php echo form_input('first_name', set_value('first_name', $customer->first_name),[
'id' => 'first_name',
'class' => 'form-control'
]);
?>

Related

How to check for Array in Database CodeIgniter and if they don't exist Add them

So I just want to insert the data if the typed data does not exist and/or remove them if users decides to remove them; the problem is that it checks for more > 1 value.
This should be my last question of three in total(see my last two question on profile) regarding the same topic, relationships.
So I have three tables like the ones given below:
AI = auto increment.
ci_users: user_id(AI), username, slug, email, biography.
ci_terms: term_id(AI), title, slug, body.
ci_relationship: id(AI), term_id, user_id, type.
I'm actually trying to do this in a edit view in which I get all the terms from ci_terms and and the already(added directly in databse) ci_terms attached to the user with the following controller:
public function edit($id){
// Verify user ID before updating/editing info
if($this->session->userdata('user_id') != $id) {
// Redirect to dashboard
redirect('users/dashboard');
}
// Field Rules
$this->form_validation->set_rules('email', 'Email', 'trim|required|min_length[7]|valid_email');
if ($this->form_validation->run() == FALSE) {
// Get user
$data['item'] = $this->User_model->get($id);
// Meta
$data['title'] = $this->settings->title.' | Edit '. ucfirst($data['item']->username);
// Get attached skills
$skills = array();
$skills[0] = 'Select Skills';
$skills_attached = $this->User_model->the_skills($id);
foreach($skills_attached as $skill){
$skills[$skill->term_id] = $skill->term_id;
}
$data['skills'] = $skills;
// Select Skills
$skill_options = array();
$skill_options[0] = 'Select Skills';
$skill_list = $this->Terms_model->get_list();
foreach($skill_list as $cat){
$skill_options[$cat->term_id] = $cat->title;
}
$data['skill_options'] = $skill_options;
//Load View Into Template
$this->template->load('public', 'default', 'users/edit', $data);
} else {
// Create User Data Array
$data = array(
'email' => strip_tags($this->input->post('email')),
'biography' => strip_tags($this->input->post('biography')),
);
// Update User
$this->User_model->update($id, $data);
// BEGINNING OF HERE IS WHERE I NEED HELP
// Here I try to check the selected ci_terms(term_id) in the database
$existent_skill = $this->User_model->existent_skill($this->input->post('term_id'));
// If the selected ci_terms(term_id) already exists, display an error
if (!empty($existent_skill)) {
// Create Message
$this->session->set_flashdata('error', 'You already have that one or more of those selected skills');
// Redirect to pages
redirect('users/edit/'.$id.'/'.$id->username);
} else {
// Display the data from ci_terms table
$skills = $this->Terms_model->get_list();
// Expect data to be array
$data = array();
foreach ($skills as $skill){
$data[] = array(
// The main problem how do I add the correct IDs to the array?
'term_id' => $skill->id,
'user_id' => $this->session->userdata('user_id'),
'type' => 'skill',
);
}
// If terms selected, add them
$this->db->insert_batch('ci_relationship', $data);
// I'm also trying to figure out a way to remove the terms that are already attached to the user if he/she decides not to want those skill anymore, any suggestion will be taken into practice.
// else if terms unselected, remove them
$this->User_model->delete_skills($id, $terms_id, $data);
// END OF HERE IS WHERE I NEED HELP
}
// Create Message
$this->session->set_flashdata('success', "You're account has been updated");
// Redirect to profile
redirect('users/dashboard');
}
}
Here is how I get to display the attached(to user) terms from the ci_terms table into the view:
public function the_skills($id){
$this->db->select('*');
$this->db->from($this->relationship);
$this->db->where('user_id', $id);
$this->db->where('type', 'skill');
$query = $this->db->get();
if($query->num_rows() >= 1){
return $query->result();
} else {
return false;
}
}
This is the method which I'm still trying to create that checks for all the selected terms before adding them if they don't exist:
// Verify if relationship already exists
public function existent_skill($term_id) {
$query = $this->db->get_where($this->relationship, array(
'user_id' => $this->session->userdata('user_id'),
'term_id' => $term_id,
'type' => 'skill',
));
return $query->row_array();
}
to continue, here is the function which is supposed(not tested) to delete them if they're unselected from the input:
// Delete un-selected skills
public function delete_skills($id, $terms_id, $data){
$this->db->from($this->relationship);
$this->db->where('user_id', $id);
$this->db->where_in('term_id', $terms_id);
$this->db->where('type', 'skill');
$this->db->delete($this->relationship, $data);
}
Finally here is the view in which I'm using a dropdown with select2:
<!-- Skills -->
<div class="form-group">
<?php echo form_label('Skills', 'skills'); ?>
<div class="input-group date"><div class="input-group-addon"><i class="fa fa-star" aria-hidden="true"></i></div>
<?php
$data = array(
'id' => 'term_id[]',
'name' => 'term_id[]',
);
$class = array(
'class' => 'form-control js-example-basic-multiple',
'multiple' => TRUE,
);
?>
<!-- $data is to provide the dropdown with the id and name -->
<!-- $skill_options is to get the terms from ci_terms in case the user wants to add them as their skill -->
<!-- $skills is to get the current term_id attached to the user which were added in the db -->
<!-- $class is to give the class of js-example-basic-multiple to enable select2 -->
<?= form_dropdown($data, $skill_options, $skills, $class); ?>
<script type="text/javascript">
// Select2 Input
$(document).ready(function () {
$('.js-example-basic-multiple').select2({
tags: true,
tokenSeparators: [',', ' '],
allowClear: true,
selectOnClose: false,
selectOnBlur: false,
});
});
</script>
</div>
</div>
BELOW ARE JUST IMAGES
So what I'm trying to achieve is this:
As you can see there HTML5(term_id, 1) and CSS(term_id, 2) are the attached term_id's and if I deselect them, they should be deleted from ci_relationship after clicking the update button and the same(not really) goes when selecting new terms that are not attached, they should be added.
Is pretty much a relationship system like the one WordPress uses.
Thanks in advance.
I guess you are overthinking here to much - you should just delete all items related to that user and after that insert the new ones which are selected...
an example for your model function could be
public function updateSkills(array $arrSkills)
{
//in case if the array is empty you can stop the process here
if (empty($arrSkills)) return false;
//kill all associated items
$this->db
->where('user_id', $this->session->userdata('user_id'))
->where('type', 'skill');
->delete('ci_relationship');
//insert all items
$arrInsertData = [];
foreach($arrSkills AS $strSkill)
{
$arrInsertData[] = [
'term_id' => $strSkill,
'user_id' => $this->session->userdata('user_id'),
'type' => 'skill'
]
}
$this->db->insert_batch('ci_relationship', $arrInsertData);
return true;
}
and the part in your controller could look like
$data = array(
'email' => strip_tags($this->input->post('email')),
'biography' => strip_tags($this->input->post('biography')),
);
// Update User
$this->User_model->update($id, $data);
// BEGINNING OF HERE IS WHERE I NEED HELP
$blnSuccess = $this->User_model->updateSkills($this->input->post('term_id[]'));
of course you can also add a rule, in case if term_id is required
$this->form_validation->set_rules('term_id[]', 'Term', 'trim|required');

Modify data before pagination in CakePhp

I'm trying to create an Api using cakephp.
I generate a json on server and it works fine , but I tired to use pagination and I got a problem.
in the first case I take the image's path and I encode it to base64 and I generate json => works
in the second case I defined the pagination by the limits and the max and I kept the same code but as a result the image field is still the path from the database and it's not encoded
this my code in my controller :
class PilotsController extends AppController {
public $paginate = [
'page' => 1,
'limit' => 5,
'maxLimit' => 5
];
public function initialize() {
parent::initialize();
$this->loadComponent('Paginator');
$this->Auth->allow(['add','edit','delete','view','count']);
}
public function view($id) {
$pilot = $this->Pilots->find()->where(['Pilots.account_id' => $id], [
'contain' => ['Accounts', 'Pilotlogs']
]);
foreach ($pilot as $obj) {
if ($obj->image_pilot!= NULL) {
$image1 = file_get_contents(WWW_ROOT.$obj->image_pilot);
$obj->image_pilot = base64_encode($image1);
}
}
$this->set('pilot', $this->paginate($pilot));
$this->set('_serialize', ['pilot']);
}
}
If I remove the pagination from the code it works fine . Any idea how to fix it ??
I'd suggest to use a result formatter instead, ie Query::formatResults().
So you'll have something like this :
public function view($id) {
$pilot = $this->Pilots->find()
->where(['Pilots.account_id' => $id], [
'contain' => ['Accounts', 'Pilotlogs']]);
->formatResults(function($results) {
return $results->map(function($row) {
$image1 = file_get_contents(WWW_ROOT.$row['image_pilot']);
$row['image_pilot'] = base64_encode($image1);
return $row;
});
});
}
You can simply first paginate the data and then get the array values and after that modify that data as you want. Check this
public function view($id) {
$pilot = $this->Pilots->find()->where(['Pilots.account_id' => $id], [
'contain' => ['Accounts', 'Pilotlogs']
]);
$pilot = $this->paginate($pilot);
$pilot = $pilot->toArray();
foreach ($pilot as $obj) {
if ($obj->image_pilot!= NULL) {
$image1 = file_get_contents(WWW_ROOT.$obj->image_pilot);
$obj->image_pilot = base64_encode($image1);
}
}
$this->set('pilot', $pilot);
$this->set('_serialize', ['pilot']);
}

Insert one row using different models/pages - CodeIgniter

I'm new to CodeIgniter and I'm building a simple I/O website. I have only one database, say test and only one table results, that looks like this:
screenshot of the table "results"
I have two views personal.php and songs.php. In the first one I collect the data values to be inserted into the fields 2,3, and 4, and the rest of the values are collected in the second view. They are then inserted into the table via their relevant models, personal_model and songs_model.
Now obviously, they will be inserted into 2 different rows which is not what I want. What is the trick here? How should I manage it? So far I have thought of getting the last ID but I have no idea how to do it. Thanks in advance!
personal.php (first view)
<?php echo validation_errors(); ?>
<?php echo form_open('data/personal'); ?> //passes the data to the controller that loads the personal_model.php
"some input fields"
<button type="submit" name="submit">Submit Data</button>
songs.php (second view)
<?php echo validation_errors(); ?>
<?php echo form_open('data/songs'); ?> //passes the data to the controller that loads the songs_model.php
"some input fields"
<button type="submit" name="submit">Submit Rating</button>
personal_model.php (first model)
<?php
class Personal_model extends CI_Model {
public function __construct()
{
$this->load->database();
}
public function insert_personal()
{
$this->load->helper('url');
$data = array(
'age' => $this->input->post('user_age'),
'education' => $this->input->post('user_edu'),
'twitter' => $this->input->post('user_twitter'),
'facebook' => $this->input->post('user_facebook')
);
return $this->db->insert('results', $data);
}
}
songs_model.php (second model)
<?php
class Ratings_model extends CI_Model {
public function __construct()
{
$this->load->database();
}
public function insert_ratings()
{
$this->load->helper('url');
#$this->load->database();
$data = array(
'score' => $this->input->post('rating'),
'song1' => $this->input->post('rnd1'),
'song2' => $this->input->post('rnd2')
);
return $this->db->insert('results', $data);
}
}
Your Controller Function should be like this.
public function personal()
{
$lastInsertedID = $this->Personal_model->insert_personal();
$this->session->set_userdata("personalID",$lastInsertedID);
}
Set the last inserted id into session in your above controller function which should be return from your Personal_model. Here is code.
public function insert_personal()
{
$this->load->helper('url');
$data = array(
'age' => $this->input->post('user_age'),
'education' => $this->input->post('user_edu'),
'twitter' => $this->input->post('user_twitter'),
'facebook' => $this->input->post('user_facebook')
);
$this->db->insert('results', $data);
return $this->db->insert_id();
}
Then update your existing row in your insert_ratings function instead of insert record. Here is code.
public function insert_ratings()
{
$data = array(
'score' => $this->input->post('rating'),
'song1' => $this->input->post('rnd1'),
'song2' => $this->input->post('rnd2')
);
$personalID = $this->session->userdata("personalID");
$this->db->where("id",$personalID);
$this->db->update('results', $data);
return $this->db->affected_rows();
}
Then no new record will insert into table while submit your song.php form it will update the existing one.

YIi PHP - Output array with a foreach loop

I'm trying to return a navigation menu using Yii PHP framework, but my controller is only outputting the first item in the array, here's my code. Note that this pattern isn't using the traditional MVC, the model i'm asking data for is being displayed site-wide, not directly to its's controller->view.
Model - get data;
//output pages for getPagesMenuItems() in base controller
public function getAllPages(){
$criteria = new CDbCriteria();
$criteria->condition = "visible = 1";
return Pages::model()->findAll($criteria);
}
Base controller in components
public $pagesMenuItems = array();
$this->pagesMenuItems = $this->getPagesMenuItems();
protected function getPagesMenuItems() {
//Non admin users - links to pages
if (Yii::app()->user->isGuest){
$rows = Pages::getAllPages();
foreach($rows as $row) {
return array(
//$row->id , $row->title , $row->guid , $row->visible
array('label' => $row->title, 'icon' => 'fa fa-times', 'url' => array('/admin/pages/view/id/' . $row->id)),
'---',
);
}
// return array();
}
else {}
}
And this is the view in the main.php
$this->widget('booster.widgets.TbMenu', array(
'items' => $this->pagesMenuItems,
'id' => 'pagesNav'
));
I know the issue is packaging the array in the foreach loop, as i've tested the output of the model and all data is correct
Can anyone see where i'm going wrong in my controller?
Thanks
change getPagesMenuItems function as below:
protected function getPagesMenuItems() {
//Non admin users - links to pages
$data = array();
if (Yii::app()->user->isGuest){
$rows = Pages::getAllPages();
foreach($rows as $row) {
$data[] = array('label' => $row->title, 'icon' => 'fa fa-times', 'url' => array('/admin/pages/view/id/' . $row->id));
}
}
else {}
return $data;
}

Laravel and a While Loop

I'm new to Laravel and at the moment I have a piece of code in a Controller which without the while loop it works, it retrieves my query from the database.
public function dash($id, Request $request) {
$user = JWTAuth::parseToken()->authenticate();
$postdata = $request->except('token');
$q = DB::select('SELECT * FROM maps WHERE user_id = :id', ['id' => $id]);
if($q->num_rows > 0){
$check = true;
$maps = array();
while($row = mysqli_fetch_array($q)) {
$product = array(
'auth' => 1,
'id' => $row['id'],
'url' => $row['url'],
'locationData' => json_decode($row['locationData']),
'userData' => json_decode($row['userData']),
'visible' => $row['visible'],
'thedate' => $row['thedate']
);
array_push($maps, $product);
}
} else {
$check = false;
}
return response()->json($maps);
}
I am trying to loop through the returned data from $q and use json_decode on 2 key/val pairs but I can't even get this done right.
Don't use mysqli to iterate over the results (Laravel doesn't use mysqli). Results coming back from Laravel's query builder are Traversable, so you can simply use a foreach loop:
$q = DB::select('...');
foreach($q as $row) {
// ...
}
Each $row is going to be an object and not an array:
$product = array(
'auth' => 1,
'id' => $row->id,
'url' => $row->url,
'locationData' => json_decode($row->locationData),
'userData' => json_decode($row->userData),
'visible' => $row->visible,
'thedate' => $row->thedate
);
You're not using $postdata in that function so remove it.
Do not use mysqli in Laravel. Use models and/or the DB query functionality built in.
You're passing the wrong thing to mysqli_fetch_array. It's always returning a non-false value and that's why the loop never ends.
Why are you looping over the row data? Just return the query results-- they're already an array. If you want things like 'locationData' and 'userData' to be decoded JSON then use a model with methods to do this stuff for you. Remember, with MVC you should always put anything data related into models.
So a better way to do this is with Laravel models and relationships:
// put this with the rest of your models
// User.php
class User extends Model
{
function maps ()
{
return $this->hasMany ('App\Map');
}
}
// Maps.php
class Map extends Model
{
// you're not using this right now, but in case your view needs to get
// this stuff you can use these functions
function getLocationData ()
{
return json_decode ($this->locationData);
}
function getUserData ()
{
return json_decode ($this->userData);
}
}
// now in your controller:
public function dash ($id, Request $request) {
// $user should now be an instance of the User model
$user = JWTAuth::parseToken()->authenticate();
// don't use raw SQL if at all possible
//$q = DB::select('SELECT * FROM maps WHERE user_id = :id', ['id' => $id]);
// notice that User has a relationship to Maps defined!
// and it's a has-many relationship so maps() returns an array
// of Map models
$maps = $user->maps ();
return response()->json($maps);
}
You can loop over $q using a foreach:
foreach ($q as $row) {
// Do work here
}
See the Laravel docs for more information.

Categories