Previously, I asked the following question.
When I'am in the edit-screen and I set the value "Done" in the field "Project_status", is it then possible that I can force me to change the field "Afgehandeld" to the value "Arjan" automaticly.
Because I was not able to add my code to the provided answeres, I asked it again, but now with the code that I already have.
This code is unfortunily not working
Who can further help this newbie?
Thanks in advance.
<?php
/* src/template/projecten/index.ctp */
foreach ($projecten as $DB_inhoud):
...
...
echo $DB_inhoud->Project_status;
echo $DB_inhoud->Opgeleverd;
...
...
endforeach;
?>
<?php
/* src/template/projecten/edit.ctp */
...
echo $this->Form->select('Project_status', $status, ['escape' => true]);
echo $this->Form->input('Opgeleverd',['label' => false]);
...
...
?>
<?php
/* src/Model/Table/ProjectenTable.php */
namespace App\Model\Table;
use Cake\ORM\Table;
use Cake\Validation\Validator;
use Cake\ORM\RulesChecker;
Class ProjectenTable extends Table
{
Public function initialize (array $config)
{
$this->addBehavior('Timestamp');
}
public function customValidationMethod($check, array $context)
{
$validator->add('Projecten->Opgeleverd', 'custom',
['rule' => function ($value, $context)
{
echo $context;
if ($context['Projecten->Project_status'] == "100. Project opgeleverd")
{
return $value == "Arjan";
}
return true;
},
'message' => 'Error message'
]);
}
}
Related
I have a field 'screenshot' that when I try to access in beforeSave callback the field it's empty.
The thing I do is access the $data on the beforeMarshal callback and store the array
into a model setting, then I can access that in the beforeSave and set 'screenshot' field to filename.ext if move_uploaded_file is true.
This is the current code:
Model
// Using CakePHP 3.8.5
public function validationDefault(Validator $validator)
{
$validator
->allowEmptyFile('screenshot', 'update')
->uploadedFile('screenshot' , [
'types' => ['image/jpeg', 'image/jpg', 'image/pjpeg'],
'maxSize' => 1000000 // 1MB
]);
return $validator;
}
public function beforeMarshal(Event $event, ArrayObject $data, ArrayObject $options)
{
if (isset($data['screenshot']) && $data['screenshot']['error'] === UPLOAD_ERR_OK) {
$this->config([ 'file_array' => $data['screenshot'] ])
}
}
public function beforeSave(Event $event, EntityInterface $entity, ArrayObject $options)
{
...
$file = $this->config([ 'file_array');
if (move_uploaded_file($file['tmp_name'], $file_path)) {
return true;
} else {
throw new Exception(__('Unable to move...'));
}
}
Form
<?= $this->Form->create($project, ['type' => 'file']) ?>
<?= $this->Form->control('screenshot', ['type' => 'file', 'class' => 'form-control-file']) ?>
<?= $this->Form->button(__('Submit'), ['class' => 'btn btn-primary col-md-3 offset-md-9']) ?>
<?= $this->Form->end() ?>
The code I expected to work
public function validationDefault(Validator $validator)
{
$validator
->allowEmptyFile('screenshot', 'update')
->uploadedFile('screenshot' , [
'types' => ['image/jpeg', 'image/jpg', 'image/pjpeg'],
'maxSize' => 1000000 // 1MB
]);
return $validator;
}
public function beforeSave(Event $event, EntityInterface $entity, ArrayObject $options)
{
...
$file = $entity->screenshot; // this is empty
if (move_uploaded_file($file['tmp_name'], $file_path)) {
return true;
} else {
throw new Exception(__('Unable to move...'));
}
}
Why is $entity->screenshot empty on BeforeSave?
Is this the correct way to do this?
At marshalling time (when patching/creating entities), CakePHP will cast/convert the input according to the database types mapped for the fields.
For your database field screenshot, which is VARCHAR, that would be \Cake\Database\Type\StringType, which returns an empty string for arrays. The reasoning being that the marshalling stage shouldn't cause "crashes", but ideally create entities with data compatible to the respective database types, which can finally be validated via application rules if necessary, for which the errors can be as easily presented to the user as the ones for the validation rules.
The two most popular ways to handle this IMHO are:
Using a different field name for the upload, one that isn't mapped to an existing database column, eg something like screenshot_upload
Using a custom database type for the field, one that doesn't transform the array
Personally I prefer the former.
I have created and registered a Yii2 component function 'formSchema' which
contains the array as such:
class FormSchema extends Component{
public function formSchema()
{
$fields = array(
['field' => 'username', 'controltype' => 'textinput'],
['field' => 'email', 'controltype' => 'textArea'],
);
return $fields;
}
}
?>
I call the array in the active form, however I cannot get the
['controltype'] using the same successful method as I do to retrieve ['field'] as
below. I would like to get that array element however seem unable to get any but the first level element:
<div class="usermanager-form">
<?php $form = ActiveForm::begin(['id'=>$model->formName()]); ?>
<?php
$fields = $items = Yii::$app->formschema->formSchema();
foreach($fields as $field)
{
$field = $field['field'];
echo $form->field($model, $field);
}
?>
You may use array values in this way:
$fields = Yii::$app->formschema->formSchema();
foreach ($fields as $field) {
echo $form->field($model, $field['field'])->{$field['controltype']}();
}
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 need to update a particular row. This doesn't seem to work. Any help is appreciated.
View updated:
<?php
echo $this->Form->create("Setting", array('action' => 'index'));
echo $this->Form->input('id', array('type' => 'hidden'));
echo $this->Form->checkbox('blog_state');
echo $this->Form->end('Save Post');
?>
Controller updated:
public function index($id = 0){
$this->Setting->id = $id;
if (empty($this->request->data)) {
$this->request->data = $this->Setting->read();
} else {
if ($this->request->is('post')) {
$this->request->data['Setting']['id'] = $id;
$this->Setting->save($this->request->data);
$this->Session->setFlash('This should have saved...');
}
}
}
Edit:
blog_state is a boolean, and works fine. It loads the value from the DB normally and saves it to the new row normally. (I need it to update the existing row it is being pulled from, which is where my problem is)
Update your view:
<?php
echo $this->Form->create("Setting", array('action' => 'index'));
echo $this->Form->input('id', array('type' => 'hidden'));
echo $this->Form->checkbox('blog_state');
echo $this->Form->end('Save Page');
?>
You will also need to make sure you set the id in the function so it will populate the value correctly. The record cannot be updated unless it knows the PK ID it is updating.
The way you can accomplish this is by setting it in the request data:
$this->request->data['Setting']['id'] = $id;
Then it will automatically be set in the view.
UPDATE
It looks like your logic may be flawed. The form will not necessarily pass the ID back on the URL. So update you form like so and check again if it works. It looks like the way you currently have it it will set ID to null which will create a new record.
public function index($id = 0){
if (empty($this->request->data)) {
$this->Setting->id = $id;
$this->request->data = $this->Setting->read();
} else {
if ($this->request->is('post')) {
$this->Setting->save($this->request->data);
$this->Session->setFlash('This should have saved...');
}
}
}
Well you need to know what row it is effecting (this will usually be argument to your function).
public function index() {
// Things here
}
This will create the index page for that controller.
Create an edit function like
public function edit($id = null) {
$this->Setting->id = $id;
if (!$this->Setting->exists()) {
// Exception.
}
if ($this->Setting->save($this->request->data)) {
$this->Session->setFlash(__('Saved'));
}
}
Then you can access it like http://example.com/setting/edit/45
Make sure you have primary key id column in your DB if not override the your chosen primary key in model like below.
<?php
class Test extends AppModel{
public $primaryKey = 'primarykey column name';
}
?>