MVC URL issues (Codeigniter) - codeigniter

I'm building a website using Codeigniter and I really like how in the MVC pattern URLs are used to reference controller methods. It seems very logical and intuitive however, I seem to be running in an array of issues with this very pattern!
So I am building an events website and currently I'm passing everything through one main Site controller, passing a number of parameters:
public function index($page = NULL, $city = NULL, $type_venue = NULL, $slug = NULL)
{
// if the page argument is empty show the homepage
if( ! ($page))
{
$page = 'home';
}
// create an array for passing to the views
$data = array(
'title_city' => $city,
'title_type_venue' => str_replace('-', ' ', $type_venue),
'locations' => $this->locations_model->load(),
'events' => $this->events_model->load($city, $type_venue, $slug),
'venues' => $this->venues_model->load($city, $slug)
);
// construct the page layout with the following views
$this->load->view('partials/head', $data);
$this->load->view('partials/header', $data);
$this->load->view('content/'.$page, $data);
$this->load->view('partials/footer');
}
This works fine, in that it loads content for the following URLs:
site.com/events/bristol/open-mic/city-varieties/another-incredible-event
site.com/events/bristol/open-mic/city-varieties/
site.com/events/bristol/open-mic/
site.com/events/bristol/
However if I want to pass anything else through this controller that isn't an event, i.e. register/user, I have to write a specific route for this!
Worth noting my routing is:
$route['(:any)'] = 'site/index/$1';
I could write separate controllers for each entity, i.e. events, venues, cities but each one would look largely like the above (correct?) in that each would need the parameters to get the data.
My question is - what is the best practice approach for developing long query strings like this? Is a single controller correct? It doesn't feel like it, but then multiple controllers would violate DRY, just because they all need so much similar data. Any help appreciated!

Avoid putting everything into a single controller; even further, in each controller, avoid putting everything into a single index function.
There is no need to write specific controllers for each function in Codeigniter - suggest you read that part again in the manual. Most of your routing will be done automatically for you if you follow the normal guidelines.
The more you try to use a single controller or function, the more you will have to add untestable, unmanageable, unscalable conditional code later.

Related

Is good practice for view sending param by assign to controller property?

For sending param to view, document in CodeIgniter use as following:
$data['name'] = $this->name;
$data['color'] = $this->color;
$this->load->view('you_view',$data);//Load view with $data param
But currently i use like this:
//Controller file
$this->params = [Big Object or Array ];//Here I assigned my OJBECT or Array to controller property PARAMS
$this->load->view('you_view');//***** Wthout send with load view*******
//View file
$var_dump($this->params);//Notice after I print_r( $this) i found that it is current controller, that why i use without sending params during load view, but i afraid any problem or make my system slow.
In many different ways you can pass variables to the view, for example through controller as you did, then through config file, model, language file, or defining a variables with define(), but then the point of MVC model was to separate data, logic and design, so i don't thing your way is a bad way, just not in the spirit of idea of MVC. Do you get any better performance?

Advanced Validation with Lithium PHP Framework

I'm building a pretty complex and dynamic form via the Lithium PHP framework.
I've got the form working and saving to MongoDB with little problem. But I am having trouble with validation.
Simple validations (such as checking if a field is not empty or is numeric) are working fine. But I have to do a few complex validations that rely on a number of fields in the form.
For example, I have a form where a user can enter a question and then enter an unlimited number of possible answers for this question. The field ID for each answer is listed such as "answer_1", "answer_2", "answer_3", etc. The user can add an unlimited number of answers. This happens via some fancy JavaScript that inserts extra elements to the form on the client side.
At the validation level, I want to make sure that every answer which was added is not null.
I would like to do this using the "traditional" Validator functionality built within Lithium. I am also doing this at the Model level, not the Controller level (note - I have a workaround to solve this on the Controller level, but would rather do it the "right" way at the Model)
The problem, as far as I can tell, is that you can only pass a single value to the validator rule. I just need to pass back ALL values in the form to the validator. If I could do that, I would be golden. The pseudo-code for what I'm looking to do looks like this:
Validator::add('CorrectTest', function(&$value, $format = null, array $options = array()) {
foreach ($_data as $key => $value) {
if (stristr($key, "answer_")) {
if ($value == "") {
return false;
}
}
}
return true;
});
This code doesn't work, because the $_data value is not present. If I could just figure out a way to get a fully-populated "$_data" object into the Validator function, I think I could get this to work.
Thanks in advance for the help
Take a look at what's inside $options. You should have a 'values' key in there that has all of the values from the form.
So try
$_data = $options['values'];

CodeIgniter - Dynamic URL segments

