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'];
Related
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.
Here's how my model works. I have a Post model that has a expires_at column. Users provide an integer for the number of days they would like the Post to last.
This was pretty straightforward when I was doing validation in the controller. Just validate the "days" field and then transform that into a future expiration date. But now I'm doing the validation in the model with Ardent and I'm not sure how to accomplish this. I think I need to use a mutator but setting expires_at as an integer seems counterintuitive. I'm also not sure if Ardent validates before or after mutation.
I figured out how to do it using the code that removes redundant from data like confirmation fields.
public $autoPurgeRedundantAttributes = true;
function __construct() {
parent::__construct();
$this->purgeFilters[] = function($key) {
$purge = array('tempData', 'myAttribute');
return ! in_array($key, $purge);
};
}
You need to enable $autoPurgeRedundantAttributes or the filters won't be called. Then you add a closure to the $purgeFilters array which returns false if the provided attribute should be removed. ("days" in this case)
Then you just need to make sure to manually set the field you want validated
$this->attributes['days'] = $value;
Edit: This is in the official docs now. I replaced my code above with theirs.
I am trying to do some very simple validation in my CakePHP contact form, but validation does not work eventhough I think I did everything necessary. Here's what I did:
I made a model like this:
class Office extends AppModel
{
var $name = 'Office';
var $useTable = false;
public $validate = array('onderwerp' => 'notEmpty');
}
(I also tried many other values for $validate from the CakePHP online manual)
In Config/bootstrap.php I made this rule for not letting CakePHP expect plural "Offices":
Inflector::rules('plural', array('rules' => array(),
'irregular' => array(),
'uninflected' => array('office')));
In OfficeController, I do this in my method contact():
$this->Office->set($this->request->data);
if($this->Office->validates()){
echo "code validates";
} else {
print_r($this->Office->validationErrors);
}
And in my Office/contact.ctp view, I have (amongst other code like starting and ending the form) this code:
$this->Form->input('onderwerp', array('label'=>false, 'size' => 60));
Now, even when I fill in the form, leaving empty the field 'onderwerp', it executes the code that should be executed when the code is executed.
When I print_r($this->request->data) or print_r($this->Office) I see that my onderwerp field is there and that it is empty (or filled when I do fill in something).
Now, when I add a public function validates() in my model and echo something there, it IS being displayed. So I'd say CakePHP knows where to find my model, and does execute my controller code. I also tried adding return parent::validates(); in my validates() function, but this also yielded no validation error, or any other error for that matter. My debug level is set to 2.
I guess I'm missing a needle in this haystack. Thanks for helping me finding it!
so drop all the inflector stuff.
and use the right model in your Form->create()
either
$this->Form->create(null)
or
$this->Form->create('Office');
and if you follow my advice to use a table less model with schema you will also have more power over input creation and validation.
I have a registration form with about 30 fields (yes.. I know.. insanity). I need some of these fields to be required by certain types of people. What I'd like to do is just use a query string like example.com/user/register/?type=notrequired. If type = notrequired then I'd like to make to make the fields not required. Is this possible? I tried using the jQuery Validate plugin but its not working.. I'm thinking the built in Drupal validation is conflicting with it :(
The required flag is set server side so I doubt you'll be able to affect it using javascript. You'll have to hook into the form and make the changes in PHP, something like this in a custom module:
function mymodule_form_user_register_form_alter(&$form, &$form_state, $form_id) {
if (isset($_GET['element_name']) && $_GET['element_name'] == 'notrequired') {
$form['element_name']['#required'] = FALSE;
}
}
Hope that helps
i'll try and be as clear as possible.
I'm working on some form validation using the wonderful kohana framework. However i have come at a crossroads and not sure whether the way i have taken is a wise choice.
Basically, i have a date selector using several select boxes (i toyed with the idea of using javascript date pickers but the select boxes proved to be more suitable for my purpose) and a date field in a database. I wanted to concatenate these select boxes into the date field so it can be checked to make sure its valid.
protected $_rules = array(
'mydate' => array(
'not_empty' => NULL,
'date' => NULL,
),
);
Now to me, it makes most sense to include the validation in the model, since that's where the data layer is in the MVC pattern, so i decided to create some class attributes named $_rules, $_filters and $_callbacks, each set as protected and with my basic rules applied. And then a function in the model that sets up a validation object using these attributes and returning it to whatever controller is calling it, then the controller can just run the validation and the job is done.
My problem comes when i want to concat these select boxes, to me it makes most sense to make a custom filter and pass in the post data, but with the filters rules and callbacks being attributes, i can't add any variables to them. My current solution is to manually add the extra filter in when the validation setup function is being run something similar to this:
public function setupValid($post) {
$this->_filters['mydatefield'] = array(
'MyClass::MyConcat' => array($post);
);
//creates a validation object and adds all the filters rules and callbacks
}
But i don't feel this is the cleanest solution, i'm probably nit picking as the solution works the way i require it to. However i'm not sure whether a filter was ever intended to do such a thing as this, or whether this should be a callback as the callback has access to the array by default, but then again callbacks are called last, which would mean i couldn't apply any rules like, 'not_empty' (not important in this case since they are pre populated select boxes, but might be in another case)
So i guess my question is, am i using filters as they were intended to be used?
I hope i've managed to explain this clearly.
Thanks
you need to keep in mind that you should only validate fields inside the $_rules that are very important to your database or business logic.
so for example if you would try to setup other form somewhere else in your app or you would provide a restfull api for your app, validation of the field 'day_field_(that_doesnt_exists_in_the_database_and_is_used_to_privide_a_better_ux_in_this_one_form)' => array('not_empty' => NULL) will give you a hard time to do that.
so i suggest you to keep your $_rules like they are now and provide some logic to your values() method:
// MODEL:
public function values($values)
{
if ( ! empty($values['day']) && ! empty($values['month']) && ! empty($values['year']))
{
$values['mydate'] = $values['year'].'-'.$values['month'].'-'.$values['day'];
}
return parent::values($values);
}
// CONTROLLER:
if ($orm->values($form['form_array'])->check())
{
$orm->save();
}
else
{
$this->template->errors = $orm->validate()->errors('validation');
}