cakephp: no save, no validate errors, no callbacks, empty sql log - cakephp

In my controller i have this add function:
public function add(){
$this->layout = false;
if($this->request->is('post')){
$this->Paciente->create();
$this->Paciente->set($this->request->data);
if ($this->Paciente->validates()) {
if($this->Paciente->save()){
$this->set('status', '200');
} else {
// debug($this->Paciente->validationErrors);
// ini_set('memory_limit', '-1');
// var_dump($this->Paciente);
$this->set('status', '101');
// $log = $this->Paciente->getDataSource()->getLog(false, false);
// debug($log);
// die;
}
} else {
// didn't validate logic
// $errors = $this->Paciente->validationErrors;
// debug($errors);
$this->set('status', '100');
}
} else
$this->set('status', '404');
}
I'm sending the post info and the status is always 101. As you can see I have tried a lot to find out where is the error, but no luck.
Also I don't have any callback in my Model (beforeSave, afterSave...)...
Anyone knows what is happening?

Your
if ($this->Paciente->validates()) {
if($this->Paciente->save()) {
}
is wrong.
You are validating twice.
Please - as documented - either use false (save(null, false)) to not invalidate twice or simply remove the validates() part here.
You can directly do:
if ($this->Paciente->save($this->request->data)) {}
This itself is unlikely causing your issue, though.
Or do you have some custom validation rules that on second (and faulty) trigger will make a field invalidate?
You can confirm that by checking $this->Paciente->validationErrors afterwards. It should be empty. If it does not save (and it's for sure no callback), and if it does not throw exceptions due to SQL errors then it most likely are your validation rules.

The problem was in the way i was sending the post info:
I was setting the variables as data['Model']['var'] and the correct way is data[Model][var]
Thanks #mark, #AD7six, #liyakat and #Alex for your help in the problem.

I can't imagine. When you set your array values like above it would likely break in php5.3 >

Related

Stumped on Drupal 7 - adding user_profile_form #validation callback via hook_form_alter

I've searched, read, and re-read. I've even stripped a test module down to the most basic elements.
I think this code should work, but the validation callback is never called. I add the callback to the form, but it is gone at the next steps.
Ultimately, my goals is to "validate" submitted usernames, in order to meet a specific business objective. I'm getting stuck just adding the form validation callback, but I'm confident that once that hurdle is overcome, the rest of the functionality is straight forward.
Can someone smarter than me please point me in the right direction to properly add a validation callback?
<?php
/*
Implements hook_form_alter();
*/
function mymod_form_alter($form, $form_state, $form_id) {
// catch the user profile form.
if('user_profile_form' == $form_id) {
// set debug message
drupal_set_message(t('adding validation callback in hook_form_alter()...'), 'warning');
// add a validation callback
$form['#validate'][] = 'mymod_user_profile_form_validate';
}
}
/*
Implements hook_form_<form_id>_alter();
If mymod_form_alter() was successful, I wouldn't need this hook, it's just here for verification.
*/
function mymod_form_user_profile_form_alter($form, $form_state, $form_id) {
// check to see if our validation callback is present
if(!in_array('mymod_user_profile_form_validate', $form['#validate'])) {
// our validatiation callback is not present
drupal_set_message(t('The validation callback is missing from #validate in hook_form_[form_id]_alter()'), 'error');
// since it's not there, try re-adding it?
$form['#validate'][] = 'mymod_user_profile_form_validate';
} else {
// We should see this message, but don't.
drupal_set_message(t('The validation callback exists!'), 'status');
}
}
/*
?? Implements hook_form_validate(); (or not...) ??
*/
function mymod_user_profile_form_validate($form, $form_state) {
// why is mymod_user_profile_form_validate() never called??
drupal_set_message(t('Validation callback called! Whoopee! Success!'), 'status'); // This never happens!
// if this was working, we would do a bit of logic here on the username.
//for this test, let's assume we want to return an error on the username field.
form_set_error('name', t('Blah, blah, blah, something about your username...'));
}
The variables $form and $form_state should be passed by reference so that your hook function can actually modify them (otherwise the function just get a copy).
You need to use & (ampersand) symbol added before variable argument in the function signature :
function mymod_form_alter(&$form, &$form_state, $form_id) {
# $form is referenced from the global scope using '&' symbol
$form['#validate'][] = 'mymod_user_profile_form_validate';
}

Which Parsley.js method should I use for adding/updating accessibility attributes?

I have a parsley-config.js file in which I have successfully added lots of customizations to parsley, utilizing the methods described on Parsley's defaults.js documentation. However I'm having trouble figuring out how to add some attributes to elements upon validation. the classHandler method looked promising but only ran on initialization, not when validating.
Here's a little of the code I'm thinking of using. I just need to know what Parsley method I should stick it in.
var ParsleyConfig = {
mysteryMethod: function(parsleyField) {
var $field = parsleyField.$element;
// Acessibility attributes based on error or not
if (parsleyField.validationResult.length > 0) {
$field.attr({'aria-describedby': parsleyId, 'aria-invalid': true});
} else {
$field.removeAttr('aria-describedby').attr({'aria-invalid': false});
}
...
}
Best is probably to listen to the events field:success and field:error or similar...

Validation doesn't work?

I have some code:
var Person = new Backbone.Model({name: 'Jeremy'});
Person.validate = function(attrs) {
if (!attrs.name) {
return 'I need your name';
}
};
Person.on("invalid", function(model, error) {
alert(model.get("title") + " " + error);
});
Person.set({name: 'Samuel'});
console.log(Person.get('name'));
// 'Samuel'
Person.unset('name', {validate: true});
console.log(Person.get('name'));//Why can i print name here if it unsetted?
When i type unset method i see an error alert. It's correct. But why can i print in console the name if it was unsetted?
The name is still there because the validation failure stopped the unset from doing anything.
The documentation isn't very explicit about how validation works with set and unset but it is quite explicit with save:
validate model.validate(attributes, options)
[...] If validate returns an error, save will not continue, and the model attributes will not be modified on the server.
So it is reasonable to think that validation errors will prevent the current operation (set, unset, save, ...) from changing anything.
You can see how it works by examining the Backbone source code. First, you need to know that unset is just a set call in disguise:
unset: function(attr, options) {
return this.set(attr, void 0, _.extend({}, options, {unset: true}));
}
So we look at set:
set: function(key, val, options) {
// A bunch of boring bookkeeping stuff...
// Run validation.
if (!this._validate(attrs, options)) return false;
// The stuff that changes attributes and triggers events.
}
The validations happen as soon as set knows what it is working with and set returns without changing anything if the validations fail.
The Backbone documentation leaves a lot of important things out so you need to be passingly familiar with the Backbone source if you're going to use Backbone. The source is fairly straight forward, don't be afraid to jump into it to see what's going on.
Do this: To not trigger events you can use the silent:true option. I believe there might be some issue upstream in your code. Anyways, do the following - it should work. ( in my tests, it did ).
Person.unset('name',{validate: true,silent:true})
p.s.: Mu ( below ) gives great information.

How to properly exit from a custom blackhole handler?

My problem is fairly basic: whenever an action in CakePHP is blackholed, I want to display a custom error page; the default behaviour of Cake to display a "File not found" message confuses the hell out of users (not to mention developers). So I came up with this, by searching the docs and StackOverflow:
class TestsController extends AppController
{
public $components = array ('Security');
public function beforeFilter ()
{
parent::beforeFilter ();
$this->Security->blackHoleCallback = 'blackhole';
$this->Security->csrfExpires = '+5 seconds'; // for testing
}
public function index ()
{
}
public function doit ()
{
$this->log ('Performing request; entry = ' . $this->data['foo'], 'tests');
$this->set ('foo', $this->data['foo']);
}
public function blackhole ($type)
{
$this->log ('Request has been blackholed: ' . $type, 'tests');
$this->render ('/Errors/blackhole');
$this->response->send ();
exit ();
}
}
In index.ctp there is a simple form with a single textbox, that commits to doit (excluded for brevity). This works, but I have one major issue: the exit() in the blackhole() function. The problem is, if I do not exit here doit() is still called, even if the request is blackholed, as evidenced by the log:
2013-01-30 15:37:21 Tests: Request has been blackholed: csrf
2013-01-30 15:37:21 Tests: Performing request; entry = kfkfkfkf
This is clearly not what you expect. The Cake documentation hints at using (custom) exceptions to stop processing in blackhole(), but that:
completely beats the purpose of using a custom handler;
adds another layer of complexity to something that should be simple.
My question is: is there a proper way to do an "exit" from blackhole() so that Cake does all the rendering/cleanup/etc. that it usually does; I already had to add $this->response->send() to force output to the browser. Or, althernatively, a way to tell Cake to skip calling doit() after blackhole().
My suggestion would be to redirect in your blackhole.
This is done e.g. here in the cookbook http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html#usage
$this->redirect(array('controller' => 'test', 'action' => 'index'));
A redirect will issue an exit (http://book.cakephp.org/2.0/en/controllers.html#flow-control).
You can also send something nice to the user if you want, before the redirect:
$this->Session->setFlash('What are you doing!?');
In your blackhole callback you could just throw an exception with required message. That would render the proper error page and get logged too (assuming you have turned on logging for errors in core.php).

Can I make CakePHP return a suitable status code based on certain conditions?

This question is slightly related to my old post Dealing with Alias URLs in CakePHP
After much thought, I am exploring the option of having a custom 404 script in my Cake App, that is reached when a URL does not map to any controllers/actions. This script would check $this->here and look it up in a database of redirects. If a match is found it would track a specific 'promo' code and redirect.
I'm thinking status codes. Can I make my script return a suitable status code based on certain conditions? For example:
URL matches a redirect - return a 301
URL really does not have a destination - return a 404.
Can I do this?
EDIT:
What about this? Anyone see any problems with it? I put it in app_controller.
function appError($method, $params) {
//do clever stuff here
}
This should work. Assuming you redirect 404's at a LegacyUrls::map() controller action. The code needs to be stored in app/app_error.php:
<?php
class AppError extends ErrorHandler{
function error404($params) {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch('/legacy_urls/map', array('broken-url' => '/'.$params['url']));
exit;
}
function missingController($params) {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch('/legacy_urls/map', array('broken-url' => '/'.$params['url']));
exit;
}
}
?>
Good luck!
I've always created app\views\errors\missing_action.ctp and app\views\errors\missing_controller.ctp
Cake will automatically display one of those views when a url does not map out to a controller or its methods.
Unless there is a certain need for the error codes that you did not give, this would work perfectly!
I'd like to augment felixge's answer.
This version outputs a 404 error to the browser:
class AppError extends ErrorHandler
{
function _outputMessage($template)
{
if ($template === 'error404') {
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch('legacy_urls/map', array('broken-url' => '/'.$params['url']));
return;
}
parent::_outputMessage($template);
}
}

Resources