I was wondering if someone could help me out.
Im building a forum into my codeigniter application and im having a little trouble figuring out how i build the segments.
As per the CI userguide the uri is built as follows
www.application.com/CLASS/METHOD/ARGUMENTS
This is fine except i need to structure that part a bit different.
In my forum i have categories and posts, so to view a category the following url is used
www.application.com/forums
This is fine as its the class name, but i want to have the next segment dynamic, for instance if i have a category called 'mycategory' and a post by the name of 'this-is-my-first-post', then the structure SHOULD be
www.application.com/forums/mycategory/this-is-my-first-post
I cant seem to achieve that because as per the documentation the 'mycategory' needs to be a method, even if i was to do something like /forums/category/mycategory/this-is-my-first-post it still gets confusing.
If anyone has ever done something like this before, could they shed a little light on it for me please, im quite stuck on this.
Cheers,
Nothing is confusing in the document but you are a little bit confused. Let me give you some suggestions.
You create a view where you create hyperlinks to be clicked and in the hyperlink you provide this instruction
First Post
In the controller you can easily get this
$category = $this->uri->segment(3);
$post = $this->uri->segment(4);
And now you can proceed.
If you think your requirements are something else you can use a hack i have created a method for this which dynamically assign segments.
Go to system/core/uri.php and add this method
function assing_segment($n,$num)
{
$this->segments[$n] = $num;
return $this->segments[$n];
}
How to use
$this->uri->assign_segment(3,'mycategory');
$this->uri->assign_segment(4,'this-is-my-first-post');
And if you have error 'The uri you submitted has disallowed characters' then go to application/config/config.php and add - to this
$config['permitted_uri_chars'] = 'a-z 0-9~%.:_\-';
You could make a route that forwards to a lookup function.
For example in your routes.php add a line something like;
$route['product/(:any)/(:any)'] = "forums/cat_lookup/$1/$2";
This function would then do a database lookup to find the category.
...
public function cat_lookup($cat, $post) {
$catid = $this->forum_model->get_by_name($cat);
if ($catid == FALSE) {
redirect('/home');
}
$post_id = $this->post_model->get_by_name($post);
/* whatever else you want */
// then call the function you want or load the view
$this->load->view('show_post');
}
...
This method will keep the url looking as you want and handle any problems if the category does not exist.Don't forget you can store the category/posts in your database using underscores and use the uri_title() function to make them pretty,
Set in within config/routes.php
$route['song-album/(:any)/:num'] = 'Home/song_album/$id';
fetch in function with help of uri segment.
$this->uri->segment(1);

"Beautifying" a URL in Yii

I want to convert a URL which is of the format
path/to/my/app/Controller_action/id/2
to
path/to/my/app/Controller_action/id/User_corresponding_to_id_2
I have already seen this tutorial from Yii, but it isnt helping me with anything. Can anyone help me with this?
EDIT: I would also like to know if this thing is even possible in the POST scenario, ie I will only have path/to/my/app/Controller_action in the URL.
Add a getUrl method in your User model
public function getUrl()
{
return Yii::app()->createUrl('controller/action', array(
'id'=>$this->id,
'username'=>$this->username,
));
}
Add the following rule urlManager component in config/main.php
'controller/action/<username:.*?>/<id: \d+>'=>'controller/action'
And use the models url virtual attribute everywhere
dInGd0nG is on the correct track, but if I understand correctly you wish to do actions based on the actual username instead of the ID as well right?
It's not that hard in Yii. I'm assuming here for simplicity the controller is user and the action is view.
Your User controller:
public function actionView($id)
{
if (is_numeric($id))
$oUser = User::model()->findByPk($id);
else
// Luckily Yii does parameter binding, wouldn't be such a good idea otherwise :)
$oUser = User::model()->findByAttributes(array('username' => $id));
...
}
Your urlManager config:
'user/view/<id: \w+>' => 'user/view',
Or more generally:
'user/<action: \w+>/<id: \w+> => 'user/<action>',
To generate a user url in a view:
$this->createUrl('user/view', array('id' => $oUser->username));

Codeigniter: Calling a method from a view

Here's my model, what it does is pulls a particular post from a user. Each post may also have comments, which are stored in an array called comments. I have everything working and I'm able to display the post along w/ the comments. The issue is, each comment has a post_date that displays when the comment was made. I need to call the function that "converts" the date into something like "3 weeks ago." The method TimeAgo is located in my user_model.php page. The excerpt shows a variable called data that's actually for the post, the comment is embedded inside the array and I loop through that in my view.
So the question is, is there a better way of handling this or do I have to call the TimeAgo method from within the view page?
Note, I'm using mongodb but it shouldn't matter if it's mongodb or mysql. Same thing ...
user_model.php
$query = array("_id" => new MongoId($plan_id), "username" => $username);
$fields = array("plan_title", "comments", "post_date");
$data = $collection_plans->findOne($query, $fields);
$data['date'] = self::TimeAgo($data['post_date']->sec);
$data['username'] = $username;
return $data;
If my understanding is correct I'd put the TimeAgo method inside a library or helper, then (auto)load whenever necessary and process the date before passing it to the view from within the controller.
this would allow you to access that method from within another model if required, or indeed any other part of your CI app, rather than from just within user_model.php
You call the model method from the controller and put it into a variable. You then pass the var to the view.

Resources