Hello,
I have a form in which a user can upload an image via a file input field. The user is allowed to leave the file field empty so it remains empty upon creation or doesnt get updated in the case its left empty on the edit screen.
When left empty the file type validation is somehow triggered
When i use the below check, file uploading works, but the validation triggers even if left blank
if($this->request->getPost("image") !== '') {
//
}
if i change this to the below, the validation is skipped but the image/file upload doesnt work anymore.
if($this->request->getPost("image") !== NULL) {
//
}
This is the full controller (above is in the save- and create action)
<?php
use PhalconTime\Forms\UserForm;
use PhalconTime\Models\User;
use Phalcon\Security\Random;
class UserController extends ControllerBase
{
/**
* The start action, it shows the "search" view
*/
public function indexAction()
{
$users = User::find();
$this->view->users = $users;
}
/**
* Execute the "search" based on the criteria sent from the "index"
* Returning a paginator for the results
*/
public function searchAction()
{
// ...
}
/**
* Shows the view to create a "new" user
*/
public function newAction()
{
$this->view->setVar('form', new UserForm(null, ['edit' => false]));
}
/**
* Shows the view to "edit" an existing user
*/
public function editAction($id)
{
if (!$this->request->isPost()) {
$user = User::findFirstById($id);
if (!$user) {
$this->flash->error('User not found');
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
$user->setPassword('');
$this->view->setVar('form', new UserForm($user, ['edit' => true]));
}
}
/**
* Creates a user based on the data entered in the "new" action
*/
public function createAction()
{
if (!$this->request->isPost()) {
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
$form = new UserForm;
$user = new User;
$data = $this->request->getPost();
if (!$form->isValid($data, $user)) {
foreach ($form->getMessages() as $message) {
$this->flash->error($message);
}
return $this->dispatcher->forward(["controller" => "user", "action" => "new" ]);
}
$password = $this->request->getPost("password");
$user->password = $this->security->hash($password);
// @TODO The check always triggers since it has to be !== NULL but if changed uploading doesnt work anymore
if($this->request->getPost("image") !== '') {
if($this->request->hasFiles()) {
foreach ($this->request->getUploadedFiles() as $file) {
if ($this->extensionCheck($file->getRealType())) {
$random = new Random();
$uuid = $random->uuid();
$user->image = $uuid.'_'.$file->getName();
$file->moveTo('img/uploads/'.$uuid.'_'.$file->getName());
}
else {
$this->flash->error('This typ of file is not supported');
return $this->dispatcher->forward(["controller" => "user", "action" => "new" ]);
}
}
}
}
if ($user->save() == false) {
foreach ($user->getMessages() as $message) {
$this->flash->error($message);
}
return $this->dispatcher->forward(["controller" => "user", "action" => "new" ]);
}
$form->clear();
$this->flash->success("User created");
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
/**
* Updates a user based on the data entered in the "edit" action
*/
public function saveAction()
{
if (!$this->request->isPost()) {
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
$id = $this->request->getPost("id", "int");
$user = User::findFirstById($id);
if (!$user) {
$this->flash->error("User not found");
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
$currentPassword = $user->getPassword();
$form = new UserForm;
$this->view->setVar('form', $form);
if($this->request->getPost("password") !== '') {
$data = $this->request->getPost();
// @TODO on edit screen validation doesn't work
// if (!$form->isValid($data, $user)) {
// foreach ($form->getMessages() as $message) {
// $this->flash->error($message);
// }
// return $this->dispatcher->forward(["controller" => "user", "action" => "edit" , "params" => $id]);
// }
$password = $this->request->getPost("password");
$user->password = $this->security->hash($password);
}
else {
$user->password = $currentPassword;
}
if($this->request->getPost("image") !== '') {
if($this->request->hasFiles()) {
foreach ($this->request->getUploadedFiles() as $file) {
if ($this->extensionCheck($file->getRealType())) {
$random = new Random();
$uuid = $random->uuid();
$user->image = $uuid.'_'.$file->getName();
$file->moveTo('img/uploads/'.$uuid.'_'.$file->getName());
}
else {
$this->flash->error('This typ of file is not supported');
return $this->dispatcher->forward(["controller" => "user", "action" => "new" ]);
}
}
}
}
if ($user->save() == false) {
foreach ($user->getMessages() as $message) {
$this->flash->error($message);
}
return $this->dispatcher->forward(["controller" => "user", "action" => "edit" , "params" => $id]);
}
$form->clear();
$this->flash->success('User updated');
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
/**
* Deletes an existing user
*/
public function deleteAction($id)
{
$user = User::findFirstById($id);
if (!$user) {
$this->flash->error("User not found");
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
if (!$user->delete()) {
foreach ($user->getMessages() as $message) {
$this->flash->error($message);
}
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
$this->flash->success("User deleted");
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
/**
* Delete only the image
*/
public function deleteImageAction($id)
{
$user = User::findFirstById($id);
if (!$user) {
$this->flash->error("User not found");
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
$user->image = NULL;
$form = new UserForm;
$this->view->setVar('form', $form);
if ($user->save() == false) {
foreach ($user->getMessages() as $message) {
$this->flash->error($message);
}
return $this->dispatcher->forward(["controller" => "user", "action" => "edit" , "params" => $id]);
}
$form->clear();
$this->flash->success('Image removed');
return $this->dispatcher->forward(["controller" => "user", "action" => "edit" ]);
}
/**
* Confirm before deleting records
*/
public function confirmAction($id)
{
if(!$id) {
$this->flash->error("User not found");
return $this->dispatcher->forward(["controller" => "user", "action" => "index" ]);
}
$this->view->setVar('id', $id);
}
/**
* Attempt to determine the real file type of a file.
*
* @param string $extension Extension (eg 'jpg')
* @return boolean
*
* @TODO move to form object, https://docs.phalcon.io/en/3.0.0/api/Phalcon_Validation_Validator_File.html
*/
private function extensionCheck($extension)
{
$allowedTypes = [
'image/gif',
'image/jpg',
'image/png',
'image/bmp',
'image/jpeg'
];
return in_array($extension, $allowedTypes);
}
}
And below is the form
<?php
namespace PhalconTime\Forms;
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
use Phalcon\Forms\Element\Hidden;
use Phalcon\Forms\Element\Password;
use Phalcon\Forms\Element\Check;
use Phalcon\Forms\Element\File;
use Phalcon\Validation\Validator\File as FileValidator;
use Phalcon\Validation\Validator\PresenceOf;
use Phalcon\Validation\Validator\Email;
use Phalcon\Validation\Validator\Identical;
use Phalcon\Validation\Validator\StringLength;
use Phalcon\Validation\Validator\Confirmation;
class UserForm extends Form
{
/**
* Initialize the project status form
*
* @param mixed $entity
* @param array $options
*/
public function initialize($entity = null, $options = [])
{
if (isset($options['edit']) && $options['edit'] === TRUE) {
$id = new Hidden(
"id", [
"class" => "hidden",
]
);
$this->add($id);
}
// Name
$name = new Text(
"name",
[
"placeholder" => "Name",
"class" => "form-control",
]
);
$name->setLabel("Name");
$name->setFilters(
[
"striptags",
"string",
]
);
$name->addValidators(
[
new PresenceOf(
[
"message" => "Name is required",
]
)
]
);
$this->add($name);
// Email
$email = new Text(
"email",
[
"placeholder" => "E-mailaddress",
"class" => "form-control",
]
);
$email->setLabel("E-mail");
$email->setFilters(
[
"striptags",
"string",
]
);
$email->addValidators(
[
new PresenceOf(
[
"message" => "E-mailaddress is required",
]
),
new Email(
[
'message' => 'E-mailaddress is not valid'
]
)
]
);
$this->add($email);
// Password
$password = new Password(
"password",
[
"placeholder" => "Password",
"class" => "form-control",
]
);
$password->setLabel("Password");
$password->setFilters(
[
"striptags",
"string",
]
);
$password->addValidators(
[
new PresenceOf(
[
"message" => "Password is required",
]
),
new StringLength(
[
'min' => 8,
'messageMinimum' => 'Password is too short. Minimum 8 characters'
]
),
new Confirmation(
[
'message' => 'Password doesn\'t match confirmation',
'with' => 'passwordRepeat'
]
)
]
);
$this->add($password);
// Password repeat
$passwordRepeat = new Password(
"passwordRepeat",
[
"placeholder" => "Password repeat",
"class" => "form-control",
]
);
$passwordRepeat->setLabel("Password repeat");
$passwordRepeat->setFilters(
[
"striptags",
"string",
]
);
$passwordRepeat->addValidators(
[
new PresenceOf(
[
"message" => "Password repeat is required",
]
)
]
);
$this->add($passwordRepeat);
// File
$file = new File(
"image",
[
"placeholder" => ""
]
);
$file->setLabel("Profile picture");
$file->addValidators(
[
new FileValidator(
[
'allowEmpty' => true
]
)
]
);
$this->add($file);
// Active
$active = new Check(
"active",
[
"value" => 1,
"checked" => "checked"
]
);
$active->setLabel("Active");
$active->setFilters(
[
"striptags",
"int",
]
);
$this->add($active);
}
}