i have a module that have different render with different conditions so i have used like
if($p_id != '') {
$this->render('view', array(
'model' => $this->loadModel($id, 'Supplier'),
'modeln' => $this->loadModel($p_id, 'Permit'),
));
} else {
$this->render('view', array(
'model' => $this->loadModel($id, 'Supplier'),
));
it works fine but i have 5 to 6 conditions like this ,so how can i handle this? any easy way than this? thanks
There are several approaches.
Switch cases to return the view and model datas as array.
Make $p_id and view name more meaning ful. Or even, as:
$views = array(
'p_id' => 'corresponding_view file'
);
And then later, use it as $this->loadModel($p_id, $views[$p_id]),
There are two solutions for this problem:
Adding condition inside controller and rendering multiple views based on condition.(As you do)
Having just one view and adding condition inside the view and showing desired parts of view based on condition.
All these two solution is achievable, But I believe first solution is better. Because second solution has inconsistency with MVC structure. It's not a good idea to put logic inside the view. So I think rendering different views based on condition is better.
Related
I have two models that have a relationship to each other. In one particular method I need to pick a field on the other, I usually create a method to pull just one field, if the field in the future subject to change, I will have to change only the return of function .. here are examples
I currently use the following: (this is just an example, obviously there is much more fields to get)
User model
function getUsername($user_id){
$this->id = $user_id;
return $this->field('my_username_field');
}
Server model
function getUserIdByServerId($server_id){
$this->id = $server_id;
return $this->field('my_user_id_field');
}
function getUsernameByServerId($server_id){
$user_id = $this->getUserIdByServerId($server_id);
return $this->User->getUsername($user_id);
}
This is a lot of code to write, because if I want to get more fields, I would have to write kind of one method for each field.. and if I do otherwise then when the field name change I'll have to re-write his name on all calls.. what is the better way?
Why do you want to fetch single fields? Especially if you need more than one? This doesnt make much sense. It is more effective to fetch the whole record (all fields, or select the 3-4 you need) and then deal with the data instead of doing multiple queries to the DB. That is inefficient and repetitive, not very DRY.
CakePHP already features a method for that, Model::field().
$this->Server->User->field('username', array(
'conditions' => array(
'User.server_id' => $serverId
)
));
But like I said, why are you not just doing this?
$this->Server->find('first', array(
'contain' => array(
'User'
),
'conditions' => array(
'User.server_id' => $serverId
)
));
You shouldn't need to create new methods in the models for this. What you would be doing now, I guess, in your Server Controller, would be something like this:
$this->Server->id = $server_id;
$username = $this->Server->getUsernameByServerId($this->Server->id);
What I think you can do, though, is just call something like this:
$this->Server->id = $server_id;
$username = $this->Server->User->field('username');
Or if you have (I think) PHP 5.4 or higher just use:
$this->Server->id = $server_id;
$username = $this->Server->read()['User']['username'];
(with PHP <5.4 you can just split that last line into two).
I don't think you should have to copy and paste loads of methods in the models for this.
I am changing the data provided by my model in the afterFind() method, so the id is clickable text, like this:
$this->id = CHtml::link($this->id, array('/admin/auditTrail/view', 'id' => $this->id));
However, this changes every single occurrence of id value - it is in lists, in detail page, even in breadcrumbs, which is unwilling of course. How can I decide which format I will use in different views? For example, in breadcrumbs and in view.php I just want the raw value, but in the list (admin.php) I would like to use the html link, like this:
'columns'=>array(
array(
'name' => 'id',
'type' => 'html',
),
On a separate note - is this a good approach in terms of MVC, I mean changing display in a model? Should not be model only used for a database manipulation stuff?
No, this is not a good approach. There are a number of alternative approaches that would be better, for example:
Let the view do the conversion
Don't do anything in the model. When the view wants to display clickable anchors instead of bare ids, it should generate the URLs itself. This is somewhat quick and dirty (it puts the logic of URL generation in the view, which is not ideal) but it's easy and it works well if you only need to do it in one or two places.
Expose the URL as a separate property
Place a calculated read-only property in your model:
public function getAuditTrailUrl()
{
return Yii::app()->createUrl('/admin/auditTrail/view',
array('id' => $this->id));
}
You can then use the auditTrailUrl property in any view. The nice thing about this approach is that the URL generation is opaque to the views and therefore easily modifiable.
You can use this syntax to easily render links from these URLs in your CDataGrid:
'columns' => array(
array(
'class' => 'CLinkColumn',
'urlExpression' => '$data->auditTrailUrl',
)
),
In the above definition $data refers to each model in the grid, as per the documentation.
Can I do this in a Controller:
$this->User->read(null, $id);
$this->User->find('list');
Is it correct?
Am I using MVC correctly?
Can these easy functions be used in a Controller? Or, do I need to create these functions in the Model? Like Model->getUser(), and have that function use Model->read().
I know that functions it's called by Model, but, when I want pass some parameters, and function makes big, for example:
$this->User->find('all', array(
'conditions' => array(
'User.active' => true,
'User.group_id' => 3,
'User.age >=' => 18
)
));
Can I call this function in Controller, or need create a custom function in Model, to call it? Like... $this->User->findSomeCustomFunction($param1, $param2, $param3)?
TLDR:
It's "ok" to call a find() from your Controller, however best practice is to put any/all find()s in your models.
If you make a habit of putting all your find()s in your models, it will make it much easier to maintain your code in the long run.
Explanation/example:
In this case, as an example, you could start with a seemingly simple function:
//User model
public function getUsers() {
return $this->find('list');
}
But later, maybe you need something more along the lines of:
//User model
public function getUsers($opts = array()) {
$defaults = array(
'findType' => 'all',
'activeOnly' => true,
);
$params = array_merge($defaults, $opts);
$qOpts = array('conditions' => array());
//active only
if(!empty($params['activeOnly'])) $conditions[$this->alias.'.active'] = 1;
return $this->find($params['findType'], $qOpts);
}
(Pardon if there are many ways to make that code better - it was just off the top of my head - It gives you the idea.)
Keeping all your find()s in the Model also keeps you from having to search through each Controller every time you want to write a find() to determine if you've used a similar find() anywhere else. If you're programming as a team, that can be a nightmare, and you're almost guaranteed to be duplicating code.
It is perfectly fine to call Model->find() from a Controller. However, you will also want follow the DRY (Don't Repeat Yourself) principles. That basically means "Don't copy-paste code everywhere."
So, if you find that you need to make this exact Model->find() call from many Controller actions, it is considered good practice to abstract it into a function call against the Model. So yes, your Controllers would then call $this->User->findSomeCustomFunction().
I am very newbie about all of these PHP Frameworks. I was once created my own framework by using phpbb's template functions, language support and sessions. I turned them into a Model-View framework. I decided that is too complicated and searched for a new framework.
Right now I am using laravel and its quite well yet I still couldn't figure how to handle controllers and views. Here comes my stuck part.
I was using my phpbb's framework by creating a file.php to root folder and create a .html file styles folder. phpbb's framework can render a html file by calling
$template->set_filenames(array(
'body' => 'file.html'
));
however i can pass every variable to file.html from the controller.php like this :
$template->assign_var('THREAD_ID', $row['id']);
$template->assign_var('THREAD_NAME', $row['title']);
even cycles were too easy
while ($row = $db->sql_fetchrow($result))
{
$template->assign_block_vars('post_row', array
(
'ID' => $row['post_id'],
'COUNT' => $count++,
'USERNAME' => $row['post_username'],
'DATE' => $row['post_datetime'],
'ENTRY' => $row['post_entry'],
)
);
}
and then for rendering the view
$template->set_filenames(array(
'body' => 'file.html'
));
this is what i couldnt understand in laravel.
I am using this but when I using this for another variable it gives me error.
$this->layout->nest('content', 'index', array(
'data' => 'pokeçu'
));
in documents they made examples just for one variable. I dont know how to continue my way.
I'm assuming you're using Laravel 3, as that is the current stable version. There's a section in the Laravel docs covering this. Basically you're going to be using the View class in whatever way suits your app best. Remember, your controller methods (or route closures) will always return something, usually a View instance. To bind data to that view, the simplest method is to use with($data[, $value]) where $data is either an associative key-value array, or $data is a key and $value is the value. For example:
public function get_index()
{
$thread = array('id'=>23, 'name'=>'Skidoo');
return View::make('home.index')->with($thread);
}
Note the return. You don't need to return it right away. You can also instantiate the View object, and bind data to it directly:
public function get_index()
{
$view = View::make('home.index');
$view->thread = array('id'=>23, 'name'=>'Skidoo');
$view->welcome = 'Welcome to My Site!';
return $view;
}
In addition to the docs, there are a couple of recent tutorial books available. Check out the Learn section on the Laravel website at http://laravel.com/
I'm using Doctrine2 and CodeIgniter2, and am new to both, as well as to OOP/MVC, so please use simple explanations :)
For testing purposes, I have a Controller a Model and a View. I want to display data from a table that contains user information. First name, last name, ID number, and so forth.
My controller makes a call to the model- which retrieves data from the doctrine entity, and then the controller passes that data to the view.
(controller)
class Test_v_to_m extends CI_Controller {
public function index() {
$this->load->model('testing/test_v_to_m_model');
$data = $this->test_v_to_m_model->display_user_info();
$this->load->view('testing/test_v_to_m_view', $data );
}
}
(model)
class Test_v_to_m_model extends CI_Model{
public function display_user_name() {
$query = $this->doctrine->em->createQuery("select u from ORM\Dynasties2\Users u");
return $query->getResult();
(view)
//print_r($data);
First question is: How do I pass the object or array along to the view in a useful way? This works if I'm just dealing with a single variable:
(controller)
$user = $this->doctrine->em->find('Entities\User', $user_id);
$data['firstname'] = $user->getFirstName();
$this->load->view('testing/test_v_to_c_view_2',$data);
(view)
echo $firstname;
But I don't know how to do something similar when its an array, or a multidimensional array.
The second question is whether or not to let the view do any real work (php logic, loops, foreach, etc) or to do all of that in the controller and have the view only do formatting and display.
Yes, You can just pass multi-dimensional array to the view and then access it as required.
e.g.
$template_date['result_arr'] = array(
array('firstname' => 'abc', 'lastname' => 'xyz')
, array('firstname' => 'abc', 'lastname' => 'xyz')
);
in your view file -
foreach($result_arr as $key => $row) {
echo $row['firstname'].' <br />';
}
Re your 2nd question - As per my understanding - it's fine to use some foreach, for loops in the view but it's best if business logic is kept to controllers and models. Hope it makes sense to you.
As for your first question, I don't know the answer off the top of my head (sorry!). I would imagine, however, that an array can be passed as part of the data (as a single item), but you would need to iterate though it in the view (see below). Just a guess, however...
As for your second question, the principle of MVC is to have only display logic in the view - so all of the "real work" should be done in the controller.
Now, if you want to have a loop to display data in a table, that's "real work" being done in the view, but since it's part of formatting and display that would be acceptable.
Regarding your first question, it's actually quite simple:
$data = array(
'firstname' => 'string',
'array' => array(1, 2, 3),
'multidimensional_array' => array('ocean' => 'deep')
);
In the view, you can access these as:
$firstname;
$array;
$multidimensional_array;
They're just exported to the view, so you can treat each key in the $data array as a variable, and the values in the $data array as the variables' values.
Regarding the second question, it is generally best if you have the view only do formatting and display. In some cases, it might be useful to use ifs or loops, for example, if you want to display different messages based on a certain variable, or if you want to fill a table with a bunch of rows. However, I strongly recommend that you keep out as much logic as possible. The view is meant to receive all the data it needs and display it in a way that suits it.
There are plenty of reasons for this, namely maintainability (if your logic changes, you don't need to update the view), reusability (if you make views as general as possible, you can reuse them very easily) and even the ability to create new views or to replace that view with a different one, without worrying about the logic.
I hope this helps. :)