These are the results from when I do debug($this->request->data)
I ommited the fields that didn't matter
I get this
[
'file' => 'Atest.doc'
]
I want this
[
'file' => [
'tmp_name' => '/Applications/MAMP/tmp/php/phpgBEFye',
'error' => (int) 0,
'name' => 'Atest.doc',
'type' => 'application/msword',
'size' => (int) 45056
]
Here is .ctp
echo $this->Form->create($contact, ['id'=>'contact-form']);
echo $this->Form->file('file', ['label'=> 'Cover Letter']);
echo $this->Form->button('Send');
echo $this->Form->end();
My Contact Controller
<?php
namespace App\Controller;
use App\Controller\AppController;
use App\Form\ContactForm;
use Cake\ORM\TableRegistry;
use Cake\Mailer\Email;
use Cake\Network\Exception\SocketException;
use Burzum\FileStorage\Storage\StorageManager;
public function index($option = 'index'){
$contact = new ContactForm();
if ($this->request->is('post')) {
if ($contact->execute($this->request->getData())) {
//debug($this->request->getData() );
}
}
///..I omitted the rest
}
echo $this->Form->create($document, ['enctype' => 'multipart/form-data']);
Related
Im using cakephp 3.2 to build an application. Im using the bookmarks tutorial as a basis for my project. in one of my bookmarks .ctp view files I would like to have a number of select boxes with data specific to the user loggged in. i have two tables namely users and bookmarks. My bookmarks table contains foreign key from users table user_id.
Here's my bookmark table with the fields i would like the dropdowns. id, user_id, title, systemregistration, systemroles, country, province, metropolitan.
Code for my appcontroller
namespace App\Controller;
use Cake\Controller\Controller;
use Cake\Event\Event;
/**
* Application Controller
*
* Add your application-wide methods in the class below, your controllers
* will inherit them.
*
* #link http://book.cakephp.org/3.0/en/controllers.html#the-app-controller
*/
class AppController extends Controller
{
/**
* Initialization hook method.
*
* Use this method to add common initialization code like loading components.
*
* e.g. `$this->loadComponent('Security');`
*
* #return void
*/
/*public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
}*/
public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'authenticate' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password'
]
]
],
'loginAction' => [
'controller' => 'Users',
'action' => 'login'
],
//'storage' => 'Session'
'Session'
]);
// Allow the display action so our pages controller
// continues to work.
$this->Auth->allow(['display']);
}
/*public function initialize()
{
$this->loadComponent('Flash');
$this->loadComponent('Auth', [
'loginRedirect' => [
'controller' => 'Bookmarks',
'action' => 'index'
],
'logoutRedirect' => [
'controller' => 'Pages',
'action' => 'display',
'home'
]
]);
}
public function beforeFilter(Event $event)
{
$this->Auth->allow(['index', 'view', 'display']);
}*/
/**
* Before render callback.
*
* #param \Cake\Event\Event $event The beforeRender event.
* #return void
*/
public function beforeRender(Event $event)
{
if (!array_key_exists('_serialize', $this->viewVars) &&
in_array($this->response->type(), ['application/json', 'application/xml'])
) {
$this->set('_serialize', true);
}
}
}
//BookmarksController looks like this
namespace App\Controller;
use App\Controller\AppController;
/**
* Bookmarks Controller
*
* #property \App\Model\Table\BookmarksTable $Bookmarks
*/
class BookmarksController extends AppController
{
public function internalprotocol()
{
$bookmark = $this->Bookmarks->newEntity();
$users = $this->Bookmarks->Users->find('list', ['limit' => 200]);
$tags = $this->Bookmarks->Tags->find('list', ['limit' => 200]);
$this->set(compact('bookmark', 'users', 'tags'));
$this->set('_serialize', ['bookmark']);
$bookmarks = $this->paginate($this->Bookmarks);
$this->set(compact('bookmarks'));
$this->set('_serialize', ['bookmarks']);
}
}
//my internalprotocol.ctp looks like this
<div>
<?php echo $this->Form->input('user_id', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('title', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('systemregistration', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('systemroles', ['options' => $bookmarks]); ?>
<?php echo $this->Form->input('country', ['options' => $bookmarks]); ?>
</div>
I would like to populate each of the fields with data specific to the user logged in. Could you please help!
You don't need to do anything. If a login is successful you can access the logged in user details through the Auth component using $this->Auth->user();
If you need to add any more information to the session you can use the Session component like $this->Session->write('User.AscociatedData', $AscociatedData);
Easiest way to access this data in the view is to set authenticated user as a view variable in the controller:
$this->set('user',$this->Auth->user());
then you can accesses the users info in the view with $user e.g$user->fieldName
Not entirely sure what your asking but I hope one of my answers is relevant.
we only need to show bookmarks for the currently logged in user.
We can do that by updating the call to paginate().Make your index() action from Controller/BookmarksController.php look like:
public function index()
{
$this->paginate = [
'conditions' => [
'Bookmarks.user_id' => $this->Auth->user('id'),
]
];
$this->set('bookmarks', $this->paginate($this->Bookmarks));
$this->set('_serialize', ['bookmarks']);
}
We should also update the tags() action and the related finder method as we done for bookmarks above
Please read the tutorial
http://book.cakephp.org/3.0/en/tutorials-and-examples/bookmarks/part-two.html#fixing-list-view-and-forms
So i have this method inside of my:
JobsController.ctp:
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\ORM\TableRegistry;
/**
* Jobs Controller
*
* #property \App\Model\Table\JobsTable $Jobs
*/
class JobsController extends AppController
{
public $name = 'Jobs';
public function add()
{
//Some Vars assigning skipped, var job is empty
$this->set('job','Job');
$this->Job->create();
}
}
And I have this view with the form itself:
add.ctp:
<?= $this->Form->create($job); ?>
<fieldset>
<legend><?= __('Add Job Listing'); ?></legend>
<?php
echo $this->Form->input('title');
echo $this->Form->input('company_name');
echo $this->Form->input('category_id',array(
'type' => 'select',
'options' => $categories,
'empty' => 'Select Category'
));
echo $this->Form->input('type_id',array(
'type' => 'select',
'options' => $types,
'empty' => 'Select Type'
));
echo $this->Form->input('description', array('type' => 'textarea'));
echo $this->Form->input('city');
echo $this->Form->input('contact_email');
?>
</fieldset>
<?php
echo $this->Form->button('Add');
$this->Form->end();
?>
Also this table class:
JobsTable.php
<?php
namespace App\Model\Table;
use Cake\ORM\Table;
class JobsTable extends Table
{
public function initialize(array $config)
{
$this->belongsTo('Types', [
'foreignKey' => 'type_id',
'joinType' => 'INNER',
]);
$this->belongsTo('Categories', [
'foreignKey' => 'category_id',
'joinType' => 'INNER',
]);
}
}
And when I submit it, it gives me next error:
Error: Call to a member function create() on boolean
No idea how to fix.
I also have an entity
Job.php:
<?php
namespace App\Model\Entity;
use Cake\ORM\Entity;
/**
* Job Entity.
*/
class Job extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* #var array
*/
protected $_accessible = array(
'category_id' => true,
'user_id' => true,
'type_id' => true,
'company_name' => true,
'title' => true,
'description' => true,
'city' => true,
'contact_email' => true,
'category' => true,
'user' => true,
'type' => true,
);
}
So how do I fix this error, that appears on form submit?
Error: Call to a member function create() on boolean
I guess I need to do something with $this->set('job'); ? but I'm not sure what exactly
By convention the default, auto-loadable table for a controller is based on the controller name without the trailing Controller, so for JobsController a table class named Jobs(Table) can be autoloaded.
In case the table class cannot be loaded (for example because it doesn't exist, or because the name doesn't match the one derived from the controller name), the magic getter that handles this will return false, a boolean, and this is where you are trying to call a method on, hence the error.
create() btw doesn't exist anymore, you should have a look at the ORM migration guide, and the docs in general to get a grasp on how things now work.
So either use $this->Jobs and make sure that you have a table class named JobsTable, or override the default model to use (Controller::_setModelClass()), or load the desired table manually (TableRegistry::get() or Controller::loadModel()).
See also
Cookbook > Database Access & ORM
Cookbook > Controllers > Loading Additional Models
In version 2.2.1 I could validate a form using rules and custom messages like below. But somehow the password rule isn't working as of version 2.3. Any help what I might be doing wrong here?
Model:
class User extends AppModel {
public $validate = array(
'password' => array(
'rule' => array ('between', 5, 10 ),
'message' => 'Password must between 5 and 10 characters long'
)
);
public function beforeSave($options = array()) {
$this->data['User']['password'] = Security::hash($this->data['User']['password'], 'sha1', true);
return true;
}
}
View:
<?php
echo $this->Form->create();
echo $this->Form->input('firstname', array('label' => 'First name'));
echo $this->Form->input('lastname', array('label' => 'Last name'));
echo $this->Form->input('adminrole', array('type' => 'checkbox', 'label' => 'Is admin?<br /><br />'));
echo $this->Form->input('email', array('label' => 'E-mail address'));
echo $this->Form->input('password', array('label' => 'Password'));
echo $this->Form->input('picturethumb', array('type' => 'file', 'label' => 'Profile picture'));
echo $this->Form->end('Save');
?>
Please bare in mind that this exact same code validates correctly in 2.2.1
Controller:
class UsersController extends AppController {
public function index() {
$users = $this->User->find('all');
$this->set('users', $users);
}
public function add() {
if ($this->request->is('post')) {
$this->User->save($this->request->data);
$this->redirect('/users');
}
}
}
Try this-
public function add() {
if ($this->request->is('post')) {
$this->User->create();
if($this->User->save($this->request->data)){
$this->redirect('/users');
}else{
$this->Session->setFlash('Opps... Something is wrong');
}
}
}
I don't work with cake sometime, but I remember had this problem before. The problem is, the cakephp will create a hash of password, so when Model get password is already big. What I did in time was make another validate, like password_tmp and use it like field and create the hash by myself in controller for the real field password.
I have a question about cakePHP. I create two drop down lists in my view. When the user changes the value in one list, I want the second to change. Currently, I have this working like this: An on click event fires when the user selects from list box one. This fires a jQuery ajax function that calls a function from my controller. This is all working fine, but how do I re-render my control, asynchronously (or, view)? I i know I could just serialize the array to json and then recreate the control in javascript, but there seems like there should be a more "CakePHP" way. Isn't that what render is for? Any help would be great. Here's the code I have so far:
jQuery:
function changeRole(getId){
$.ajax({
type: 'POST',
url: 'ResponsibilitiesRoles/getCurrentResp',
data: { roleId: getId },
cache: false,
dataType: 'HTML',
beforeSend: function(){
},
success: function (html){
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
}
});
View:
<?php
echo 'Roles:';
echo'<select name="myOptions" multiple="multiple">';
foreach ($rolesResponsibility as $role) {
echo' <option onclick="changeRole(this.value);" value="'; echo $role["ResponsibilitiesRole"]["role_id"]; echo '">'; echo $role["r"]["role_name"]; echo '</option>';
}
echo '</select>';
echo 'Responsbility:';
echo'<select name="myOptionsResp" multiple="multiple">';
foreach ($respResponsibility as $responsibility) {
echo' <option value="'; echo $responsibility["responsibility"]["id"]; echo '">'; echo $responsibility["responsibility"]["responsibility_name"]; echo '</option>';
}
echo '</select>';
?>
Controller function:
public function getCurrentResp(){
$getId = $this->request->data['roleId'];
$responsibilityResp = $this->ResponsibilitiesRole->find('all',
array("fields" => array('role.role_name','ResponsibilitiesRole.role_id','responsibility.*'),'joins' => array(
array(
'table' => 'responsibilities',
'alias' => 'responsibility',
'type' => 'left',
'foreignKey' => false,
'conditions'=> array('ResponsibilitiesRole.responsibility_id = responsibility.id')
),
array(
'table' => 'roles',
'alias' => 'role',
'type' => 'left',
'foreignKey' => false,
'conditions'=> array('ResponsibilitiesRole.role_id = role.id')
)
),
'conditions' => array ('ResponsibilitiesRole.role_id' => $getId),
));
$this->set('respResponsibility', $responsibilityResp);
//do something here to cause the control to be rendered, without have to refresh the whole page
}
The js event is change fired on the select tag and NOT click
You can use the Form Helper to build your form.
Pay attention Naming things following the cakephp way.
Because your code is a bit confused i will make other simple example:
Country hasMany City
User belongsTo Country
User belongsTo City
ModelName/TableName (fields)
Country/countries (id, name, ....)
City/cities (id, country_id, name, ....)
User/users (id, country_id, city_id, name, ....)
View/Users/add.ctp
<?php
echo $this->Form->create('User');
echo $this->Form->input('country_id');
echo $this->Form->input('city_id');
echo $this->Form->input('name');
echo $this->Form->end('Submit');
$this->Js->get('#UserCountryId')->event('change',
$this->Js->request(
array('controller' => 'countries', 'action' => 'get_cities'),
array(
'update' => '#UserCityId',
'async' => true,
'type' => 'json',
'dataExpression' => true,
'evalScripts' => true,
'data' => $this->Js->serializeForm(array('isForm' => false, 'inline' => true)),
)
)
);
echo $this->Js->writeBuffer();
?>
UsersController.php / add:
public function add(){
...
...
// populate selects with options
$this->set('countries', $this->User->Country->find('list'));
$this->set('cities', $this->User->City->find('list'));
}
CountriesController.php / get_cities:
public function get_cities(){
Configure::write('debug', 0);
$cities = array();
if(isset($this->request->query['data']['User']['country_id'])){
$cities = $this->Country->City->find('list', array(
'conditions' => array('City.country_id' => $this->request->query['data']['User']['country_id'])
));
}
$this->set('cities', $cities);
}
View/Cities/get_cities.ctp :
<?php
if(!empty($cities)){
foreach ($cities as $id => $name) {
?>
<option value="<?php echo $id; ?>"><?php echo $name; ?></option>
<?php
}
}
?>
Consider this code:
Controller Code
<?php
App::uses('AppController', 'Controller');
class UsersController extends AppController {
public $components = array(
'Security',
'Session'
);
public function example() {
if ($this->request->is('post')) {
$this->set('some_var', true);
}
}
}
View Code
<?php
echo $this->Form->create();
echo $this->Form->input('name');
echo $this->Form->end('Submit');
Since I have the Security component in place, tampering with the form in any way (such as adding a field to it) will cause the request to be black-holed. I'd like to test this:
Test Code
<?php
class UsersControllerTest extends ControllerTestCase {
public function testExamplePostValidData() {
$this->Controller = $this->generate('Users', array(
'components' => array(
'Security'
)
));
$data = array(
'User' => array(
'name' => 'John Doe'
)
);
$this->testAction('/users/example', array('data' => $data, 'method' => 'post'));
$this->assertTrue($this->vars['some_var']);
}
public function testExamplePostInvalidData() {
$this->Controller = $this->generate('Users', array(
'components' => array(
'Security'
)
));
$data = array(
'User' => array(
'name' => 'John Doe',
'some_field' => 'The existence of this should cause the request to be black-holed.'
)
);
$this->testAction('/users/example', array('data' => $data, 'method' => 'post'));
$this->assertTrue($this->vars['some_var']);
}
}
The second test testExamplePostInvalidData should fail because of some_field being in the $data array, but it passes! What am I doing wrong?
By adding the 'some_field' in the data of ->testAction, the security component will assume that field is part of your app (since it's coming from your code, not a POST array) so it won't be seen as a "hack attempt".
Checking for blackholes is a little more convoluted. But Cake core tests already test the blackhole functionality, so if those tests pass, you don't need to check it in your app.
If you insist though, check out the core Cake tests for guidance:
Specifically:
/**
* test that validatePost fails if any of its required fields are missing.
*
* #return void
*/
public function testValidatePostFormHacking() {
$this->Controller->Security->startup($this->Controller);
$key = $this->Controller->params['_Token']['key'];
$unlocked = '';
$this->Controller->request->data = array(
'Model' => array('username' => 'nate', 'password' => 'foo', 'valid' => '0'),
'_Token' => compact('key', 'unlocked')
);
$result = $this->Controller->Security->validatePost($this->Controller);
$this->assertFalse($result, 'validatePost passed when fields were missing. %s');
}
Lots more examples in the file:
https://github.com/cakephp/cakephp/blob/master/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php