CakePHP Test Controller add edit - cakephp

I am testing controllers add method (CakePHP2.0).
But the issue is that what ever data I send as post gets added to my default databases and not my test database.
Heres the code.
public function testAdd() {
$data = array(
'Post' => array(
'title' => 'Fourth Post Title',
'body' => 'Fourth Post Body',
'created' => '2012-01-22 21:31:52'
)
);
$result = $this->testAction('/posts/add', array('data' => $data, 'method', 'post'));
debug($result);
}
What I was actually expecting that the posted data togo into test DB that i configured in database.php and not in default DB.

There are a few requirements for tests to occur in CakePHP 2.0 that you may want to double check:
Ensure that your Database Config setting in config/database.php is setup as
public $test = array(
//Sample Test Settings Here
);
If you running tests from the web interface, debug must be set to at least 1 or else the tests will not run.
You can also validate that PHPUnit and your test database connection is working properly by running CakePHP core tests by navigating to: http://localhost/your_app/test.php and "AllConfigure" test.
All information from the CakePHP Book: http://book.cakephp.org/2.0/en/development/testing.html

Related

Can you test with a test database copy instead of Fixtures with CakePHP3?

I'm using CakePHP3 and have copied the production database (my_app) into a test database (test_my_app). The details of the test connection are listed in app.php and debug is set to true.
Do I need to use fixtures or will my controller tests pickup the test database? At the moment when I post to controller (REST API) it seems to apply to the production database, instead of the test db. The app is running on http://localhost/my_app/ which is the url used in the controller testing.
I'm running tests on the console with :
$ vendor/bin/phpunit tests/TestCase/Controller/ArticlesControllerTest
This is still in dev stages so the databases are small.
This is the code:
public function testAdd()
{
$users = TableRegistry::get('Users');
$query = $users->find('all');
$before = $query->count();
$params = [
'username' => 'foo',
'email' => 'foobar#example.com ',
'password' => 'password',
'fullname' => 'Elbart Bart',
'status' => 'active'
];
$this->configRequest([
'headers' => [
'Authorization' => 'Bearer ' . $this->token
]
]);
$this->post('users/add', $params);
$query2 = $users->find('all');
$after= $query2->count();
debug($before);
$this->assertEquals($after,$before+1);
}
Yes you can test using a test DB, you don't need fixtures at all. I copied the my_app database into test_my_app, and the CakePHP test conventions were able to pick it up.
Also make sure not to use the absolute/full URL as that then uses the production database -
// so DON'T do this
$this->post('http://localhost/my_app/users/add', $data).
//Instead do:
$this->post('/users/add', $data);

how to give CAKEPHP validation?

If condition is true it should show an error message "already exits" or else a message "successful" should be displayed.
Is it possible to add a validation like this to the model part:
$name = $_POST["name"];
$validation_sql = "SELECT COUNT(*) > 0 FROM college WHERE status='2' AND name='$name'";
You can use hasAny() as the solution:
$conditions = array(
'status'=>'2',
'name'=>$name
);
if ($this->XXXXXXX->hasAny($conditions)){
//do something
}
hasAny will return true if found else false.
NOTE: hasAny is not available in version 3.x
You can add server validation in model like:
public $validate = array(
'name' => array(
'rule' => array('isUnique', array('name'), false),
'message' => 'This name has already been used.'
)
);
It is not recommended to use $_POST in CakePHP at all, rather use the Request Object in the controller to access the data given by a POST request:
$this->request->data['College']['name'];
This information can then be passed to the model where it is validated.
If the post request has been created by the CakePHP form helper you don't need to access it - you can directly pass the data to the save method of the model instance (see CakePHP Handbook - Saving your data).
if ($this->College->save($this->request->data)) {
// handle the success (Normally success flash)
}
debug($this->College->validationErrors); //Normally error flash - if FormHelper is used the error messages are automatically shown beside the input elements
The validations can be added with the Bake Console or manually by adding validation rules to the College Model code:
public $validate = array(
'name' => array(
'rule' => 'isUnique',
'message' => 'This username has already been taken.'
)
);

cakephp How to change the X-Mailer

Using cakePHP version 2.3.8,
I am trying to change the X-Mailer: CakePHP Email into X-Mailer: PHP mail.
I have tried this in the controller and in the /app/Config/email.php in my 'default' settings.
'X-Mailer' => 'PHP mail',
But not able to get it changed, really frustrating.
You need to use addHeaders() to change it prior to sending the email.
As done here, for example:
https://github.com/dereuromark/tools/blob/master/Lib/EmailLib.php#L638
In this case - extending the core class - one can use Configure to automatically populate the X-Mailer via configs. But you can also do it inline for each email sending functionality.
Basically, on your CakeEmail object:
$CakeEmail = new CakeEmail();
$CakeEmail->addHeaders(array('X-Mailer' => 'My custom X-Mailer'));
If set manually Cake will not add his default value 'CakePHP Email'.
CakePHP 2,
Instead of setting it every time from a controller as suggested by #mark,
you can set in the EmailConfig class, located in Config/email.php:
public $default = array(
'transport' => '...',
'from' => '...',
'emailFormat' => 'both',
'charset' => 'utf-8',
'headerCharset' => 'utf-8',
'headers'=>array('X-Mailer'=>'Your App Name'),
);
Will send an email with these headers:
To: .....
X-Mailer: Your App Name
Date: ....

How do I load associated models and save related data in CakePHP?

