I cant find why my code isn't working properly. I try to upload the image through the form and save it in a directory, but it isnt there. For a test I did echo on the file object from the form to display the name of the file and extension and its correct, but its not saving.
Here is my code:
Form:
class WgrajForm extends sfForm
{
public function configure()
{
$this->setWidgets(array(
'zdjęcie' => new sfWidgetFormInputFile(),
'nazwa' => new sfWidgetFormInput(),
));
$this->setValidators(array(
'zdjęcie' => new sfValidatorFile(array(
'mime_types' => 'web_images',
'path' => '/projektSymfony/web/images',
),array(
'mime_types' => 'Plik może być tylko zdjęciem'
)
),
'nazwa' => new sfValidatorString(array(), array('required' => 'pole wymagane')),
));
$this->getWidgetSchema()->setNameFormat('wgraj[%s]');
}
}
Action:
public function executeDodaj(sfWebRequest $request)
{
$this->form= new WgrajForm();
if ($request->isMethod('post'))
{
$this->form->bind(
$request->getParameter('wgraj'),
$request->getFiles('wgraj'));
if ($this->form->isValid())
{
$wgrane = $this->form->getValues();
$plik = $wgrane['zdjęcie'];
$pliknazwa = $wgrane['nazwa'];
$rozszerzenie = $plik->getExtension($plik->getOriginalExtension());
$plik->save('/projektSymfony/web/images/'.$pliknazwa.$rozszerzenie);
//$this->redirect('galeria/index');
}
}
}
The path parameter is better when you use sfConfig::get('sf_upload_dir') or sfConfig::get('sf_web_dir') in your case.
You don't need to save() the widget inside your action. You just need to save the form, and then, it will save your image.
if ($this->form->isValid())
{
$this->form->save();
$this->redirect('galeria/index');
}
Take a look at the documentation, you will find lots of information, specially the part of Jobeet tutorial about Form.
Related
I'm able to add file details in database but not able to update it.
I am able to add file details entries, but when i try to update only the file that i am updating is moved to the storage folder. My update manager doesn't show any errors and doesn't update the file details in database.
this is my file form
protected function addElements()
{
// Add "name" field
$this->add([
'type' => 'file',
'name' => 'image',
'attributes' => [
'id' => 'image'
],
'options' => [
'label' => 'ImageFile',
],
]);
// Add the Submit button
$this->add([
'type' => 'submit',
'name' => 'submit',
'attributes' => [
'value' => 'Add Image File',
'id' => 'submit',
],
]);
// Add the CSRF field
$this->add([
'type' => 'csrf',
'name' => 'csrf',
'options' => [
'csrf_options' => [
'timeout' => 600
]
],
]);
}
public function addInputFilter()
{
$inputFilter = new InputFilter\InputFilter();
// File Input
$fileInput = new InputFilter\FileInput('image');
$fileInput->setRequired(true);
$inputFilter->add($fileInput);
$this->setInputFilter($inputFilter);
}
}
this is the update image manager
public function updateImage($name, $size)
{
$images = new Images();
$images->setName($name);
$images->setSize($size);
// Apply changes to database.
$this->entityManager->flush();
}
and this is my controller
public function editAction()
{
$id = (int)$this->params()->fromRoute('id', -1);
if ($id<1) {
$this->getResponse()->setStatusCode(404);
return;
}
$image = $this->entityManager->getRepository(Images::class)
->find($id);
if ($image == null) {
$this->getResponse()->setStatusCode(404);
return;
}
// Create form
$form = new ImageUploadForm('update', $this->entityManager);
$request = $this->getRequest();
if ($this->getRequest()->isPost()) {
$data = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
$form->setData($data);
if($form->isValid()) {
$data = $form->getData();
$imgtmp = $data["image"]["tmp_name"];
$name = $data["image"]["name"];
$size = $data["image"]["size"];
$filepath = $this->_dir.$name;
move_uploaded_file($imgtmp, $filepath);
$this->achimotaImagesManager->updateImage($name, $size);
var_dump($name, $size);
return $this->redirect()->toRoute('images', ['action'=>'index']);
}
}
return new ViewModel([
'form' => $form,
]);
}
Do not create a new object
If you update an Images entity (consider naming it Image if it is one image), you should not create a new one. Hand over the $image you need to update:
public function updateImage($image, $name, $size){
$image->setName($name);
$image->setSize($size);
...
}
Persist before flush
You need to persist the entity before you flush.
$this->entityManager->persist($image);
$this->entityManager->flush();
Organize the code nicer
Do not inject entity manager in your controller. Inject rather a service through a factory, which handles all features of your Image entity. (ImageService.php)
Do not inject entity manager into your ImageService neither. Create a ImageMapper service, inject that into your ImageService. Create all Doctrine-related features in this Mapper. This has this advantage: Doctrin specific functionality is only in your Mapper files. Should you need to use another solution to store data, you only need to replace the Mapper files, providing the Service with the same interface.
Controller
public function editAction()
{
...
$this->serviceImage->update($image,$name,$size);
...
}
Service - ImageService.php
public function update($image,$name,$size)
{
$image->setName($name);
$image->setSize($size);
$this->mapperImage->save($image);
}
Mapper - ImageMapper.php
public function save($image)
{
$this->managerEntity->persist($image);
$this->managerEntity->flush();
}
Consider adding rich comments and typehints to the arguments and return value of the functions.
Moreover
The form should not be created in your controller. Put that code in your ImageService too. And consider inject form into the service. (Make sure you define the form for the factory in the getFormElementConfig()! This is more advance stuff, if you do not test with phpunit, you might not bother creating form as a service, hovever it leads to a very organized codebase.)
var_dump($name, $size) has no place in your controller. (If this is for debug purposes, it is OK, but use rather something like XDebug with a compatible IDE - PHPStorm is far the best one.)
This line is not so easy to understand: $filepath = $this->_dir.$name; Maybe:
$filePath = _dir . $name;
Naming convention: look for camelCase.
I created a form with validation rules. Everything is fine, form is visible and works.
Problem is with validators. Only first validator works in addValidators([ ....])
My form class source code:
public function initialize()
{
$title = new Text('title');
$title->setLabel('Title of article');
$title->setFilters([
'striptags', 'trim'
]);
$title->addValidators([
new PresenceOf([
'message' => 'Title can not be empty'
]),
new StringLength([
'min' => 5,
'messageMinimum' => 'Title is too short. Should has more than 5 letters'
]),
new MYArticleAddCheckTitleValidator([
'message' => 'aaaaaaaaaaaaaaa'
])
]);
$this->add($title);
..........
Validator PresenceOf works fine. validation flash message is visible.
Validator StringLength does not work. It looks like form doesn't know about it
Validator MYArticleAddCheckTitleValidator (my own validator class) - the same as StringLength.
Phalcon version 2.0.4 on windows.
Any proposition, or suggestions ?
Thanks a lot.
Using Phalcon\Flash\Direct
The best way to get around this problem is to use flash messages, with the class Phalcon\Flash\Direct. You can find the documentation here.
This strategy is used by the phalcon vokuro project which I suggest you to look at.
The key of this solution is the message() function inside your form class.
Form class
<?php
namespace Your\App\Forms;
use Phalcon\Forms\Form;
use Phalcon\Forms\Element\Text;
use Phalcon\Validation\Message;
use Phalcon\Validation\Validator\PresenceOf;
use Phalcon\Validation\Validator\StringLength;
use Your\App\Validation\MYArticleAddCheckTitleValidator;
class YourForm extends Form {
public function initialize()
{
$title = new Text('title');
$title->setLabel('Title of article');
$title->setFilters([
'striptags', 'trim'
]);
$title->addValidators([
new PresenceOf([
'message' => 'Title can not be empty'
]),
new StringLength([
'min' => 5,
'messageMinimum' => 'Title is too short. Should has more than 5 letters'
]),
new MYArticleAddCheckTitleValidator([
'message' => 'aaaaaaaaaaaaaaa'
])
]);
$this->add($title);
}
/**
* Prints messages for a specific element. Call it in the view
*/
public function messages($name)
{
if ($this->hasMessagesFor($name)) {
foreach ($this->getMessagesFor($name) as $message) {
$this->flash->error($message);
}
}
}
}
Controller
<?php
namespace Your\App;
use Your\App\YourForm;
class YourController extends ControllerBase
{
public function indexAction()
{
$form = new YourForm();
$this->view->form = $form;
if($this->request->hasQuery('title')){
if ($form->isValid($this->request->getQuery()) != false) {
// Code when form is valid
}
}
}
}
View
If you follow the suggested schema should be located in /app/views/your/index.html
<form method="GET" action="">
<?= $form->label('title') ?>
<?= $form->render('title')?>
<?= $form->messages('title') //show messages here ?>
</form>
If you have more than one form, it is useful to register the flash service with the DI.
When you define your services (could be in the index.php in the root folder or services.php in the /app/config/ folder) you define your flash service:
<?php
use Phalcon\DI\FactoryDefault;
$di = new FactoryDefault();
// Register the flash service with custom CSS classes
$di->set('flash', function () {
$flash = new Phalcon\Flash\Direct(
array(
'error' => 'your-error-class',
'success' => 'your-success-class',
'notice' => 'your-notice-class',
'warning' => 'your-warning-class'
)
);
return $flash;
});
I have created a module in SocialEngine(*which is built on Zend framework v1.9) that contains an admin form with a few options.
The problem I have with it is that it seems to no get the values of the fields from database after I refresh the page and it shows me the default values.
It shows the correct values immediately after I save(*but I am not sure if the page is refreshed after saving), but not after I refresh.
controller /application/modules/Mymodule/controllers/AdminSomesettingsController.php :
class Mymodule_AdminSomesettingsController extends Core_Controller_Action_Admin
{
public function indexAction()
{
$this->view->form = $form = new Mymodule_Form_Admin_Someform();
$settings = Engine_Api::_()->getApi('settings', 'core');
if(!$form->isValid($settings->mymodule))
{ return $form->populate($settings->mymodule); }
if( !$this->getRequest()->isPost() ) { return; }
if( !$form->isValid($this->getRequest()->getPost()) ) { return; }
$db = Engine_Api::_()->getDbTable('settings','core')->getAdapter();
$db->beginTransaction();
try {
$values = $form->getValues();
$settings->mymodule = $values;
$db->commit();
} catch( Exception $e ) {
$db->rollback();
throw $e;
}
$form->saveValues();
$form->addNotice('Your changes have been saved.');
}
}
form /application/modules/Mymodule/Form/Admin/Someform.php :
class Mymodule_Form_Admin_Someform extends Engine_Form
{
public function init()
{
$this
->setTitle('My Settings')
->setDescription('Settings');
$this->addElement('Radio', 'some_setting', array(
'label' => 'Some Setting',
'description' => '',
'multiOptions' => array(
0 => 'Option One',
1 => 'Option Two',
2 => 'Option Three',
),
'value' => 1,
'escape' => false,
));
// Add submit button
$this->addElement('Button', 'submit', array(
'label' => 'Save Changes',
'type' => 'submit',
'ignore' => true
));
}
public function saveValues()
{
}
}
I have checked with other plugins and it seems to me that $form->populate($settings->mymodule); repopulates the form after refresh, but it does not work for me.
Any idea how I could make it show the values from the database(*when these values exist) instead of the default values?
I myself am new to socialengine and zend.My understanding of socialengine says, make a function saveValues() inside ur form class, then call it from controller action as $form->saveValues(),passing parameter as needed.This is the convention that socialengine seems to follow, and inside the saveValues() of form class,u can save valus as needed.Ur form shud be populated only if validation fails
(!$form->isValid($formData ))
{ return $form->populate($formData); }
Instead of default adapter,U should try this-
$db =Engine_Api::_()->getDbTable('settings','core')->getAdapter(),
$db->beginTransaction();
If u want to set the value of a particular field try - $form->populate(array('formField'=>'urValue')); in ur case maybe -
$val=$settings->mymodule,
$form->populate('formField'=>$val);
You can add the code in controller $form->some_setting->setValue('1');
Got The Answer
To upload multiple file in to the database for registration
have tried so many ways to make multiple file upload workable using CMultiFileUpload widget. Already, I have checked and followed below links-
http://www.yiiframework.com/forum/index.php/topic/47665-multiple-file-upload/
Yii multiple file upload
BUT still no luck!!
Error: storing the data but the files are not getting uploaded
please help
Here is my code:
In Form
<?php $this->widget('CMultiFileUpload',
array(
'model'=>$model,
'attribute' => 'documents',
'accept'=>'jpg|gif|png|doc|docx|pdf',
'denied'=>'Only doc,docx,pdf and txt are allowed',
'max'=>4,
'remove'=>'[x]',
'duplicate'=>'Already Selected',
)
);?>
Controller Code
public function actionRegistration()
{
$model=new PatientRegistration;
$this->performAjaxValidation($model);
if(isset($_POST['PatientRegistration']))
{
$model->attributes=$_POST['PatientRegistration'];
if($model->validate())
{
if(isset($_POST['PatientRegistration']))
{
if($filez=$this->uploadMultifile($model,'documents','/Images/'))
{
$model->documents=implode(",", $filez);
}
$model->attributes=$_POST['PatientRegistration'];
if($model->save())
{
// $this->render('registration',array('model'=>$model));
$this->redirect(array('/patientregistration/patientview','id'=>$model->register_id));
}
}
}
}
$this->render('registration',array('model'=>$model));
}
public function uploadMultifile($model,$attr,$path)
{
/*
* path when uploads folder is on site root.
* $path='/uploads/doc/'
*/
if($sfile=CUploadedFile::getInstances($model, $attr)){
foreach ($sfile as $i=>$file){
// $formatName=time().$i.'.'.$file->getExtensionName();
$fileName = "{$sfile[$i]}";
$formatName=time().$i.'_'.$fileName;
$file->saveAs(Yii::app()->basePath.$path.$formatName);
$ffile[$i]=$formatName;
}
return ($ffile);
}
}
Add in CActiveForm widget
'htmlOptions' => array(
'enctype' => 'multipart/form-data',
),
Hence u can use this code to upload multiple files in yiiframework
Here is the simplest Code for Multiple File Upload in Yii Framework
code
In Controller
public function actionCreate()
{
$model = new Upload;
echo Yii::app()->basePath.'/Images/';
if(isset($_POST['Upload']))
{
if($filez=$this->uploadMultifile($model,'Document','/Images/'))
{
$model->Document=implode(",", $filez);
}
$model->attributes=$_POST['Upload'];
if ($model->save())
{
$this->redirect(array('view', 'id' => $model->idUpload));
}
}
$this->render('create', array(
'model' => $model,
));
}
//Function for uploading and saving Multiple files
public function uploadMultifile ($model,$attr,$path)
{
/*
* path when uploads folder is on site root.
* $path='/uploads/doc/'
*/
if($sfile=CUploadedFile::getInstances($model, $attr)){
foreach ($sfile as $i=>$file){
// $formatName=time().$i.'.'.$file->getExtensionName();
$fileName = "{$sfile[$i]}";
$formatName=time().$i.'_'.$fileName;
$file->saveAs(Yii::app()->basePath.$path.$formatName);
$ffile[$i]=$formatName;
}
return ($ffile);
}
}
In Form
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'upload-form',
// Please note: When you enable ajax validation, make sure the corresponding
// controller action is handling ajax validation correctly.
// There is a call to performAjaxValidation() commented in generated controller code.
// See class documentation of CActiveForm for details on this.
'enableAjaxValidation'=>false,
'htmlOptions' => array(
'enctype' => 'multipart/form-data',
),
)); ?>
<?php $this->widget('CMultiFileUpload',
array(
'model'=>$model,
'attribute' => 'Document',
'accept'=>'jpg|gif|png|doc|docx|pdf',
'denied'=>'Only doc,docx,pdf and txt are allowed',
'max'=>4,
'remove'=>'[x]',
'duplicate'=>'Already Selected',
)
);?>
That was all up is for multiple upload - that's nice, but as for multiple select you can try this yii extension
I hope that this link will help someone, because I was struggling with multiple select files for multiple upload then. Spent lot of time in Google search. Cheers
First my code:
class ProfileController extends Zend_Controller_Action {
private function getUploadAvatarForm()
{
$form = new Zend_Form;
$form->setAttrib('enctype', 'multipart/form-data');
$form->setAction($this->view->baseUrl('/profile/upload-avatar'))
->setName('uploadAvatarForm')
->setMethod('POST');
$element = new Zend_Form_Element_File('avatar');
$element->setLabel('Upload an image:')
->addFilter('Rename',
array('target' => '/path/toimages/directory/' . $this->userId . '.png',
'overwrite' => true)
);
$element->addValidator('Count', false, 1);
$element->addValidator('Size', false, 102400);
$element->addValidator('Extension', false, 'png');
$form->addElement($element, 'avatar')
->addElement('submit', 'submit_upload', array('label' => 'upload'));
return $form;
}
public function uploadAvatarAction()
{
$form = $this->getUploadAvatarForm();
$this->view->form = $form;
if (!$this->getRequest()->isPost() || !$form->isValid($_POST)) {
return;
}
if (!$form->avatar->receive()) {
... error...
}
... ok ...
}
}
The question is: part of buissiness logic is placed into Rename filter. In my vision it worth it, but may be I'm wrong.
I'm trying to test it:
public function testUploadFile()
{
$this->_doLogin('user', 'password');
$this->getRequest()
->setMethod('POST'));
$this->mockFileUpload();
$this->dispatch('profile/upload-avatar');
var_dump($this->getResponse()->getBody());
}
private function mockFileUpload()
{
$_FILES = array(
'avatar' => array(
'name' => 'test.png',
'type' => 'image/png',
'tmp_name' => '/tmp/test.png',
'error' => 0,
'size' => 10127));
}
but got:
The file 'avatar' was illegal uploaded, possible attack
Could you please suggest me how to test this situation?
(With filesystem everything will be ok - I'm going to use vfsStream for that, so the problem is only to emulate post upload)
In your test class, set your form to use an extended class of Zend_File_Transfer_Adapter_Http and override the isValid() method. You will obviously need to change the scope of your form function to public in your ProfileController. This is to be used with PHPUnit. I am not sure how to integrate it with Zend_Test_PHPUnit_ControllerTestCase just yet, but I will need to figure it out at some point and will update.
$class = new ProfileController();
$form = $class->getUploadAvatarForm();
$form->getElement('avatar')->setTransferAdapter(new MockAdapter());
MockAdapter.php
class MockAdapter extends Zend_File_Transfer_Adapter_Http
{
public function isValid($files = null)
{
return true;
}
}
I had a similar problem.
After some code reading and experimenting I discovered that my problem was caused by calling the isValid function of my form twice (caused by a minor code glitch).
Not exactly sure how but the double isValid was causing my tmp file (the uploaded file) to be deleted before the second isValid function was run, this made line 183 of Zend_Validate_File_Upload think that it wasn't a proper file upload (because the second time it looked for it it was already deleted):
If you want to check if your temp file isn't there for some reason modify line 183 of Zend_Validate_File_Upload:
case 0:
var_dump(file_exists($content['tmp_name']));
if (!is_uploaded_file($content['tmp_name'])) {
$this->_throw($file, self::ATTACK);
}
break;
Perhaps your rename filter is moving or renaming the file?