I'm trying to create a site with CakePHP 4.0, but can't get the validation rules to work. I read the documentation, but wasn't sure where I was supposed to put the validationDefault function. I've put it in UsersTable.php, which looks like this:
<?php
namespace App\Model\Table;
use App\Model\Entity\User;
use Cake\ORM\Query;
use Cake\ORM\RulesChecker;
use Cake\ORM\Rule\IsUnique;
use Cake\ORM\Table;
use Cake\Validation\Validator;
class UsersTable extends Table {
public function initialize(array $config): void {
$this->addBehavior('Timestamp');
$this->hasMany('Requests')
->setDependent(true);
$this->hasMany('Offers')
->setDependent(true);
}
public function validationDefault(Validator $validator) {
$validator->notEmptyString('email', 'Please enter your email address')
->notEmptyString('name', 'Please enter a name');
return $validator;
}
}
?>
So I'm expecting that if a user tries to sign in without an email or name, it should throw an error.
The form I have for registration is:
echo $this->Form->create();
echo $this->Form->control('name');
echo $this->Form->control('email');
echo $this->Form->control('password', array('type' => 'password'));
echo $this->Form->control('confirm_password', array('type' => 'password'));
echo $this->Form->button('Register');
echo $this->Form->end();
and that sends the data to UsersController.php, which contains:
public function login() {
// Otherwise, we're registering
$users = TableRegistry::getTableLocator()->get('Users');
$user = $users->newEntity($this->request->getData());
if ($users->save($user)) {
$result = $this->Authentication->getResult();
if ($result->isValid()) {
$target = '/users/home';
return $this->redirect($target);
}
}else {
$this->Flash->error('Please fix errors below');
}
exit;
}
}
}
When I try to register without entering a name and email, I get the following error message:
Fatal error: Declaration of App\Model\Table\UsersTable::validationDefault(Cake\Validation\Validator $validator) must be compatible with Cake\ORM\Table::validationDefault(Cake\Validation\Validator $validator): Cake\Validation\Validator in /Applications/MAMP/htdocs/src/Model/Table/UsersTable.php on line 26
I can't see any obvious problems with my code. Where am I going wrong?
The declaration of the validationDefault function in Cake is:
public function validationDefault(Validator $validator): Validator
Your declaration is just
public function validationDefault(Validator $validator)
You need to add the return type declaration at the end in order to match. The docs don't seem to mention that, you might want to raise an issue on that.
Related
I'm trying to create a Dropdown menu from the table Holidays for the column name. But I'm too dumb to make it work.
I already tried some of the things people wrote but most of them have a second database. But I only have one.
My goal is to show all the names from the Holiday name column so, if I create a new holiday, I just get the name of the date from the Dropdown menu and don't need to write it down every time.
HolidaysController.php
public function index()
{
$holidays = $this->paginate($this->Holidays);
$this->set(compact('holidays'));
$name =$this->name->find('list');
$this->set(compact('name'));
}
Holidays add.ctp
<?php
echo $this->Form->control('date', array('label' => __('Datum', true)));
echo $this->Form->control('name', ['options' => $name, 'empty' => true]);
?>
I thought he would show me now a dropdown list from the names of the holidays but i just have a normal field and get the error:
Notice (8): Undefined variable: name [APP/Template\Holidays\add.ctp, line 19]
I'm probably missing something really basic here, I'm still learning coding so if I missed any information, you need, just let me know.
EDIT:
My add function after the edit
HolidaysController
public function add()
{
$name =$this->name->find('list');
$this->set(compact('name'));
$holiday = $this->Holidays->newEntity();
if ($this->request->is('post')) {
$holiday = $this->Holidays->patchEntity($holiday, $this->request->getData());
if ($this->Holidays->save($holiday)) {
$this->Flash->success(__('Der Feiertag wurde gespeichert.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('Der Feiertag wurde nicht gespeichert. Bitte, versuchen sie es erneut.'));
}
$this->set(compact('holiday'));
}
You must find and set list in your add() method, like :
public function add()
{
// your add code here .. then:
$name =$this->Holidays->find('list');
$this->set(compact('name'));
}
By default every controller method has own view template:
index() >> index.ctp
add() >> add.ctp
edit() >> edit.ctp
myCustomMethod() >> my_custom_method.ctp
// ...
EDIT:
If I add your code to function add() i get an Error: Call to a member
function find() on string.
I copy code from your question. But you must update:
from: $this->name->find('list'); to
$this->Holidays->find('list', [
'keyField' => 'name',
]);
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
I have code in place so that if the "Add User" page is accessed from anywhere in the "Posts" section of the website, the user will be taken to the "Users" index after adding the user. But if the "Add User" page is accessed from any other section of the website, the user will be taken back to where they were after adding the user. I want to test this, but I don't know how. This is what I have so far:
Controller Code
<?php
App::uses('AppController', 'Controller');
class UsersController extends AppController {
public function add() {
if ($this->request->is('post')) {
$this->User->create();
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved'));
return $this->redirect($this->request->data['User']['redirect']);
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
}
else {
if ($this->referer() == '/' || strpos($this->referer(), '/posts') !== false) {
$this->request->data['User']['redirect'] = Router::url(array('action' => 'index'));
}
else {
$this->request->data['User']['redirect'] = $this->referer();
}
}
}
public function index() {
$this->User->recursive = 0;
$this->set('users', $this->paginate());
}
}
Test Code
<?php
App::uses('UsersController', 'Controller');
class UsersControllerTest extends ControllerTestCase {
public function testAdd() {
$this->Controller = $this->generate('Users');
// The following line is my failed attempt at making $this->referer()
// always return "/posts".
$this->Controller->expects($this->any())->method('referer')->will($this->returnValue('/posts'));
$this->testAction('/users/add/', array('method' => 'get'));
$this->assertEquals('/users', $this->Controller->request->data['User']['redirect']);
}
}
What am I doing wrong?
You aren't mocking any methods
This line
$this->Controller = $this->generate('Users');
Only generates a test controller, you aren't specifying any methods to mock. To specify that some controller methods need to be mocked refer to the documentation:
$Posts = $this->generate('Users', array(
'methods' => array(
'referer'
),
...
));
The expectation is never triggered
Before asking this question, you probably had an internal conversation a bit like: "why is it saying that my expectation is never called? I'll just use $this->any() and ignore it.."
Don't use $this->any() unless it really doesn't matter if the mocked method is called at all. Looking at the controller code, you're expecting it to be called exactly once - so instead use $this->once():
public function testAdd() {
...
$this->Controller
->expects($this->once()) # <-
->method('referer')
->will($this->returnValue('/posts'));
...
}
The full list of available matchers is available in PHPUnit's documentation.
I have this created:
<?php
class AppExceptionHandler
{
public static function handle($error)
{
$this->controller->redirect('www.google.com');
//echo 'Oh noes! ' . $error->getMessage();
// ...
}
// ...
}
?>
The echo will output fine but how do I use a layout or view? I keep getting this erro:
Fatal error: Using $this when not in object context in ...
Try to add the following method in you AppController.php
public function appError($error) {
//Do whatever you want
debug($error);
}
I need to change page title from default "Error" when handling errors like 404. So I need to put my the title in the variable $title_for_layout for my Layout. I tried to create custom error handling function by changing configuration in app/Config/core.php and setting the page title as in controllers
Configure::write('Error.handler', function($code, $description, $file = null, $line = null, $context = null) {
$this->set('title_for_layout', 'Vyskytla sa chyba');
});
As I expected, I got a PHP error (line 59 is the second line in the code sample)
Fatal error: Using $this when not in object context in /var/www/web/app/Config/core.php on line 59
So how I can set the title for my default.ctp layout?
Thanks.
In CakePHP 2.0, you can try the following code to achieve the same you needed.
Try this:
/app/Config/core.php
Exception render need to set as an AppExceptionRender. Example:
Configure::write('Exception', array(
'handler' => 'ErrorHandler::handleException',
'renderer' => 'AppExceptionRenderer',
'log' => true
));
/app/Controller/ErrorsController.php
class ErrorsController extends AppController {
public $name = 'Errors';
public function beforeFilter() {
parent::beforeFilter();
$this->Auth->allow('error404');
}
public function error404() {
//$this->layout = 'default';
$this->set('title_for_layout', 'Vyskytla sa chyba');
}
}
/app/Lib/Error/AppExceptionRenderer.php
App::uses('ExceptionRenderer', 'Error');
class AppExceptionRenderer extends ExceptionRenderer {
public function notFound($error) {
$this->controller->redirect(array('controller' => 'errors', 'action' => 'error404'));
}
}
/app/View/Errors/error404.ctp
<div class="inner404">
<h2>404 Error - Page Not Found</h2>
</div>
Insert it where you need: throw new NotFoundException();
Ref: CakePHP 2.0 - How to make custom error pages?
For < CakePHP 2.x:
If you create a custome error page view in app/views/errors then in a
php section on that error view page you can use:
$this->setLayout("Title for the error page here");
Then when you see the error page, it will have your title. Again, that
is if you set a custom error page.
Here is another way to do the same you needed.
// Create an error.php file in your /app folder with the following code:
<?php
class AppError extends ErrorHandler {
function error404($params) {
$this->controller->layout = "error";
$this->set('title_for_layout', 'Vyskytla sa chyba');
parent::error404($params);
}
}
?>