I am setting up a user/group system that allows users to send requests to join a group.
I can't seem to load the associated model and add a row. It's really really really difficult to resist the urge to just use $this->query() and be done with it... but I'm trying to learn the Cake conventions and do things the right way.
In my group model's function for handling group join requests:
$this->loadModel('GroupRequest');
$this->data = array('GroupRequest' =>
array('user_id' => $uid, 'group_id' => $gid));
if($this->GroupRequest->save($this->data)){ echo 'save success'; }
else { echo 'save fail'; }
Here are the errors I get when I run this:
Warning (512): SQL Error: 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'loadModel' at line 1 [CORE/cake/libs/model/datasources/dbo_source.php, line 684]
Query: loadModel
Notice (8): Undefined property: Group::$GroupRequest [APP/models/group.php, line 124]
Fatal error: Call to a member function save() on a non-object in /home/wxworksmat/sspot3/app/models/group.php on line 124
I also tried using App::import:
App::import('Model','GroupRequest');
I don't get any SQL errors importing the Model this way, but it still doesn't work. I get the following error on the save() or create() call:
Fatal error: Call to a member function save() on a non-object in /home/wxworksmat/sspot3/app/models/group.php on line 124
You are confusing controller and model methods
$this->loadModel()
is a controller method and can only be used there.
You should always use
$this->ModelName = ClassRegistry::init('ModelName');
everywhere else
I might be wrong, and please excuse me if I'm wrong, but it looks like you don't understand the concept of the framework very well. It is difficult to answer your question without giving you a complete tutorial.
This said, everything relies on model associations. If it's done correctly, things are getting easy. You should read:
Associations: Linking Models Together
Once you have your models correctly linked, you will be able to save the primary model, as well as the related model, very easily.
Saving Related Model Data (hasOne, hasMany, belongsTo)
As I understand, you are trying to do this from inside a model?
class GroupRequest extends AppModel {
public function associate($user, $group) {
$data["GroupRequest"] = array("user_id" => $user, "group_id" => $group);
$this->save($data);
}
}
Then in your Controller (assuming group_requests_controller)
$this->GroupRequest->associate($user, $group);
If you're calling this from another controller you would loadModel first
$this->loadModel("GroupRequests");
$this->GroupRequest->associate($user, $group);
However, if you're doing all of this from within GroupRequests controller you should be able to save directly, without making a separate method for it
public function add() {
$this->GroupRequest->create();
$this->GroupRequest->save($this->data); #for < 2.0
}
Your view should be something like
<?php
echo $this->Form->create("GroupRequest");
echo $this->Form->input("user_id");
echo $this->Form->input("group_id");
echo $this->Form->end("Submit");
?>
The problem I had was that I didn't have the correct model association declarations at the top of my model.
Now I have:
group.php
var $hasMany = 'GroupRequest';
group_request.php
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
),
'Group' => array(
'className' => 'Group',
'foreignKey' => 'group_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
public function new_request($user, $group) {
$data["GroupRequest"] = array("user_id" => $user, "group_id" => $group, 'status' => 'pending');
if($this->save($data)){ return true;} else {return false;}
}
Now because everything is set up CORRECTLY... I can do this in my group.php model:
$this->GroupRequest->new_request($uid,$gid)
As an added bonus, because the assocations are populating properly, when I do $this->find in my group or user model, now all the related GroupRequest entries show up. Bonus data FTW.

How to check session when downloading uploaded file in cakephp?

I have created a feature to upload and download file in my site. But I want to validate the download feature. I want to allow a user to download file if user is already logged in to my site and given permission to download.
Help me. How to check whether session is present there or not?
I am uploading files in /app/webroot/documents/users/ path.
Download link generated is like this : http://localhost/my_project/documents/users/TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx.jpg
Thank you all.
The easiest way to deal with this is to use the AuthComponent for your authentication and the MediaView for handling the download prompt from a "download this file" link on the page.
An Example.
class SomeController extends AppController {
...
public $components = array(
'Auth' => array(
... auth settings ...
),
...
);
public function download( ){
$this->view = 'Media';
$this->set( array(
'id' => 'TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx.jpg',
'name' => 'TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx',
'download' => true,
'extension' => 'jpg',
'path' => join( DS, array(
APP, 'webroot', 'documents', 'users', ''
))
));
}
This assumes you have the download action as a restricted action with regards to the AuthComponent. If you have the download action allowed you can wrap the MediaView code in an Auth->user( ) check like so..
public function download( ){
if( $this->Auth->user( )){
$this->view = 'Media';
$this->set( array(
'id' => 'TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx.jpg',
'name' => 'TGlnaHRob3VzZS5qcGcxMjc3ODIzMTAx',
'download' => true,
'extension' => 'jpg',
'path' => join( DS, array(
APP, 'webroot', 'documents', 'users', ''
))
));
} else {
... do something else here ...
}
}
This just checks that Auth has a valid User object saved to the session. This should only occur when there is a User logged in.
A couple of notes:
I use a blank array entry at the end of the join( DS, array( 'path', 'parts', '' ) call to get the trailing slash required for the path. Do that however you want - I am partial to join myself when building repetitive strings or paths.
http://book.cakephp.org/view/489/Media-Views
http://book.cakephp.org/view/563/Setting-Auth-Component-Variables
I would probably set something up so you're not giving them a direct download link. I usually set up an AttachmentsController, with a download() method. Then you can run all the permissions checks you want (and keep stats on the files, etc.)
In that case you can have your controller check the session variable before enabling the download.
If you're using the Session component, you can check the user's status in your users action using something like this:
if($this->Session->read('Auth.User.id'))
{
//download file
}
How you serve your files is up to you though, but that session check should work inside whatever you use to serve the file, such as Travis Leleu's AttachmentsController.

Resources