I'm trying to working with the Uploader Plugin to create a structure where a User Model can upload it's avatar with the Avatar Model, I've read the instructions several times but when I try to $this->Uploader->upload('Avatar.filename') I get no validation errors but the upload method fails.
Here is how I've written the User Model
<?php
class User extends AppModel {
public $name = 'User';
public $hasOne = array(
'Profile' => array(
'className' => 'Profile',
'conditions' => '',
'dependent' => true,
'foreignKey' => 'user_id',
'associatedKey' => 'user_id'
),
'Avatar' => array (
'className' => 'Avatar',
'foreignKey' => 'user_id',
'dependent' => true
)
);
public $validate = array(...);
// other stuff not relevant here...
?>
Here is the Avatar Model
<?php
class Avatar extends AppModel {
public $name = 'Avatar';
public $actsAs = array (
'Uploader.Attachment' => array (
'Avatar.filename' => array(
'name' => 'setNameAsImgId', // Name of the function to use to format filenames
'baseDir' => '', // See UploaderComponent::$baseDir
'uploadDir' => 'files/avatars/', // See UploaderComponent::$uploadDir
'dbColumn' => 'filename', // The database column name to save the path to
'importFrom' => '', // Path or URL to import file
'defaultPath' => '', // Default file path if no upload present
'maxNameLength' => 500, // Max file name length
'overwrite' => true, // Overwrite file with same name if it exists
'stopSave' => true, // Stop the model save() if upload fails
'allowEmpty' => true, // Allow an empty file upload to continue
'transforms' => array (
array('method' => 'resize', 'width' => 128, 'height' => 128, 'dbColumn' => 'name')
) // What transformations to do on images: scale, resize, ete
)
),
'Uploader.FileValidation' => array (
'Avatar.filename' => array (
'maxWidth' => array (
'value' => 512,
'error' => 'maxWidth error'
),
'maxHeight' => array (
'value' => 512,
'error' => 'maxWidth error'
),
'extension' => array (
'value' => array('gif', 'jpg', 'png', 'jpeg'),
'error' => 'extension error'
),
'filesize' => array (
'value' => 5242880,
'error' => 'filesize error'
)
)
)
);
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'order' => ''
)
);
public function setNameAsImgId ($name, $field, $file) {
/**
* Format the filename a specific way before uploading and attaching.
*
* #access public
* #param string $name - The current filename without extension
* #param string $field - The form field name
* #param array $file - The $_FILES data
* #return string
*/
// devo ricavare l'id dell'immagine appena creata per rinominare il file
return $name;
}
}
?>
This is the UsersController for edit method
<?php
App::uses('CakeEmail','Network/Email');
CakePlugin::load('Uploader');
App::import('Vendor', 'Uploader.Uploader');
class UsersController extends AppController {
public $name = 'Users';
public function edit ($id) {
$this->User->id = $id;
if (!$this->User->exists()) {
throw new NotFoundException ('Nessuna corrispondenza trovata per questo utente');
}
if (!$id) {
$this->set('flash_element','error');
$this->Session->setFlash ('Utente non valido');
}
$this->User->recursive = 1;
$this->set('user', $this->User->read());
if ($this->request->is('post')) {
$this->User->id = $this->request->data['User']['id'];
if (!$this->User->exists()) {
$this->set('flash_element','warning');
$this->Session->setFlash('Nessun utente trovato con questa corrispondenza');
}
if ($this->User->save($this->request->data)) {
$this->request->data['Profile']['user_id'] = $this->User->id;
$conditions = array(
'conditions' => array(
'Profile.id' => $this->request->data['Profile']['id']
)
);
if ($this->User->Profile->save($this->request->data, $conditions)) {
if (!empty($this->request->data['Avatar']['filename'])) {
$this->request->data['Avatar']['user_id'] = $this->User->id;
if ($this->User->Avatar->save($this->request->data)) {
$avatar = $this->User->Avatar->find('first', array(
'conditions' => array('Avatar.user_id' => $this->User->id)
));
$ext = Uploader::ext($this->request->data['Avatar']['filename']);
$filename = $avatar['Avatar']['id'].'.'.$ext;
if ($this->User->Avatar->save('Avatar.filename')) {
$this->set('flash_element','done');
$this->Session->setFlash('Avatar changed successfully');
debug('saved successfully');
} else {
debug('not saved');
$this->set('flash_element','warning');
$this->Session->setFlash('Avatar not saved on the server');
}
} else {
$this->Session->write('flash_element','error');
$this->Session->setFlash('Avatar data not saved on the server');
$this->redirect(array('action'=>'index'));
}
} else {
$this->Session->write('flash_element','done');
$this->Session->setFlash('Data successfully saved, avatar not changed');
$this->redirect(array('action'=>'index'));
}
} else {
$this->set('flash_element','error');
$this->Session->setFlash('Error on saving Profile data to the server');
}
} else {
$this->Session->write('flash_element','error');
$this->Session->setFlash('Error on saving User data to the server');
$this->redirect(array('action'=>'index'));
}
}
}
}
?>
And in the view file I have this
<?php
echo $this->Form->create('User', array ('class' => 'form'));
echo $this->Form->input('User.id', array ('type'=>'hidden', 'value'=> $user['User']['id'],'label'=> false, 'id' => 'id'));
echo $this->Form->input('User.username', array ('label'=> false, 'value' => $user['User']['username'], 'id' => 'username', 'after' => '<div class="message">Message for username field'));
echo $this->Form->input('User.email', array ('label'=> false, 'value' => $user['User']['email'], 'id' => 'email', 'after' => '<div class="message">Message for email field</div>'));
echo $this->Form->input('UserOptions.id', array ('type'=>'hidden', 'value'=> $user['UserOptions']['id'],'label'=> false, 'id' => 'UserOptions.id'));
$attributes = array ('value' => $user['UserOptions']['avatar_type'], 'empty' => false);
$options = array('0' => 'This site', '1' => 'Gravatar');
echo $this->Form->select('UserOptions.avatar_type', $options, $attributes);
/* avatar code */
echo $this->Form->input('Avatar.id', array ('type'=>'hidden', 'value'=> $user['Avatar']['id'],'label'=> false, 'id' => 'Avatar.id'));
echo $this->Form->input('Avatar.filename', array('type' => 'file'));
/* end avatar code */
echo $this->Form->input('Profile.city', array ('label'=> false, 'value' => defaultValue ('City', $user['Profile']['city']), 'id' => 'city', 'after' => '<div class="message">Message for city field</div>'));
echo $this->Form->input('Profile.country', array ('label'=> false, 'value' => defaultValue('',$user['Profile']['country']), 'id' => 'country', 'after' => '<div class="message">Message for country field</div>'));
echo $this->Form->input('Profile.url', array ('label'=> false, 'value' => defaultValue('http://', $user['Profile']['url']), 'id' => 'url', 'after' => '<div class="message">Message for url field</div>'));
echo $this->Form->input('Profile.description', array ('label'=> false, 'value' => defaultValue('Description',$user['Profile']['description']), 'id' => 'description', 'after' => '<div class="message">Message for description field</div>'));
echo $this->Form->submit('Modifica', array('id'=>'edit'));
echo $this->Form->end();
?>
In the Controller, every part of the data is saved until I reach $this->Uploader->upload('Avatar.filename', array('overwrite' => true, 'name' => $filename)) where I get a generic error.
This Plugin seems to be the best way to do it without write tons of code, but I'm not sure how to use it.
I'm not sure what's wrong with the code, can You help me to solve the problem?
I've found the problems, I forgot two things:
In the view page I've forgot 'type' => 'file'
<?php
echo $this->Form->create('User', array ('class' => 'form', 'type' => 'file'));
?>
I was used to work with 1.3 version so the app/Config/bootstrap.php configuration was missing:
<?php
CakePlugin::load('Uploader');
?>
Now it works!
Related
I have a form with one field and a submit button with ajax submission option like following -
public function buildForm(array $form, FormStateInterface $form_state, $id = 0)
{
$form['fieldset']['message'] = array(
'#type' => 'textfield',
'#default_value' => "",
'#required' => true,
'#attributes' => array(
'placeholder' => t('write here'),
),
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => $this->t('Send'),
'#attributes' => array(
'class' => array(
),
),
'#ajax' => [
'callback' => [$this, 'Ajaxsubmit'],
'event' => 'click']
);
return $form;
}
The ajax function is following -
public function Ajaxsubmit(array $form, FormStateInterface $form_state)
{
$user = \Drupal\user\Entity\User::load(\Drupal::currentUser()->id());
$db_values = [
"message" => $form_state->getValue("message"),
"date_create" => date("Y-m-d H:i:s"),
];
$save = DbStorage::Insert($db_values);
//$('#mychat_form input').val("");
//$form_state->setValue('content', NULL);
$response = new AjaxResponse();
if ($form_state->hasAnyErrors() || !$save) {
$response->addCommand(new AlertCommand('something wrong!'));
} else {
$message = DbStorage::Get(["id" => $save]);
$send_id = $message->send_id;
$build = [
'#theme' => "chat_view",
'#message' => $message,
'#sender' => $send_id,
'#current_user' => true
];
$ans_text = render($build);
$response->addCommand(new AppendCommand('#mychat', $ans_text));
}
return $response;
}
Here form data submission is working fine. But input data is not cleared after submission. I tried to clear it from my javascript using -
$('#my_form input').val("");
But the problem is my javascript file is called every 3 seconds and the form input is also cleared in every 3 seconds. this is problematic for users. Is there any other way to clear the form input after the ajax submission ? Can i do anything inside Ajaxsubmit function ?
You can use InvokeCommand for doing it.
For e.g: to clear an input value $('#my_form input').val(""); in ajax response
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\InvokeCommand;
use Drupal\Core\Ajax\AppendCommand;
:
$form['fieldset']['message'] = array(
'#type' => 'textfield',
'#default_value' => "",
'#required' => true,
'#attributes' => array(
'placeholder' => t('write here'),
'class' => ['custom-class'],
),
);
In Ajax function
:
$build = [
'#theme' => "chat_view",
'#message' => $message,
'#sender' => $send_id,
'#current_user' => true
];
$response->addCommand(new AppendCommand('#mychat', $build));
$response->addCommand(new InvokeCommand('.custom-class', 'val', ['']));
I tried to validate a simple form in zend framework 2 for days now.
I checked the documentation and a lot of posts considering this topic but I found no solution!
I have a very simple form:
class AlimentForm extends Form
{
public function __construct($name = null)
{
parent::__construct('aliment');
$this->add(array(
'required'=>true,
'name' => 'year',
'type' => 'Text',
'options' => array(
'label' => 'Jahr',
),
));
$this->add(array(
'required'=>true,
'name' => 'number',
'type' => 'Text',
'options' => array(
'label' => 'Number',
),
));
$this->add(array(
'name' => 'submit',
'type' => 'Submit',
'attributes' => array(
'value' => 'Go',
'id' => 'submitbutton',
),
));
}
}
I created a custom InputFilter:
namespace Application\Form;
use Zend\InputFilter\InputFilter;
class AlimentInputFilter extends InputFilter {
public function init()
{
$this->add([
'name' => AlimentForm::year,
'required' => true,
'validators' => array(
array(
'name' => 'Between',
'options' => array(
'min' => 1900,
'max' => 3000,
),
),
),
]);
}
}
and finally in my controller I try to validate the form
public function alimentAction(){
$form = new AlimentForm();
$form->setInputFilter(new AlimentInputFilter());
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->getPost());
if ($form->isValid()) {
$year = $form->get('year')->getValue();
$number = $form->get('number')->getValue();
return array('result' => array(
"msg" => "In the Year ".$year." you get ".$number." Points"
));
}
}
return array('form' => $form);
}
It can't be that difficult, but from all those different ways to validate a form I found in the net, I'm a bit confused...
What am I missing?
Greetings and thanks in advance
U.H.
Ok, I solved the problem.
I created a Model for the aliment Form that has a year and a number attribute
and I defined an input filter within that model:
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
class Aliment implements InputFilterAwareInterface
{
public $year;
public $number;
public function exchangeArray($data){
$this->year = (!empty($data['year']))?$data['year']:null;
$this->number = (!empty($data['number']))?$data['number']:null;
}
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new \Exception("Not used");
}
public function getInputFilter()
{
if (!$this->inputFilter) {
$inputFilter = new InputFilter();
$inputFilter->add(array(
'name' => 'year',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'Between',
'options' => array(
'min' => 1900,
'max' => 3000
)
)
),
));
$inputFilter->add(array(
'name' => 'number',
'required' => true,
'filters' => array(
array('name' => 'StripTags'),
array('name' => 'StringTrim'),
),
'validators' => array(
array(
'name' => 'Between',
'options' => array(
'min' => 1,
'max' => 10
)
)
),
));
$this->inputFilter = $inputFilter;
}
return $this->inputFilter;
}
}
In the action method of the controller I was able to set the InputFilter of the model to the form and voila! It worked!
public function alimentAction(){
$form = new AlimentForm();
$request = $this->getRequest();
if ($request->isPost()) {
$aliment = new \Application\Model\Aliment;
$form->setInputFilter($aliment->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$aliment->exchangeArray($form->getData());
$year = $form->get('year')->getValue();
return array(
'result' => array(
//your result
)
);
}
}
return array('form' => $form);
}
The form is correctly validated now and returns the corresponding error messages.
I hope, it help somebody whos got similar problems with validating!
I am using CodeIgniter 2.3.1 and created a form_validation.php file in config and the content is as below.
<?php
$config = array(
array(
'field' => 'firstname',
'label' => 'First Name',
'rules' => 'required'
),
array(
'field' => 'lastname',
'label' => 'Last Name',
'rules' => 'required'
),
array(
'field' => 'email',
'label' => 'Email',
'rules' => 'required|valid_email|callback_unique_email'
),
array(
'field' => 'password',
'label' => 'Password',
'rules' => 'required|matches[confirm_password]'
),
array(
'field' => 'confirm_password',
'label' => 'Confirm Password',
'rules' => 'required'
)
);
function unique_email($email) {
if($email == 'm#gmail.com') {
$this->form_validation->set_message('unique_email', 'Hello World !');
return false;
}
}
?>
And checking the form_validation in register function of user controller. The code is below.
public function register() {
$this->load->helper('form');
$data['message'] = '';
if($this->input->post('submit')) {
$this->load->library('form_validation');
if($this->form_validation->run() == FALSE) {
$data['message'] = 'User could not be saved.';
} else {
$user_data['firstname'] = $this->input->post('firstname');
$user_data['lastname'] = $this->input->post('lastname');
$user_data['email'] = $this->input->post('email');
$user_data['password'] = md5($this->input->post('password'));
if($this->user_model->insert($user_data)) {
if($this->user_model->login($user_data)) {
$this->session->set_flashdata('message', 'User saved successfully.');
redirect('/user', 'refresh');
}
}
}
}
$this->load->view('user/register', $data);
}
But I am not getting validation message for the custom method. Please suggest me how to do it?. The work is more appreciated.
Have a look at the following documentation: http://ellislab.com/codeigniter/user-guide/libraries/form_validation.html#callbacks
As you can see int the documentation, the custom validation function actually belongs in the controller, and not in the config file. By moving the validation function to the controller, the callback function should start getting called.
Another fun fact, people can access this unique_email function through a url (ie. http://yoursite.com/index.php/user/unique_email). To avoid this, we can write the function as a private function by simply placing an underscore at the beginning of the function, like so:
function _unique_email($email) {
...
}
You can then call the function in your validation by using the new function name in your config (notice the extra underscore in the callback:
array(
'field' => 'email',
'label' => 'Email',
'rules' => 'required|valid_email|callback__unique_email'
)
In the end, your controller should look similar to the following:
class User extends CI_Controller {
public function register() {
$this->load->helper('form');
$data['message'] = '';
if($this->input->post('submit')) {
$this->load->library('form_validation');
if($this->form_validation->run() == FALSE) {
$data['message'] = 'User could not be saved.';
} else {
$user_data['firstname'] = $this->input->post('firstname');
$user_data['lastname'] = $this->input->post('lastname');
$user_data['email'] = $this->input->post('email');
$user_data['password'] = md5($this->input->post('password'));
if($this->user_model->insert($user_data)) {
if($this->user_model->login($user_data)) {
$this->session->set_flashdata('message', 'User saved successfully.');
redirect('/user', 'refresh');
}
}
}
}
$this->load->view('user/register', $data);
}
function _unique_email($email) {
if($email == 'm#gmail.com') {
$this->form_validation->set_message('unique_email', 'Hello World !');
return false;
}
}
}
Your config would look similar to the following:
$config = array(
array(
'field' => 'firstname',
'label' => 'First Name',
'rules' => 'required'
),
array(
'field' => 'lastname',
'label' => 'Last Name',
'rules' => 'required'
),
array(
'field' => 'email',
'label' => 'Email',
'rules' => 'required|valid_email|callback__unique_email'
),
array(
'field' => 'password',
'label' => 'Password',
'rules' => 'required|matches[confirm_password]'
),
array(
'field' => 'confirm_password',
'label' => 'Confirm Password',
'rules' => 'required'
)
);
I used this answer and got error:
Unable to access an error message corresponding to your field name.
In function _unique_email instead set_message('unique_email', 'Hello World !'); should be set_message('_unique_email', 'Hello World !'); like this:
function _unique_email($email) {
if($email == 'm#gmail.com') {
$this->form_validation->set_message('_unique_email', 'Hello World !');
return false;
}
}
I'm having some issues with validating form fields inside my controller, for testing purposes.
I have my model Experience with hasMany ExperienceDetail. ExperienceDetail belongsTo Experience.
I created a form using the FormHelper which contains the following:
index.ctp
<?php
echo $this->Form->create('Experience', array('action' => 'index'));
echo $this->Form->input('Experience.date', array(
'label' => array(
'text' => 'Datum'),
'type' => 'date',
'dateFormat' => 'DMY',
'monthNames' => false,
'minYear' => date('Y') - 10,
'maxYear' => date('Y')
)
);
echo $this->Form->input('Experience.test');
echo $this->Form->input('ExperienceDetail.vertrekstation');
echo $this->Form->end('Verstuur!');
?>
There are some more fields provided with ExperienceDetail, but these are irrelevant for this matter.
Experience.php
<?php
class Experience extends AppModel {
public $name = 'Experience';
public $hasMany = 'ExperienceDetail';
public $validate = array(
'vertrekstation' => array(
'rule' => 'notEmpty',
'message' => 'Voer een vertrekstation in',
'required' => true
),
'test' => array(
'rule' => 'notEmpty',
'message' => 'Test mag niet leeg zijn!'
)
);
}
?>
ExperienceDetail.php
<?php
class ExperienceDetail extends AppModel {
public $name = 'ExperienceDetail';
public $belongsTo = 'Experience';
public $validate = array(
'vertrekstation' => array(
'rule' => 'notEmpty',
'message' => 'Voer een vertrekstation in'
)
);
}
?>
ExperiencesController.php
<?php
class ExperiencesController extends AppController {
public $helpers = array('Html', 'Form', 'Session');
public function index() {
// $this->layout = 'default_orig';
$this->set('title_for_layout', 'De OV-Ervaringenmeter!');
// LOAD Model Carrier
$this->loadModel('Carrier');
$this->set('carrier', $this->Carrier->find('list', array('order' => array('Carrier.name' => 'asc'))));
// Check if form is allready filled
if($this->request->is('post')) {
$this->Experience->set($this->request->data);
$this->Session->setFlash('No if or else statement is called');
if ($this->Experience->validates()) {
$this->Session->setFlash('Validates!');
}
}
}
}
?>
The problem is: when I send the form and leave test empty, it provides me the validation error which I've set up in the Model. But when I leave vertrekstation empty, it doesn't provide me any errors that belongs to the input field.
What am I doing wrong and how am I able to get these errors printed?
I currently have the following models:
class Category extends AppModel {
var $name = 'Category';
/*var $validate = array(
'name' => 'multiple'
);
no idea how to use this
*/
var $hasAndBelongsToMany = array(
'Post' => array(
'className' => 'Post'
)
);
class Post extends AppModel {
var $name = 'Post';
var $hasAndBelongsToMany = array(
'Category' => array(
'className' => 'Category'
)
);
var $belongsTo = array(
'Page' => array(
'className' => 'Page'
)
);
class Page extends AppModel {
var $name = 'Page';
var $order = array('Page.modified' => 'desc');
var $hasOne = array(
'Post' => array(
'className' => 'Post'
));
I also have this Form in the view:
<div id="content-wrap">
<div id="main">
<h2>Add Post</h2>
<?php echo $this->Session->flash();?>
<div>
<?php
echo $this->Form->create('Post');
echo $this->Form->input('Post.title');
echo $this->Form->input('Category.Category', array('multiple' => 'checkbox'));
echo $this->Form->input('Post.body', array('rows' => '3'));
echo $this->Form->input('Page.meta_keywords');
echo $this->Form->input('Page.meta_description');
echo $this->Form->end('Save Post');
?>
</div>
<!-- main ends -->
</div>
My Controller:
function admin_add() {
// pr(Debugger::trace());
$this->set('categories', $this->Post->Category->find('list'));
if ( ! empty($this->data)) {
$this->data['Page']['title'] = $this->data['Post']['title'];
$this->data['Page']['layout'] = 'index';
if ($this->Post->saveAll($this->data)) {
$this->Session->setFlash('Your post has been saved', 'flash_good');
$this->redirect($this->here);
}
}
}
The problem I am having is that I could save a Post without choosing a category for it.
I've tried adding the following as a rule to the Category Model:
var $validate = array(
'rule' => array('multiple', array('in' => array(1, 2, 3, 4))),
'required' => TRUE,
'message' => 'Please select one, two or three options'
);
The Post and Page Model validates.
How do I activate validation for the Category?
First off, you haven't set up the $validate variable properly. The keys in the $validate array must be field names. Secondly, the multiple rule is used to check if the value(s) of a field lies within a set of values.
var $validate = array(
'color' => array(
'multiple' => array(
'rule' => array('multiple', array('in' => array('Red', 'Blue', 'Green'))),
'required' => false,
'message' => 'Please select one, two or three options'
),
),
);
I checked the example in the book for multiple and it's a typo there. The above code is correct.
Next, if you want to validate related models, I suggest you do that in your beforeSave() function:
function beforeSave(){
if (isset($this->data['Category']['Category']) && empty($this->data['Category']['Category'])) {
return false;
}
return true;
}
Here, returning false from the beforeSave() would prevent the save from going through. So, you will have successfully validated your requirement.