cakePHP basic ajax form problem - cakephp

i am trying to do a simple form that adds a new comment using ajax to a blog post (actually this is a part of a cakePHP tutorial)
but the problem is that the submit button do nothing at all
here is the part of code that generates the form in the view.ctp file
<?php echo $ajax->form('/comments/add', 'post', array('url' => '/comments/add', 'update' => 'PostsComments', 'indicator' => 'commentSaved'));?>
<fieldset>
<legend><?php __('Add Comment');?></legend>
<?php
echo $form->hidden('Comment.post_id', array('value' => $post['Post']['id']));
echo $form->input('Comment.name');
echo $form->input('Comment.content');
?>
</fieldset>
<?php echo $form->end('Submit');?>
and here is the add comment action in the comments_controller.php
if (!empty($this->data)) {
$this->Comment->create();
if ($this->Comment->save($this->data)) {
$comments = $this->Comment->find('all',array('conditions'=>array('post_id'=>$this->data['Comment']['post_id']),'recursive'=>-1));
$this->set(compact('comments'));
$this->render('add_success','ajax');
} else {
$this->render('add_failure','ajax');
}
}
the problem is that the action add isnt called from the view ... when i viewed the generated html source code i found something like that
<form id="form304217296" onsubmit="event.returnValue = false; return false;" method="post" action="/php-cake/blog/comments/add"><fieldset style="display:none;">
if i removed the on submit tag manually then the action is called but the add_success.ctp is generated as a new page not as an ajax call.
so what could be the problem ?

finally i have discovered the problem
there was more than one mistake in the tutorial (chapter 8 in CakePHP from novice to professional) after fixing those errors i found another problem is that cakephp v1.2.6 is not compatible with the latest version of prototype (v1.6.1)
as it gives the following error in firebug
Event.observe is not a function
so i used version 1.6.0.3 of prototype and the problem was solved.
for a list of mistakes in this chapter see this

Do you include prototype and scriptaculus in your View/Layout (both are needed for the Ajax-helper)? Also there might be an interference with jquery if you use that too

Related

How is current and modified time is saving in CakePHP's blog tutorial?

I have just started learning CakePHP and I started with the official blog tutorial. So far so good but I am not getting how current and modified time is saving in db because neither in views nor in controller there is any line which points to these fields.
Here is PostsController.php code for add:
public function add()
{
if($this->request->is('post'))
{
$this->Post->create();
if($this->Post->save($this->request->data))
{
$this->Session->setFlash(__('Your post has been saved.'));
return $this->redirect(array('action' => 'index'));
}
else
{
$this->Session->setFlash(__('Unable to add your post.'));
}
}
}
And here is view code for add.ctp:
<!-- File: /app/View/Posts/add.ctp -->
<?php echo $this->Html->link('Home', 'index/home'); ?>
<h1>Add Posts</h1>
<?php
echo $this->Form->create('Post');
echo $this->Form->input('title');
echo $this->Form->input('body', array('rows' => '3'));
echo $this->Form->submit('Add Post', array('name' => 'add_post'));
//echo $this->Form->end('Save Post');
?>
So someone please tell me which line is saving current time? Thanks a lot for help.
There's a hidden function inside the default Cake parent model that checks for fields with the name 'created' and 'modified', and updates the values automagically.
Search inside /lib/Cake/Model/Model.php for the string 'modified', and you'll see lots of references to this.
I'm not sure how well this is documented, I came across it while debugging some funky saving behavior.
In my system I settled on the fields 'created_at' and 'modified_at' before I found this little gem.
EDIT: This is documented here:
http://book.cakephp.org/2.0/en/models/saving-your-data.html#using-created-and-modified
Check if AppModel.php contains function save(){} and UpdateAll(){}. Next check datatype of created and modified fields in mysql. then modify your question for more clarity.

CakePHP 2 pagination gives 404 address not found error

