Ok so i've got a big problem with CodeIgniter flexibility. I've many personal rules (like 20) targeting an input in a form within a huge project.
Everything work while I use the classic "callback_" system by CodeIgniter. I just put the methods in the same class than the form check and it checks it correctly.
My problem is :
1) I'd like to use all these rules in another form_validation in another controller without copy/paste the code ; we all know it's dirty/evil.
2) Ideally, i'd appreciate to put these rules in a big library, because it takes something like 800 lines and this is not a good idea to let it be in my controller ; as I said this project is quite huge.
It's 6 hours i'm looking for a solution and there's absolutely nothing clean :
I already have a MY_Form_Validation to put some general rules but i don't like the idea to mix my specific rules in a global class which will call it everytime vainly. Plus these rules contain many libraries, models, native CI core methods such as $this->input->post() which generate errors when I put everything in this MY_Form_Validation. Not the good solution :(
I created a MY_Controller including a method named 'imports' which re-generate selected libraries methods within the controller (in PHP4 it was kind of the 'aggregate_methods' function if people are curious) ; the system works perfectly but CodeIgniter doesn't understand it. The methods can be called within the controller but it seems the framework check the $CI content to call the rules (Form_validation.php line 590 in '/system/') so it doesn't work at the end ; it's also hard to modify this core part, I prefered not touching it and gave up.
$this->load->library('volt/lbl_validation');
$this->imports('Lbl_validation');
// Then you can call any $this->lbl_validation->method() with $this->method() in the controller
I tried to hack CI creating a customized form_validation within my library ('lbl_validation') ; the system was a bit messy but worked. The problem is when i came back to the CI form_validation system to show error messages, it was a true spaghetti-code which wasn't working that well. Not the good solution either.
I also tried some other shitty solutions but i prefer not confess it.
Now i'm here in front of my computer asking myself why bad things happened to good people, why this is so hard to separate set_rules from the called methods in CodeIgniter, why they didn't plan ahead people could've needed to call libraries methods as rules. I don't know what to do and i'm hesitating to put a dumb require() somewhere and make it all dirty and messy like my desk right now.
Maybe, there's someone with a good dans clean solution. All my hope are turned to the StackOverFlow community ; someone ? A crazy CI geek ?
Thank you ;)
The only good, DRY way to handle validation is to put validation rules at the last resort before saving to the the database, in other words in the models. By doing this, the same rules can be used in any controller or library without being redefined.
The following idea is taken from Jamie Rumbelows excellent Codeigniter handbook:
Simply create an array in your model:
$validate = array(
array( 'field' => 'username', 'label' => 'Username', 'rules' => 'required,trim' ),
array( 'field' => 'password', 'label' => 'Password', 'rules' => 'required|min_length[8]' )
);
Then implement a method that you can use to validate your data prior to save()
function validate($data) {
if (!empty($this->validate)) {
foreach ($data as $key => $value) {
$_POST[$key] = $value;
}
$this->load->library('form_validation');
$this->form_validation->set_rules($this->validate);
return $this->form_validation->run();
}
else
{
return TRUE;
}
}
Now, in your controllers you can use:
if ($this->user->validate($user))
save...
Related
Am little confused to follow the efficient way to post and process data in controller or model in CodeIgniter 3.1.5 (latest)
method:1 In the model
public function insert_entry()
{
$this->title = $_POST['title'];
$this->content = $_POST['content'];
$this->date = time();
$this->db->insert('entries', $this);
}
method:2 In Controller
public function insert_entry()
{
$title = $this->input->post("title");
$content = $this->input->post("content");
$date = $this->input->post("date");
$data = array(
'title' => $title,
'content' => $content,
'date' => $date
);
$this->model->insert($data);
}
Then process data and query in the model.
which is the efficient method to follow if we are creating a large scale web application.
Actually, there is no best way. Only there is Good Practice. Either way, you can archive this. But Model and Controller have different jobs.
Model Only interconnected with the database. And the controller is the one own Load it, initialize, pass it and all.
I personally recommend you is if it's a database related thing use model. Other than any perform it in Controller(Like File Upload, Validations, redirect, load URL). If we wrote code in an ethical manner it should understand by another developer. So if it's messy he/she can't understand any of these. So simply make it nice and clear .. always.
Read these
Model–view–controller
You should never use $_POST directly in CodeIgniter like this without good reason. Doing so means the data will not be automatically sanitized by the framework. The second method is therefore the way to go.
Here is some suggestion regarding your question.
First. User Input Class for post and get.
Base controller is also very helpfull for large scale projects. base-controller-and-apply-it-to-all-existing-controller
Codeigniter has a great validation Libraries Form Validation
Mainly I will suggest you is that please read out Codeigniter User Guide. It is great. I have also started From that.
I am adding some helpful links for better understanding.
Here is a Helper link of CodeIgniter forum for best practices
CodeIgniter Documentation
Ok after your comment I will suggest this:
Models meant to be doing all database related functionality. It is not must but as say we always follow the best practices so all DB related functions will be placed in the model.
The posted data form view will come first in the controller. (see input suggestion) then send that data to model and do the further process as required.
In CakePHP, I am trying to create a autocomplete function from a textbox, using this tutorial: http://bakery.cakephp.org/articles/matt_1/2011/08/07/yet_another_jquery_autocomplete_helper_2
I keep getting a
Error: AutoCompleteHelper could not be found.
Undefined index: autoCompleteText
I am unsure how to fix this as I have tried relocating the files and still the same error.
I create the below files and copy the code from the tutorial,
create the auto_complete.php in the view/helpers directory,
and create webroot/js/views/helpers/auto_complete.js.
controller - Tests
function auto_complete
class TestsController extends AppController {
public $helpers = array('Html', 'Form', 'Session','Js','AutoComplete');
public function auto_complete() {
$this->loadModel('Tutor');
debug( $this->params);
$terms = $this->Tutor->find('all', array(
'conditions' => array(
'Tutor.first_name LIKE' => $this->params['url']['autoCompleteText'].'%'
),
'fields' => array('Tutor.first_name'),
'limit' => 3,
'recursive'=>-1,
));
$terms = Set::Extract($terms,'{n}.Tutor.first_name');
$this->set('terms', $terms);
$this->layout = '';
}
view
auto_complete.ctp
<?php
echo $this->AutoComplete->input(
'Tutor.first_name',
array(
'autoCompleteUrl'=>$this->Html->url(
array(
'controller'=>'tests',
'action'=>'auto_complete',
)
),
'autoCompleteRequestItem'=>'autoCompleteText',
)
);
if(isset($terms)) {
echo $this->Js->object($terms);
}
echo $this->Form->create('');
echo $this->Form->input('type', array('label' => 'Choose' ));
echo $this->Form->end('send');
?>
I had a good look around previous posts and I really couldnt solve the problem.
Cakephp form input with autocomplete
The tutorial you're looking at is for CakePHP 1.x (it's from August 2011, Cake 2 came out in October '11), but you're running Cake 2.5. The naming standards have changed between 1.x and 2.x, so Cake can't see your helper.
First: Your main problem is that you're naming your helper auto_complete.php when it should be AutoCompleteHelper.php.
Second, you are placing it in the wrong directory. In Cake 1.x, helpers lived under /view/helpers/. In 2.x, they live under /View/Helper/.
Third, regarding the undefined index error, you need to understand how this helper works in the first place, and why you're implementing it incorrectly.
The controller action auto_complete should not have a view. It's just a data source. When you use the helper, it loads the Javascript, which does its magic by polling /auto_complete?autoCompleteText=stringgoeshere.
You might notice that you removed $this->layout = 'ajax'; from the controller action, probably because your toolbars weren't rendering. They weren't supposed to. It's just a datasource, it NEEDS the ajax layout, and there should be no view on that action.
Because you were trying to put a form on your auto_complete action and not on another action, the helper was looking for the query parameter autoCompleteText, not finding it, and displaying an error.
You can solve this by changing the auto_complete action back as close as possible to how it was in the example, deleting auto_complete.ctp, and by trying to use the helper in the correct view, like add.ctp.
Fourth: You shouldn't be using jsHelper anymore. It's been deprecated in 2.5 and is going to disappear in the future. Basically, the tutorial is obsolete.
However, it's really easy to just replace $this->set('terms', $terms); with return json_encode($terms) and write your own piece of JS to make an AJAX call. I suggest incorporating Typeahead.js.
Finally: You should consult the 1.x -> 2.x migration guide, and as well, once you get your helper running you've got some other typos in your code that will break it anyway- "Ttuor.first_name", for example. Good luck!
CakePHP will automatically assume that all model validation error messages in your $validate array are intended to be localized. But, I don't want to translate model validation messages. How to achieve this, any suggestion?
The simplest most easiest way would be just not translating those strings. So, if in your .po file
Mistake here -> Error aqui //don't do that
Mistake here -> Mistake here
And your validation errors are "translated" to the same language.
If you just don't want to filter yourself which strings are from validation and which are "normal" strings, change the validation domain of the models (do it in the AppModel so you'll only have to do it once).
class User extends AppModel {
public $validationDomain = 'validation_errors';
}
and now your validation messages will be in the new validation domain and not in default.pot, so you could just not translate the whole "validation_errors.pot" file and you'd be fine.
This part is only really valid for cake 2.5, I can't be sure if it applies to other versions
Now, if you want the really "difficult" way and just erase that functionality from the face of the earth, you'll have to overwrite some functionalities in Cake lib.
I'm not recommending changing the code directly in the the lib Folder, just extending the classes and replacing the in app/lib, otherwise upgrading versions will be a pain.
The class and functions you'll have to modify should be CakeValidationSet in lib/Cake/Model/Validator and the function is _processValidationResponse
All parts that have something like this
__d($this->_validationDomain, $result, $args);
should be replace with a vsprintf($result, $args) or similar (depending on the name of the parameters. This __d function is called 4 times inside that function, so replace all of them.
Personally, I'd just change the validation domain, wouldn't translate the file, and be done with it. Searching the code that translated this messages was really not worth the effort (except, you know, just to know how it's done).
I'm trying to learn more about the codeigniter framework by porting an existing website to it -- something that's not too complex, or so I thought.
Currently the site is replicated for its users and presents personalized data based on the url, for example, Joe might have his site at:
www.example.com/joe
www.example.com/joe/random-page.php
And you'd replace "joe" with any given user name. The URLs need to be structured this way: /joe/ isnt FOR joe, its for joe's visitors, so I can't rely on a user login or method of this sort. I could switch to joe.example.com but would rather not.
Is there a way I can make this play nice with Code Igniter?
Currently, it would want to call the joe controller. My initial thought is trying to find a way to have a default controller called when a controller doesn't exist, but if some CI pros have advice on a different, better way to handle this, it would be great.
Upgrade to CodeIgniter 2.0 and use $route['404_override'] = 'controller'; or install Modular Extensions which does the same thing, but for now they use $route['404'] instead.
There are a number of different ways to go about this. Just be warned, both of these solutions require you to edit CI's core files. That means you can't upgrade without breaking these edits. Unfortunately hooks do not suitably address this issue.
The easy way:
line 188-195 in system/vodeigniter/CodeIgniter.php handle the logic for what happens when a controller is not found.
The harder but better way:
There is a hook (http://codeigniter.com/user_guide/general/hooks.html)
pre_controller
But this will not work! The reason is that this is called after the controller has been determined, but before anything is actually executed. In other words, it is too late. The next earlier one
pre_system
is in fact too early, because routing has not been done and anything you do the routing will get overwritten.
So I needed the first controller to look the same, yet end up calling a different controller. The reason was that the page was accessed in a hierarchical way, so that it would be the subsection of a subsection and so on.
What I did was add on line 43 of system/libraries/Controller.php
$this->_ci_initialize();
Basically I had it autoload the libraries BEFORE the controller was called, because I was finding that the libraries were not loaded before the controller was called and I needed it to be done so because I needed to check user access authentication and hook directly into the routing itself.
After I did that, I extended one of the native core libraries that were autoloaded (in this case session, for applicaiton specific reasons) and then executed the rerouting.
$RTR = & load_class( 'Router' );
$this->URI = & load_class( 'URI' );
$this->URI->_fetch_uri_string();
I called this code in the start, then put my logic afterwards. This is a sample of what my rerouting logic looks like
if ( $this->segment( 1 ) == 'institute' )
{
if ( ! in_array( $this->segment( 3 ), $course ) )
{
$RTR->set_class( 'courseClass' );
$RTR->set_method( 'index' );
if ( ! $this->segment( 4 ) )
{
$RTR->set_class( 'course' );
$RTR->set_method( 'index' );
}
else
{
$RTR->set_class( 'course' );
$RTR->set_method( $this->segment( 3 ) );
}
}
The original is much longer. I probably should consider writing some sort of plugin or superior way to handle the rewriting rather than silly spagetti logic. However, I needed extremely fine grain control of the controllers being called based on the URLs. This will literally give you god mode control over your controller based on the URLs. Is it a hack? Yes. Is it inelegant? Absolutely. But I needed it done.
Just remember since this edits the core files, you can't easily upgrade after. I think the Kohana framework has a solution to this.
I kept reading the CI docs after Alex's post and found info on the routes.php file which does exactly what I needed.
It allows you to use regular expressions to rewrite the routes (URLs), much in the same manner as mod_rewrite, so I could strip out the user name and end up passing it as a param.
I have recently begun working on a PHP/JS Form Class that will also include a SQL Form builder (eg. building simple forms from sql and auto inserts/updates).
I have tried several classes (zend_form, clonefish, PHP Form Builder Class, phorms etc) but as yet haven't come across a complete solution that is simple, customizable and complete (both server side and client side validation, covers all simple html elements and lots of dhtml elements: sorting, wysiwyg, mutli file upload, date picker, ajax validation etc)
My question is why do some "classes" implement elements via an array and others via proper OO class calls.
eg.
Clonefish (popular commercial php class):
$config = Array(
'username' => Array(
'type' => 'inputText',
'displayname' => 'Username',
validation => Array(
Array(
'type' => 'string',
'minimum' => 5,
'maximum' => 15,
),
),
));
$clonefish = new clonefish( 'loginform', 'test.php', 'POST' );
$clonefish->addElements( $config, $_POST );
Then others eg. Zend_Form
$form = new Zend_Form;
$username = new Zend_Form_Element_Text('username');
$username->addValidator(new Zend_Validate_Alnum());
$form->addElement($username);
I realise Zend_Form can pass elements in via an array similar to clonefish but why do this?
Is there any benefit? It seems to make things more complicated especially when using a proper IDE like Komodo.
Any thoughts would be appreciated as I dont want to get too far down the track and realize there was great benefit in using arrays to add elements (although this wouldn't be much of a task to add on).
Cheers
My question is why do some "classes" implement elements via an array and others via proper OO class calls.
For convenience. It's less verbose and it feels less like coding and more like configuration and you need less intimate knowledge of the API.
Btw, the reason you have not yet come across a complete solution that is simple, customizable and complete is because it is not simple. Forms, their validation and rendering is complex, especially if you want to have it customizable for any purpose. ZF's form components are a good example of how to properly decouple and separate all concerns to get the ultimate extensible form builder (including client side code through Zend_Dojo or ZendX_Jquery). But they are also a great example of the complexity required for this. Even with the convenient array configuration, it is damn difficult to make them bend to your will, especially if you need to depart from the default configuration and rendering.
Why to use objects? Becouase they are a much more complex types. Consider the following example (I never useed Zend_Form so I don't even know its architecture):
class MySuperAlnumValidator extends Zend_Validate_Alnum {
protected $forbiddenWords = array();
public function addForbiddenWord($word) {
$this->forbiddenWords[] = $word;
}
// Override Zend_Value_Alnum::validate() - I don't know whether such a method even exists
// but you know what's the point
public function validate() {
parent::validate();
if (in_array($this->value, $this->forbiddenWords) {
throw new Exception('Invalid value.');
}
return $this->value;
}
}
// -----------------------
$validator = new MySuperAlnumValidator();
$validator->addForbiddenWord('admin');
$validator->addForbiddenWord('administrator');
$username->addValidator($validator);
This is only a simple example but when you start writing more complex validators/form fields/etc. then objects are, in principle, the only meaningful tool.