new to CodeIgniter and MVC/OOP as well. My current problem that I am trying to work through involves 2 tables.
Gallery Table
id
name
clientID
Client Table
id
Name
The gallery['clientID'] references the client['id'] so I can retrieve the name. Currently my gallery_model.php file looks like
class Gallery_model extends CI_Model
{
public function __construct()
{
$this->load->database();
}
//Get all in progress galleries from client
public function get_progress($id = FALSE , $clientRef = '205')
{
if($id == FALSE) {
$query = $this->db->get_where('gallery', array('clientRef' => $clientRef, 'finish' => '0' ));
return $query->result_array();
}
}
//Get all proofed galleries from client
public function get_proofed($id = FALSE , $clientRef = '205')
{
//get all galleries from client
if ($id == FALSE) {
$query = $this->db->get_where('gallery',array('clientRef' => $clientRef, 'finish' => '1'));
return $query->result_array();
}
}
//get the gallery selected
public function get_gallery($id , $clientRef = '205')
{
//This returns individual galleries
$query = $this->db->get_where('gallery', array('id' => $id));
return $query->row_array();
}
}
My controller looks like:
public function index()
{
//Proofed Albums
$data['gallery'] = $this->gallery_model->get_proofed();
//Albums that are in progress
$data['in_progress'] = $this->gallery_model->get_progress();
$this->load->view('templates/header',$data);
$this->load->view('gallery/index',$data);
$this->load->view('templates/footer');
}
Then the view's out put is
$gallery['name'] - $gallery['clientId']
What is the best practice for something like this. I know it's probably simple, but I want to start out doing this correctly. Should I use $this->db->join();
Thanks in advance for the help on this.
Following up on William's answer, you can do a join using CI's Active Record
$this->db->from('gallery')->join('client', 'gallery.id = client.id')->get()
Using $this->db->join() is indeed the best (and the only way done via Active Records without adding your own SQL) way to get information from several tables all in one query.
You're probably already aware of this, but just in case (and for the benefit of future people visiting this page), the CodeIgniter User Guide has a nice page detailing how to use Active Records.
The default of Inner Join should be fine for your purposes. If you have gallery entries without clients linked to them and you want them to be included in the results, then you may want to consider the other types of join, which you can read about here.
Related
I have three tables,
users => id, user_name, etc etc
messages => id, user_id, message_text etc etc
answers => id, user_id, message_id, answer_text.
I want to get all messages for logged in user along will all answers for each message. I have tried many join examples, but I always get all answers (coupled with their message data).
I need data like that
message_1 => all_answers
message_2 => all_answers
message_3 => all_answers
It's impossible, or too complicated, to get that result with one query only.
You must extract data in stages. Using model functions would be the best.
Let's say you have the id of the user.
You have to get the messages, and that's easy.
$this->db->where('user_id', $user_id);
$query = $this->db->get('messages');
Now that must be put inside the model. Let't call it messages_model.
class messages_model extends CI_Model {
function __construct(){
parent::__construct();
}
function get_messages($user_id){
$this->db->where('user_id', $user_id);
$query = $this->db->get('messages');
return $query->result();
}
}
Say, you want to put those messages inside some variable, and get them to your view. In your controller:
$this->load->model('messages_model');
$rough_messages = $this->messages_model->get_messages($user_id);
foreach($rough_messages as $message){
$messages[$message->id][$message_text] = $message->message_text;
$messages[$message->id]['answers'] = $this->messages_model->get_answers($message->id);
}
Then, your 'get_answers()' model function would look like this, inside messages_model(edit: I split it in two functions, one for db qwery and the other for refined results):
function get_answers($message_id){
$rough_answers = $this->get_rough_answers($message_id);
$answers = array();
foreach($rough_answers as $answer){
$answers[$answer->id] = $answer->answer_text;
}
return $answers;
}
function get_rough_answers($message_id){
$this->db->where('message_id', $message_id);
$query = $this->db->get('answers');
return $query->result();
}
Now, if you do echo '<pre>'.print_r($messages, true).'</pre>'; in your controller, you will get an multi-dimensional array, with your messages and corresponding answers, for a given user id. You can now alter and use this as you see fit.
i was getting in a question when i got this scenario:
I have to make a history log about what the user does and of course the user can do a lots different action.
i thought two different 2 way for make it i just need someone that can help me to follow the right way.
First way:
Create 2 different tables
History_user
History_type
History_user table
id | user_id | history_type (int)
1 1 1
1 3 2
History_type
id | name_action (string)
1 The user has posted on the wall
2 The user has change his profile picture
and then just join on the query with History_user.history_type = History_type.id
Second way:
is create the History_user table and an helper example called Converter.
<?php
class Converter {
function history($type_history) {
switch($type_history) {
case 1:
$human_history = "The user has posted on the wall";
break;
case 2:
$human_history = "The user has change his profile picture";
break;
}
return $human_history;
}
}
$converter = new Converter();
$converter->history(1);
I was looking for the better way for do that, in terms of performance and maintainability. Thank you.
Both helper and History_type table are necessary for information representation. In terms of performance it doesn't really matter, because you will insert only in one table on user action. If you need to represent data, you will need just one more query to get descriptions of actions (without joins, ofc, if you want some performance). So 2 tables way is more flexible and extendable.
You still could do that helper function which lets say will have static cache variable - array of id => name of actions, which will be lazy loaded on history() function like this:
class Converter {
protected static $_cache;
protected static function _loadCache() {
if (null !== self::$_cache) {
return;
}
self::$_cache = array();
$query = "SELECT * FROM `History_type`";
$res = mysql_query($query);
while ($row = mysql_fetch_assoc($res)) {
self::$_cache[(int) $row['id']] = $row['action'];
}
}
public static function history($id) {
self::_loadCache();
return isset(self::$_cache[$id]) ? self::$_cache[$id] : 'Undefined action';
}
}
Converter::history(1);
I have a Model for Groups and another model for Notes (Notes and Posts are same things).
NotesController:
public function groupnotes()
{
if (!empty($this->data))
{
$data = $this->data;
$data['Note']['user_id'] = $this->Auth->user('id');
if ($this->Note->save($data))
{
PROBLEM HERE
}
}
if(empty($this->data['Note']['notes']))
{
PROBLEM HERE
}
GroupsController: (ViewCourse is used to view each group )
public function viewcourse($id=NULL)
{
$this->set('viewcourse', $this->Group->read(NULL,$id));
$this->set('course', $this->Group->find('all', array('conditions'=>array('Group.id'=>$id))));
}
Now when i create a post in a group it redirects me to "groupnotes" action and i want it to redirect me to viewcourse/id ... I am a bit confused how can i redirect the page to viewcourse/id ...
I tried doing it by adding this to groupnotes action
$this->redirect(array('controller'=>'groups', 'action' => 'viewcourse'));
but here i do not have the id.
What do you suggest?
This question might help you: What is the equivalent to getLastInsertId() in Cakephp?
$this->redirect(array(
'controller'=>'groups',
'action' => 'viewcourse/'.$this->Group->getLastInsertId())
);
EDIT:
I have only suggested that you go to the last inserted id of a group as a suggestion. Your question is a bit vague when you say "but here i do not have the id."
1. are you looking to go to any valid course id?
2. last entered course?
3. first entered course id?
Alternatively you could set a default course in your controller like so...
public function viewcourse($id=NULL)
{
if(!$id){
$id = $this->Group->find('first');
$id = $id['Group']['id'];
}
$this->set('viewcourse', $this->Group->read(NULL,$id));
$this->set('course', $this->Group->find('all', array('conditions'=>array('Group.id'=>$id))));
}
NOTE: Just a tip,
$this->set('course', $this->Group->find('all', array('conditions'=>array('Group.id'=>$id))));
Can be substituted with
$this->set('course', $this->Group->findById($id));
To make your code a bit leaner
I want to have a delete button underneath blogs entered just by the owner of the current profile, I have tried implementing a deleteMyBlog function but no joy so far. whats the best way to go about this?
Here is my view. I know I would need but some delete button here but I'm not sure how to fit around my current foreach loop:
<?foreach($blogs AS $viewData):
$delete = $viewData['id'];
{
$id = $viewData->id;
$title = $viewData->title;
$body = $viewData->body;
$username = $viewData->username;
$date = $viewData->date;
?>
<b> <?=$title?></b>
<p><?=$body?></p>
<p>posted by:<?=$username?></p>
<p>date: <?=$date?></p>
<?=anchor("blog/deleteMyBlog/$delete", 'delete')?>
<hr>
<?
}
?>
My model:
class Blogmodel extends CI_Model
{
public function __construct()
{
parent::__construct();
}
function deleteMyBlog($id)
{
$this->db->where(array('id' => $id));
$this->db->delete('blogs');
}
public function get_last_ten_entries()
{
$query = $this->db->get('blogs', 10);
return $query->result();
}
public function insert_entry()
{
$this->title = $this->input->post('title');
$this->body = $this->input->post('text');
$this->username = $this->session->userdata('username');
$this->date = date("Y-m-d");
$this->db->insert('blogs', $this);
}
}
Controller:
class Blog extends CI_Controller {
public function _construct()
{
parent::__construct();
$this->load->model('Blogmodel','Blog');
$this->load->model("profiles");
}
function deleteMyBlog($id) {
$this->blogs->deleteBlog($id);
redirect('blog');
}
public function index()
{
$username = $this->session->userdata('username');
$viewData['username'] = $username;
$this->load->model('Blogmodel');
if($this->input->post('act') =='create_post')
{
$this->Blogmodel->insert_entry();
}
$viewData['blogs'] = $this->Blogmodel->get_last_ten_entries();
$this->load->view('shared/header');
$this->load->view('blog/blogtitle', $viewData);
$this->load->view('shared/nav');
$this->load->helper('form');// Load the form helper.
// Lets set the stuff that will be getting pushed forward...
$data = array();
$data['form_open']=form_open();
$data['form_title'] = form_input(array('name' => 'title'));
$data['form_text'] = form_textarea(array('name' => 'text'));
$data['form_hidden'] = form_hidden('act','create_post');
$data['form_submit'] = form_submit('submit','Make Post');
$this->load->view('blog/blogview');
$this->load->view('blog/post', $data);
$this->load->view('shared/footer');
}
}
Thanks again guys
Simplest way is with assigning username to a variable, then with the SQL statement.
Delete from tbl where colname='$username'
That's the way I would do it, other people might have different methods. So all respect to those who would use somethin different
You're getting the error because of this bit:
<?foreach($blogs AS $viewData):
$delete = $viewData['id'];
It should be this:
$delete = $viewData->id;
You're using the exact same data a line later correctly, why are you trying to use $viewData which is an object as an array here, but an object 2 lines later. Other than that the rest of what you're doing there should work fine but it is rather dangerous in practice. If I go to your site and type the url to that controller function with a blogId at the end that blog goes away, at no point are you checking that the user actually should be allowed to delete that blog. Obscurity != Security. Meaning that just because you think people won't find the link doesn't mean they won't.
Personally I save the userId of a logged in user to the session and save the session to the database. Then when I do anything to user records I do a check to ensure the user making the change has the authorization to make that change.
So your delete function would be something like this:
function deleteMyBlog($id)
{
$this->db->where('username',$this->session->userdata('username');
$this->db->where('id',$id);
$this->db->delete('blogs');
}
Also you should be using userId's not usernames for saving to other tables, the indexes work better on numerical ID's as far as I know and it's less overall data in the tables. Saving userId 342 to your blogs table takes up less space than saving username bobsyouruncle3421.
For the record, I know this isn't part of the question but actually deleting things from the database has downsides. Not the least of which is screwing up the indexing and slowing down queries in the long run. A far better solution is adding a status or active column to any tables you may want to delete from and giving them a value of 1 for active and 0 for deleted. Then instead of actually deleting the item you change it's active column to 0. When displaying items you add a check for active = 1 to the display query.
This serves two purposes, first you don't mess up the indexing, the record is never removed just modified so the indexes remain intact. Second and nearly important is you never have the possibility of accidentally deleting something you didn't mean to delete, it is never really gone. So you could "undelete" anything at any time.
I'm trying to learn the code igniter library and object oriented PHP in general and have a question.
I've gotten as far as making a page which loads all of the rows from my database and in there, I'm echoing an anchor tag which is a link to the following structure.
echo anchor("videos/video/$row->video_id", $row->video_title);
So, I have a class called Videos which extends the controller, within that class there is index and video, which is being called correctly (when you click on the video title, it sends you to videos/video/5 for example, 5 being the primary key of the table I'm working with.
So basically all I'm trying to do is pass that 5 back to the controller, and then have the particular video page output the particular rows data from the videos table. My function in my controller for video looks like this:
function video()
{
$data['main_content'] = 'video';
$data['video_title'] = 'test';
$this->load->view('includes/template', $data);
}
So ya, basically test should be instead of test, a returned value of a query which says get in the table "videos", the row with the video_id of "5", and make $data['video_title'] equal to value of video_title in database...
Should have this figured out by now but don't, any help would be appreciated!
I don't know if I'm too late but maybe this can solve your problem...
put this in your video() function
data[$query] = $this->db->query("SELECT * FROM videos WHERE video_id = 5");
and then that in your video_view file...
if ($query->num_rows() > 0)
{
$row = $query->row_array();
echo $row['title'];
echo $row['something'];
echo $row['somethingElse'];
}
this is a good resource: http://codeigniter.com/user_guide/database/index.html
hope that helps...
and please someone edit the question because it's too hard to read...
What you need is to understand how the URI Class works
Basically:
$default_url_args = array('video');
$url_args = $this->uri->uri_to_assoc(3,$default_url_args);
$video_UID = $url_args['video'];
and then something like
$the_video = $this->videos_model->get_video_by_UID($video_UID);
You could use the URI Class, or you can do the following:
function video($video_id)
{
$data['main_content'] = $this->videoprovider->get_video( $video_id );
$data['video_title'] = 'test';
$this->load->view('includes/template', $data);
}
In other words, with functions inside classes that extend Controller, you can add parameters to those functions and CI will automatically pass in the URI items in order to those parameters.
function generic_function_in_controller($item1, $item2, ...)
{
// would receive as: http://example.com/controller/generic_function_in_controller/item1/item2
}