I am developing an application with CakePHP 2.3 and am having a problem with pagination. When I click on any of the pagination links I am getting a /cab/ServiceDirectory/refine/page:2 (or which ever link) was not found on this server. If I go to /cab/ServiceDirectory/refine I see the pagination links showing there should be 5 pages. If I remove the pagination code from the controller and the view I see all the results I should see.
In my ServiceDirectoryResultsController I have
public function index() {
$this->ServiceLocation->recursive=0;
}
public function refine ($id=null) (
// All my code to get the ServiceLocations from the DB
$this->paginate->array(
'conditions' => array('ServiceLocation.state' => $states[$state], 'ServiceLocation.solution_categories' => $active_cat),
'limit' => 8,
);
$results = $this->paginate('ServiceLocation');
$this->set('serviceLocation' ,$results);
}
In my View I have
<div class="paging">
<?php
echo $this->Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));
echo $this->Paginator->numbers(array('separator' => ''));
echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));
?>
</div>
<?php foreach ($serviceLocation as $Location): ?>
// I echo a few things from the $Location array
<?php endforeach; ?>
<div class="paging">
<?php
echo $this->Paginator->prev('< ' . __('previous'), array(), null, array('class' => 'prev disabled'));
echo $this->Paginator->numbers(array('separator' => ''));
echo $this->Paginator->next(__('next') . ' >', array(), null, array('class' => 'next disabled'));
?>
</div>
Without the paging and use doing a find all and sending that to the view I see the 40 results I would expect.
With the pagination in I see the pagination links and if I hover over them I see my url /cab/ServiceDirectoryResults/refine/page:2 or page:3 or page:4 or page:5
If I click on any of these links with the :pageX on them I get an error
Error: The requested address '/cab/ServiceDirectoryResults/refine/page:2 was not found on this server'
I have done a lot of reading about the CakePHP paging and can not find any reason for this behaviour. Can anyone suggest a reason or a possible solution or a path to follow to debug this error?
Regards
Richard
I checked the error level and it was already set to level 2
Here is the last entry in the error log
2013-05-22 17:09:28 Error: [NotFoundException] Not Found
Request URL: /cab/ServiceDirectoryResults/refine/page:2
Stack Trace:
#0 /var/www/html/cab/lib/Cake/Controller/Controller.php(1074): PaginatorComponent->paginate('ServiceLocation', Array, Array)
#1 /var/www/html/cab/app/Controller/ServiceDirectoryResultsController.php(381): Controller->paginate('ServiceLocation')
#2 [internal function]: ServiceDirectoryResultsController->refine()
#3 /var/www/html/cab/lib/Cake/Controller/Controller.php(486): ReflectionMethod->invokeArgs(Object(ServiceDirectoryResultsController), Array)
#4 /var/www/html/cab/lib/Cake/Routing/Dispatcher.php(187): Controller->invokeAction(Object(CakeRequest))
#5 /var/www/html/cab/lib/Cake/Routing/Dispatcher.php(162): Dispatcher->_invoke(Object(ServiceDirectoryResultsController), Object(CakeRequest), Object(CakeResponse))
#6 /var/www/html/cab/app/webroot/index.php(109): Dispatcher- >dispatch(Object(CakeRequest), Object(CakeResponse))
#7 {main}
Hope that helps
FYI: I'm using Cakephp 2.4, I've only tested it on this version.
I ran into this same issue. I store the pagination variables in the user's session.
This way when a user navigates away from a page, they don't loose their place (page/sort field/direction) when they come back to the page.
Because I store the variables in the session, then retrieve them from the session, if say the user clicks on a link that causes the results to be less then the page they were on, I'll get a 404.
Example (The page they were on):
http://localhost/products/index/page:5/sort:Product.name
I send them this link:
http://localhost/products/index/search:[search_term]
This filters the results to only 2 pages.
In this case, actual (perma)link, with the session variables restored, would look like:
http://localhost/products/index/page:5/sort:Product.name/search:[search_term]
Page 5 is out of the scope of the 2 pages from the new results.
This will throw the NotFoundException(); seen here:
http://api.cakephp.org/2.4/source-class-PaginatorComponent.html#238
How I resolved this was to catch the exception, then redirect them to the first page.
Since all of the pagination variables (including the 'search') are stored in the session, I only need to pass the page variable:
Example:
http://localhost/products/index/page:1
Cakephp recommended this as a possible way to overcome it:
http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html#out-of-range-page-requests
However, I wanted this available for all of my 'index' pages, so I overwrote the Controller::paginate() method in the AppController.
Original paginate method seen here:
http://api.cakephp.org/2.4/source-class-Controller.html#1070-1081
Here is how I did it in my Controller/AppController.php:
<?php
class CommonAppController extends Controller
{
// ..... other code
public function paginate($object = null, $scope = array(), $whitelist = array())
{
/*
* Used to see if we get an exception thrown,
* If so, send them to the first page, and set the flash so they know
*/
try
{
// taken from their current paginate();
// http://api.cakephp.org/2.4/source-class-Controller.html#1070-1081
return $this->Components->load('Paginator', $this->paginate)->paginate($object, $scope, $whitelist);
}
catch (NotFoundException $e)
{
//Do something here like redirecting to first or last page.
//$this->request->params['paging'] will give you required info.
$page = (isset($this->request->params['named']['page'])?$this->request->params['named']['page']:1);
$this->Session->setFlash(__('Unable to find results on page: %s. Redirected you to page 1.', $page));
return $this->redirect(array('page' => 1));
}
}
// ..... other code
}
?>
8 months later...I just bumped into the same issue, and thought I could leave my findings here to avoid somebody else spending a couple of hours looking for a solution like I have been.
I had the same issue as Richard, when a GET request onto any other link of the pagination split bar, from 2 to n, was to generate a 404 error.
This 404 error originates from the PaginatorComponent (CORE/Cake/Controller/Component/PaginatorComponent.php), in these lines:
$pageCount = intval(ceil($count / $limit));
$requestedPage = $page;
$page = max(min($page, $pageCount), 1);
if ($requestedPage > $page) {
throw new NotFoundException();
}
In a nutshell, this happens when the predicative conditions member has become so restrictive as to create a much smaller recordset than for page #1.
What can create this is that it now contains more predicates in it, that you just do not want. A way to see what it contains for page #2+ is to add this call:
FirePHP($parameters);
just before the lines above. You may be surprised.
The question is "why does conditions, that you should build in your controller and pass to the find() method, has changed so much from page #1 that works, to page #2+ that does not?
I cannot just answer for you without seing the rest of your code, but I can tell you what was happening for my case:
I was storing some values in $_SESSION so that my search could be remembered, and I was relying on isset($this->request->data[$objectName]) to know if I should add that particular predicate to my 'conditions' array. But that was without thinking that only page #1 is the result of a POST method, not the subsequent paginated requests pages, which are got through GET method. Therefore from page #2 onwards, $this->request->data[$objectName] is empty, but SESSION was still set because I had forgottent to reset it.
The conclusion is: remember page #2+ calls are GET, and the request data that you may have used and were working for POST are no more valid, creating a different set of conditions now, reducing your recordset, and creating a total count that may be 0, voiding the pagination system, hence the 404.
I came across the same issue for CakePHP3. The quickest way to solve is to change the form action so that it do not grab the "?page=x" part of the URL. For example, change it to current page URL like
<form action="<?=\Cake\Core\Configure::::read('App.domain')?>/page_url" ...

