So I started to play around with cakePHP after i did the blog tutorial (yes im new), and i would like to do something complicated. Like, theres a comment form, which is simple it contains Name and the Comment. And I would like to send the data to another application in the same host, which is save this comment in the DB. Currently the Comments/add.ctp saves it.
Thanks for any advice!
So theres the CommentsControll.php
<?php
class CommentsController extends AppController{
public $components = 'Session'
public function add(){
if($this->request->is('POST')){
$this->Comment->create();
if($this->Comment->save($this->request->data)){
$this->Session->setFlash('Your comment is saved!')
}
}
}
}
?>
And theres the Comments/add.ctp file
<?php
echo $this->Form->create('Comment');
echo $this->Form->input('name', array(
'label' => 'Your Name'
));
echo $this->Form->input('commenttext',array(
'label' => 'Your Comment'
));
echo $this->Form->end('Submit');
?>
Solution HttpSocket
CakePHP includes an HttpSocket class which can be used easily for making requests. It is a great way to communicate with external webservices, or remote apis.
// in your controller
App::uses('HttpSocket', 'Network/Http'); // This should be at the top of your Controller
class CommentsController extends AppController{
public $components = 'Session'
public function add(){
if($this->request->is('POST')){
$this->Comment->create();
$HttpSocket = new HttpSocket();
$response = $HttpSocket->post('http://example.com/add', $this->request->data));
// Get the status code for the response.
$code = $results->code;
if($code == 200) {
$this->Session->setFlash('Your comment is saved!');
} else {
$this->Session->setFlash('Opps! Somthing is wrong!');
}
}
}
}
Also see here CakePHP HttpSocket
Related
The Code
AppController.php
<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
'Auth' => array(
'authorize' => array('Controller')
),
'Session'
);
}
PostsController.php
<?php
App::uses('AppController', 'Controller');
class PostsController extends AppController {
public function isAuthorized() {
return $this->Auth->user('role') == 'admin';
}
public function add() {
$this->set('some_var', true);
}
}
PostsControllerTest.php
<?php
App::uses('PostsController', 'Controller');
class PostsControllerTest extends ControllerTestCase {
public function setUp() {
parent::setUp();
CakeSession::write('Auth.User', array(
'id' => 2,
'username' => 'joe_bloggs',
'role' => 'user',
'created' => '2013-05-17 10:00:00',
'modified' => '2013-05-17 10:00:00'
));
}
public function testAddWhileLoggedInAsNonAdminFails() {
$this->testAction('/posts/add/', array('method' => 'get'));
$this->assertTrue($this->vars['some_var']);
}
public function tearDown() {
parent::tearDown();
CakeSession::destroy();
}
}
The Problem
Right now, the "testAddWhileLoggedInAsNonAdminFails" test passes. It should fail. The issue is that redirects do not exit/halt the simulated request.
Partial Solution
I can fix the problem by modifying "AppController.php" and "PostsControllerTest.php" like so:
Modified AppController.php
<?php
App::uses('Controller', 'Controller');
class AppController extends Controller {
public $components = array(
'Auth' => array(
'authorize' => array('Controller'),
// ***** THE FOLLOWING LINE IS NEW *****
'unauthorizedRedirect' => false
),
'Session'
);
}
Modified PostsControllerTest.php
<?php
App::uses('PostsController', 'Controller');
class PostsControllerTest extends ControllerTestCase {
public function setUp() {
parent::setUp();
CakeSession::write('Auth.User', array(
'id' => 2,
'username' => 'joe_bloggs',
'role' => 'user',
'created' => '2013-05-17 10:00:00',
'modified' => '2013-05-17 10:00:00'
));
}
// ***** THE FOLLOWING 3 LINES ARE NEW *****
/**
* #expectedException ForbiddenException
*/
public function testAddWhileLoggedInAsNonAdminFails() {
$this->testAction('/posts/add/', array('method' => 'get'));
}
public function tearDown() {
parent::tearDown();
CakeSession::destroy();
}
}
The problem with this solution is it modifies the behavior of the real website too. I'm looking for a way to set the Auth component's unauthorizedRedirect property to false only when tests are being run. How can I do this?
Changing the behavior of your code to make tests work right is not really a good idea.
The correct answer to this question is that it's not a very good question, and what you really should do is test each function separately.
For the isAuthorized function, you should do:
<?php
class PostsControllerTest extends ControllerTestCase {
public function testIsAuthorized() {
$Posts = $this->generate('Posts');
$user = array('role' => 'admin');
$this->assertTrue($Posts->isAuthorized($user));
$anotherUser = array('role' => 'saboteur');
$this->assertFalse($Posts->isAuthorized($user));
}
public function testAdd() {
$this->testAction('/posts/add/', array('method' => 'get'));
$this->assertTrue($this->vars['some_var']);
}
}
The core concept behind unit testing is breaking down your app into the smallest pieces possible, and testing each in isolation. Once you have your unit tests sorted out, you can work on integration tests that cover more than one function, but many projects never reach that stage, and that's okay. The redirect issue can be interesting to work with, but you can mock out controller::redirect as described in this blog post. It's a bit old but still useful.
Did you check the book? http://book.cakephp.org/2.0/en/development/testing.html#testing-controllers
When testing actions that contain redirect() and other code following
the redirect it is generally a good idea to return when redirecting.
The reason for this, is that redirect() is mocked in testing, and does
not exit like normal. And instead of your code exiting, it will
continue to run code following the redirect.
It exactly describes your problem.
I haven't tested this but try it, the manual says the controller is already mocked when using ControllerTestCase so you should be able to expect it:
$this->controller->expects($this->at(0))
->method('redirect')
->with('/your-expected-input');
Taking a look at the ControllerTestCase class might reveal how the controller is exactly mocked and set up. Alternatively you could just fall back to the regular CakeTestCase and set the controller mocks up by yourself.
Another alternative would be to extend your controller you want to test and override the redirect() method, not calling the parent but setting the first arg to a property like Controller::$redirectUrl. After your action call you can then assertEqual the properties value. But this still requires you to return after the redirect call in your controller. Also this won't work either when using ControllerTestCase because it would mock your overriden method.
echo $this->Form->create('Driver', array('type' => 'get'));
echo $this->Form->input('name');
echo $this->Form->end('Search');
as result $this->request:
query => array(
'name' => 'some name'
)
Problem is input form is empty after search although $this->request->query['name'] = 'some name'
Everything works as expected when change form back to post
Edit. Included the model and the controller. For testing I use clean install.
Model (Driver.php):
App::uses('AppModel', 'Model');
class Driver extends AppModel {
public $displayField = 'name';
}
Controller (DriversController.php):
App::uses('AppController', 'Controller');
class DriversController extends AppController {
public function index() {
$drivers = $this->Driver->find('all');
$this->set(compact('drivers'));
}
}
In your controller code you do not show us where you are trying to access the submitted form values so I will try and give some general information to get you moving.
To access your form data, you need to cool use request. To see exactly what is going on, enter in your controller one of the below...
print_r($this->request->data);
or
print_r($this->request);
Either of those will show you any data registered with CakePHP.
If you want to save this save using your Models. use...
$this->Driver->save($this->request->data)
You might want to check it is a post first though.. lets complete the code...
public function submit() {
if ($this->request->is('post')) {
$this->Driver->create();
if ($this->Driver->save($this->request->data)) {
$this->Session->setFlash('Saved.');
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash('FAILED');
}
}
}
The information above can be read in further detail here.
You can set form values by assigning to $this->data.
$this->data = $this->request->query;
i am new to cake and using version 2.
i have models
hgcylinder.php
class HgCylinder extends AppModel {
//put your code here
var $name= "HgCylinder";
var $belongsTo = array('HgKeyGase');
}
hgkeygase.php
class HgKeyGase extends AppModel {
//put your code here
var $name= "HgKeyGase";
public $belongsTo = array(
'HgKeyColor' => array(
'className' => 'HgKeyColor',
'foreignKey' => 'hg_key_color_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
}
Controller HgCylindersController.php
<?php
class HgCylindersController extends AppController
{
var $name = "HgCylinders";
// var $scaffold;
function index()
{
$this->set('hey',$this->HgCylinder->find('all'));
}
public function edit($id = null) {
$this->HgCylinder->id = $id;
if ($this->request->is('post')) {
var_dump($this->request->data);
exit;
if ($this->HgCylinder->save($this->request->data)) {
$this->Session->setFlash(__('Cylinder has been updated successfull'));
$this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The cylinder could not be saved. Please, try again.'));
}
} else {
$this->request->data = $this->HgCylinder->read(null, $id);
}
$hg_key_gase_id = $this->HgCylinder->HgKeyGase->find('list');
$this->set(compact('hg_key_gase_id'));
}
}
?>
View : edit.ctp
<?php
echo $this->form->create('HgCylinder',array('action'=>'edit'));
echo $this->form->input('hg_key_gase_id',);
echo $this->form->input("capacityM3");
echo $this->form->input("weightEmpty");
echo $this->form->input("weightFilled");
echo $this->form->input("isFilled");
echo $this->form->end('Add');
?>
my problem is hg_key_gase_id is become select list with no options. if i changed the name to "hgKeyGas" in view and controller it shows the options from the hg_key_gases table. but on saving does not saving the value of hg_key_gase_id field in hg_cylinders table instead it stores null in this field.
second i want to know that it is necessary to have variable name passing to view from controller exactly same for as field in table.
try to stick to conventions.
so its
$hgKeyGases = $this->HgCylinder->HgKeyGase->find('list');
$this->set(compact('hgKeyGases'));
the pluralized form will be able to populate your select box (as documented in the cook book)
also use $this->Form->input() (note the capital F). $name is not necessary.
dont use read(), use find(first) instead. dont set the action (the form will post to itself by default).
and most importantly. ALWAYS respect the casing of files in your filesystem. especially if you plan on deploying on NIX systems (which are case sensitive).
so it would be HgCylinder.php and HgKeyGase.php as Model class files.
last tip: use baking (cake bake via shell console) to bake your crud files. this way you learn how its done the right way. it would have also answered your question itself by the way.
the documentation can be found here: http://book.cakephp.org/2.0/en/index.html
maybe you found an old outdated version, the 2.x one is the one you should have used.
Good Day to all. I am currently developing a chat application using cakePHP. It will be a chat application that focuses on answering questions. That means the user will receive an automated response based on his/her question. I am working on the chat interface right now that doesn't require the user to login. The chat application will only be interacting to a database table once the user has sent the question. Now my problem is on how to send the question to a method in the controller where it will be parsed. I tried to do the following in the view file:
<!--View/People/index.ctp-->
<h1>This is the chat interface</h1>
<?php $this->Html->charset(); ?>
<p>
<!--This is the text area where the response will be shown-->
<?php
echo $this->Form->create(null);
echo $this->Form->textarea('responseArea', array('readonly' => true, 'placeholder' =>
'***********************************************************************************
WELCOME! I am SANTI. I will be the one to answer your questions regarding the enrollment process
and other information related to it. ***********************************************************************************', 'class' => 'appRespArea'));
echo $this->Form->end();
?>
</p>
<p>
<!--This is the text area where the user will type his/her question-->
<?php
echo $this->Form->create(null, array('type' => 'get', 'controller' => 'people', 'action' => 'send', ));
echo $this->Form->textarea('userArea', array('placeholder' => 'Please type your question here', 'class' => 'userTextArea'));
echo $this->Form->end('Send');
?>
</p>
This is the controller:
<!--Controller/PeopleController.php-->
<?php
class PeopleController extends AppController{
public $helpers = array('Form');
public function index(){
}
public function send(){
//parsing logic goes here
}
}
?>
As you can see, I am telling the form in index.ctp to point the action to the send() method in PeopleController so it can parse the question before interacting with the database. The problem that arises when I click the button is that I am always redirected to /users/login which is not what I want to happen. I just want the application to point itself to /people/send. What seems to be the problem in that case? I have tried to look for answers both in the Internet and in the documentation and then tested them but nothing has resolved the problem so far. Can anyone please help me on this? I've been trying to resolve this for so many days.
I keep on getting this error:
Missing Method in UsersController
Error: The action *login* is not defined in controller *UsersController*
Error: Create *UsersController::login()* in file: app\Controller\UsersController.php.
<?php
class UsersController extends AppController {
public function login() {
}
}
If you are using Auth Component, then you might need to change your PeopleController code:
<!--Controller/PeopleController.php-->
<?php
class PeopleController extends AppController{
public $helpers = array('Form');
public beforeFilter()
{
parent:: beforeFilter();
$this->Auth->allow('index', 'send');
}
public function index(){
}
public function send(){
//parsing logic goes here
}
}
?>
This is because of you used people/send as a form action. And the user is not logged in, it means there is no any Auth session has been set. Thats why it always redirect the user to login page, and if there is not login page, then it will show you the error.
So I made the send() method also public, so that anyone can access it.
Hope this concept will help you.
I am new in cakephp. I wrote a validation ctpfile in cakephp 2.6.7 for viewing login and logout word but the validation doesn't work.
My code is:-
<?php
if (!$authUser) {
echo $this->element('logout-header');
} else {
echo $this->element('login-header');
}
?>
How can I write validation in ctp file for viewing login and logout word in my page header?
Why you wrote a validation ctp? put your validation rules in model
http://book.cakephp.org/2.0/en/models/data-validation.html
In your AppController's beforeRender() callback set the authUser view variable by retrieving the logged in user:-
public function beforeRender() {
parent::beforeRender();
$this->set('authUser', $this->Auth->user());
}
Then the view code in your question should work as expected.
I have a solution, which I regularly use when I worked in cakephp.
in AppController.php
class AppController extends Controller{
public function beforeFilter() {
parent::beforeFilter();
$userInfo = array();
if($this->Auth->user('_id')){
$userInfo['User'] = $this->Auth->user();
Configure::write($userInfo);
}
}
}
And after this in view .ctp file
<?php
$authUser = Configure::read('User');
if (!$authUser) {
echo $this->element('logout-header');
} else {
echo $this->element('login-header');
}
?>