blackhole cakephp 2 associated entities

My Goal:
Reuse of a contact form to be related to several different entities I call "Parents" ie Group has contact information, Member has contact info etc....
The way I tried doing it was:
1. Creating a view file for contact, named "form.ctp" which doesn`t create a new form, nor submits, just echo's the contact's fields.
2. Calling this file using requestAction
My Problem:
The form's _Token get crumbled.
Parent add.ctp example
<?php echo $this->Form->create('Group');?>
<fieldset>
echo $this->Form->input($field_prefix.'contact_id',array('type'=>'hidden'));
<?php echo $this->requestAction(array('controller' => 'contacts', 'action' => 'form'), array('named' => array('index'=>'0','parent'=>'Group',
'fields'=>array(
'email'=>array('value'=>'xx#yy.com','hidden'=>1)
))));
inside the form.ctp I have:
//Associated Model
echo $this->Form->input('Contact.0.city',array('type'=>'hidden'));
echo $this->Form->input('Contact.0.postcode');
echo $this->Form->input('Contact.0.phone');
echo $this->Form->input('Contact.0.cellphone');
echo $this->Form->input('Contact.0.email',array('value'=>""));
echo $this->Form->input('Contact.0.id',array('type'=>'hidden'));
?>
Looking at the HTML source code that is generated, I see that whether I use the request action or just copy the contect of the form.ctp into the "Parent's" add file, I get the same HTML result.
HOWEVER!!! when I use the form.ctp Action Request, I get the blackhole, the tokens are being messed up!!!
Any Ideas?
Thanks in advance
Orly
If your problem is solely reusing a form, you can use the form as a Element, and then you could call it multiple times, substituting in the exact values you need.
As for SecurityComponent, I would recommend (at least as a temporary fix) disabling SecurityComponent for that specific action by using $this->Security->unlockedActions(); in your controller's beforeFilter()

Including JS in default View in Cake PHP

I can do this in any of my View file in Cake PHP:
<?php echo $this->Html->script('myjs.js', false); ?>
but if I do the same thing in my default view (default.ctp) then the JS files don't load i.e. they don't get echoed. I have tried moving includes above and below <?php echo $scripts_for_layout ?> in the default view but they still don't get printed:
<?php echo $scripts_for_layout ?>
<?php echo $this->Html->script('myjs.js'); ?>
<?php echo $this->Html->script('myjs.js'); ?>
<?php echo $scripts_for_layout ?>
Any ideas?
Thank you :).
with or without an extension - this is not the reason why the script do not get echoed,
as mensch mentioned before it makes no difference because of:
source of html helper cakephp 2
if (strpos($url, '?') === false && substr($url, -3) !== '.js') {
$url .= '.js';
}
the reason is:
you have already inserted this script inside your view,
cake checks if the script is already inserted on the page
options - 'once' - Whether or not the script should be checked for uniqueness. If true scripts will only be included once, use false to allow
the same script to be included more than once per request.
by default the value of once is set to TRUE
remove the script from your view first and then try it with or without '.js'
P.S.: why the petervaz answer has worked for you:
because this check:
if ($options['once'] && isset($this->__includedScripts[$url])) {
return null;
}
made before check for file extension
so isset(__includedScripts['myjs']) == false // because first key was __includedScripts['myjs.js']
and you've got your script included
I have a project with scripts added just before $scripts_for_layout and they are displayed fine. The only difference is that I'm not adding the extension .js to the call, like this:
default.ctp:
<head>
<?php echo $this->Html->charset(); ?>
<title>
<?php echo "Site > $title_for_layout"; ?>
</title>
<?php
echo $this->Html->script('jquery-1.6.4');
echo $this->Html->script('jquery-ui-1.8.16.custom.min');
echo $this->Html->script('mercado');
echo $scripts_for_layout;
?>
</head>
Another thing I'd DEFINITELY recommend is to check that loading your JS in a view is 100% OK with everything.
Do NOT use $this->Html->script if you are unsure about:
--- the dependency of scripts on each other
--- the dependency of some plugins on other scripts
--- how many different layouts and/or views you want to use in the future.
For example, some plugins use jQuery but they require jQuery to be loaded BEFORE the plugin itself.
So if you put jQuery in a view or layout, the plugin's JS loads before jQuery and plugin may not work. If you want to make sure some script loads first, you can try this:
in your app/View/Helper/AppHelper.php:
class AppHelper extends Helper {
public $helpers = array('Html', 'Session');
public function beforeRender($viewFile){
echo $this->Html->script('jquery', array('inline'=>false));
}
}
Therefore you don't have to include jQuery in multiple views and it loads first.
$scripts_for_layout in a layout is a placeholder for all the scripts included in views, so if you include it or don't won't have any effect if you load scripts directly in the default.ctp.
That being said, adding the extension or leaving it out of the $this->Html->script() call shouldn't make a difference. What could be the case is that the HtmlHelper isn't called correctly (it's called by default in Cake 2.0), but you should be receiving error messages. Is debug set to 2 in /app/Config/core.php?

Cakephp Validation

I am using an Account Controller which doesnt have its own table but uses User Model.
All works fine except - when I validate any form. It says validation fails (when I try to fail the validation to check) but doesnt throw the error below the field
View
<?php echo $this->Form->input('id'); ?>
<label for="UserPassword">New Password:</label>
<?php echo $this->Form->text('password', array('type' => 'password', 'value' => 'harsha')); ?><em>Password must be min 6 characters.</em> <?php echo $form->error('password'); ?>
Controller Action
if($this->User->saveField('password', $this->data['User']['password'], array('validate' => 'first'))) {
$this->Session->setFlash('Password has been changed.', 'flash-success');
} else {
$this->Session->setFlash('There was some problem with our system. Please try after some time.', 'flash-warning');
}
Try debug()ing the contents of $this->validationErrors in your view, as well as $this->data in your controller just after a form submission. This should give you a lot more information to work from.
I suspect that your problem is Cake is building form inputs based on the wrong model -- building form fields for Account.id and Account.password instead of User.id and User.password. This is because FormHelper takes its default model from the controller/view it's invoked from, which in your case appears AccountsController.
In order to generate the User.id and User.password fields your controller's submission handling expects, you'll need to prepend User. in your FormHelper calls. Thus:
$this->Form->input('User.id');
$this->Form->text('User.password');
Have you tried:
echo $session->flash();
Note that whatever the manual says, it returns, not echoes. I logged this a while back and it has been changed in the 1.3 manual, but not the 1.2.
Hi you who's asking If you want to show error-message that return from UserModel's validate So you can add line code bellow after input form password
<?php
if ($this->Form->isFieldError('password')) {
echo $this->Form->error('password', array('class' => 'error'));
?>
and if you want to show error-message that set by method setFlash
you must redirect page and then use $this->Session->flash('flash-name') in page you want to show it
<?php
//in UsersController
$this->Session->setFlash('message here', 'flash-name');
//in view
echo $this->Session->flash('flash-name');
?>
Good luck!

Resources