Now I'm a bit more into this ZF3 stuff. I could (with some help) implement nearly everything I wanted. To dive in the, for me new version, I developed a test project.
Some questions are still unanswered and I didn't find usable explanations.
My new issue is InputFilterAwareInterface. I tried the examples for strings from the tutorial, so far everything ok. But like always for the easy topics you find everything, if you go further it ends abruptly.
I need an Inputfilter for xls and xlsx files. I googled of course, read tutorials, searched in the zend tutorial, because I had the idea there must somewhere exist some complete reference, but I couldn't find any.
So I tried this one:
$inputFilter->add([
'type' => 'Zend\InputFilter\FileInput',
'name' => 'DCL_Path',
'required' => true,
'validators' => [
['name' => 'FileUploadFile'],
[
'name' => 'FileMimeType',
'options' => [
'mimeType' => ['text/xls', 'text/xlsx']
]
],
[
'name' => 'Filesize',
'options' => [
'max' => 4096
]
],
],
// 'filters' => [
// [
// 'name' => 'FileRenameUpload',
// 'options' => [
// 'target'=>'./data/upload',
// 'useUploadName'=>true,
// 'useUploadExtension'=>true,
// 'overwrite'=>true,
// 'randomize'=>false
// ]
// ]
// ],
]);
As you an see I'm still fighting the validator part. What would be the right syntax to validate xls and xlsx files with a maximum size of let's say 4 MB?
And after that, what about the filterarea, I did the following in my controller action just because I'm used to
if ($form->isValid()) {
$data = $form->getData();
// Upload path
$location = "public/files/";
// A bit validation of uploaded file
$allowedExtension = array('xls', 'xlsx');
$extension = explode('.', $data['DCL_Path']['name']);
$extension = end($extension);
//$import['DCL_Path']=$data['DCL_Path']['name'];
//$fileName = time() . '.' . $extension;
$fileName = $data['DCL_Path']['name'];
// Check if everything is OK!
//echo $fileName;
if (0 === $data['DCL_Path']['error'] && in_array($extension, $allowedExtension)) {
move_uploaded_file($data['DCL_Path']['tmp_name'], $location . $fileName);
} else {
echo 'Something went wrong!';
}
Is the move_uploaded_file($data['DCL_Path']['tmp_name'], $location . $fileName); obsolet with the filterstuff in the interface? And again how would be the syntax in this case?
And one of my biggest wish, does somebody know kind of a tutorial which explains plainly the different possibilities and keys of both options (validator and filter)? Sometimes I can't believe that you need so much time to find only the right keys.
EDIT 1: Show Form, filterstuff and changed controller
here is part my Form class:
<?php
namespace Import\Form;
use Zend\Form\Form;
class ImportForm extends Form
{
public function __construct($name = null)
{
// We will ignore the name provided to the constructor
parent::__construct('import');
$this->add([
'name' => 'DCLID',
'type' => 'hidden',
]);
$this->add([
'name' => 'UnitID',
'type' => 'text',
'options' => [
'label' => 'equipment',
],
]);
$this->add([
'name' => 'DCL_Path',
'type' => 'File',
//'required' => true,
'options' => [
'label' => 'path to file',
],
// 'name' => 'FileRenameUpload',
// 'filters' => [
// 'target'=>'./public/files',
// 'useUploadName'=>true,
// 'useUploadExtension'=>true,
// 'overwrite'=>true,
// 'randomize'=>false
// ],
// 'validators' => [ // Validators.
// // Put validator info here.
// ]
]);
here part of the class extended InputFilterAwareInterface
<?php
namespace Import\Model;
use DomainException;
use Zend\Filter\StringTrim;
use Zend\Filter\StripTags;
use Zend\Filter\ToInt;
use Zend\InputFilter\InputFilter;
use Zend\InputFilter\InputFilterAwareInterface;
use Zend\InputFilter\InputFilterInterface;
use Zend\Validator\StringLength;
class Import implements InputFilterAwareInterface
{
public $DCLID;
public $DCL_Path;
public $Unitname;
public $UnitID;
public $Importdate;
public $Importuser;
public $Importok;
public $DCL_Type;
public $Changed_per_User;
public $Description_Changes;
private $inputFilter;
public function exchangeArray(array $data)
{
$this->DCLID= !empty($data['DCLID']) ? $data['DCLID'] : null;
$this->UnitID= !empty($data['UnitID']) ? $data['UnitID'] : null;
$this->DCL_Path= !empty($data['DCL_Path']) ? $data['DCL_Path'] : null;
$this->Importdate= !empty($data['Importdate']) ? $data['Importdate'] : null;
$this->Importuser= !empty($data['Importuser']) ? $data['Importuser'] : null;
$this->Importok= !empty($data['Importok']) ? $data['Importok'] : null;
$this->DCL_Type= !empty($data['DCL_Type']) ? $data['DCL_Type'] : null;
$this->Changed_per_User= !empty($data['Changed_per_User']) ? $data['Changed_per_User'] : null;
$this->Description_Changes= !empty($data['Description_Changes']) ? $data['Description_Changes'] : null;
}
public function getArrayCopy()
{
// echo var_dump(get_object_vars($this)
// );
return get_object_vars($this);
}
public function setInputFilter(InputFilterInterface $inputFilter)
{
throw new DomainException(sprintf(
'%s does not allow injection of an alternate input filter',
__CLASS__
));
}
public function getInputFilter()
{
if ($this->inputFilter) {
return $this->inputFilter;
}
$inputFilter = new InputFilter();
// $inputFilter->add([
// 'name' => 'DCLID',
// 'required' => false,
// 'filters' => [
// ['name' => ToInt::class],
// ],
// ]);
// Validator für das Upload Element
$inputFilter->add([
'type' => 'Zend\InputFilter\FileInput',
'name' => 'DCL_Path', // Element's name.
'required' => true, // Whether the field is required.
'filters' => [ // Filters.
[
'name' => \Zend\Filter\File\RenameUpload::class,
'options' => [
'use_upload_extension' => true,
'randomize' => false,
'overwrite' => true,
'target' => 'public/files',
],
],
],
'validators' => [ // Validators.
[
'name' => \Zend\Validator\File\Extension::class,
'options' => [
'extension' => 'xls, xlsx',
'message' => 'File extension not match',
],
],
[
'name' => \Zend\Validator\File\MimeType::class,
'options' => [
'mimeType' => 'text/xls', 'text/xlsx',
'message' => 'File type not match',
],
],
[
'name' => \Zend\Validator\File\Size::class,
'options' => [
'min' => '1kB', // minimum of 1kB
'max' => '4MB',
'message' => 'File too large',
],
],
]
]);
and my part of my controlleraction, I think inhere might be the problem, something is probably not logic:
$form = new ImportForm();
$form->get('submit')->setValue('Add'); //Änderung des LAbels des Submit Buttons, um das Form wiederverwenden zu können
//echo "hier";
$request = $this->getRequest();
if (! $request->isPost()) { //wurden Daten über POST geschickt?
return ['form' => $form]; //Keine Daten, nur Form anzeigen, nicht verarbeiten
}
else {
//Es wurden Daten gesendet
//echo "Daten";
$import = new Import(); //Neue Instanz von Import
$form->setInputFilter($import->getInputFilter()); //Filter an Form binden
$form->setData($request->getPost()); //Daten abholen
//echo $form->isValid();
if (! $form->isValid()) {
return ['form' => $form]; //Wenn die Daten nicht valide sind
}
else{ //aus Tableadapter
$import->exchangeArray($form->getData());
$data = array_merge_recursive(
$this->getRequest()->getPost()->toArray(),
$this->getRequest()->getFiles()->toArray()
);
$form->setData($data);
if ($form->isValid()) {
$data = $form->getData();
// Upload path
// $location = "public/files/";
// $allowedExtension = array('xls', 'xlsx');
// $extension = explode('.', $data['DCL_Path']['name']);
// $extension = end($extension);
$fileName = $data['DCL_Path']['name'];
// // Check if everything is OK!
// //echo $fileName;
// if (0 === $data['DCL_Path']['error'] && in_array($extension, $allowedExtension)) {
// move_uploaded_file($data['DCL_Path']['tmp_name'], $location . $fileName);
// } else {
// echo 'Something went wrong!';
// }
//-----------------------------------------------------------------
// t_dcl befüllen
//-----------------------------------------------------------------
//$namen = explode(",", $import ); //Konvertierung des Strings in ein Array
//echo "<pre>"; var_dump($namen); echo "</pre>"; //Formartierte Ausgabe des Arrays
$this->table->saveImport($import);
EDIT2: Post part of controlleraction to discuss order of some statements:
controlleraction
$form = new ImportForm();
$form->get('submit')->setValue('Add');
$request = $this->getRequest();
if (! $request->isPost()) {
return ['form' => $form];
}
else {
$import = new Import(); //Neue Instanz von Import
$form->setInputFilter($import->getInputFilter());
$form->setData($request->getPost());
$data = array_merge_recursive(
$this->getRequest()->getPost()->toArray(),
$this->getRequest()->getFiles()->toArray()
);
$form->setData($data);
if (! $form->isValid()) {
return ['form' => $form];
}
else{
$import->exchangeArray($form->getData());
$data = $form->getData();
$fileName = $data['DCL_Path']['name'];
Is the position of $form->setInputFilter($import->getInputFilter()); correct? Or when do I have to bind the Inputfilter to form?
There is a small issue left: I now have a message:
File type not match
I tried to upload a .xlsx file
Please try this for InputFilter
$inputFilter->add([
'type' => 'Zend\InputFilter\FileInput',
'name' => 'DCL_Path', // Element's name.
'required' => true, // Whether the field is required.
'filters' => [ // Filters.
[
'name' => \Zend\Filter\File\RenameUpload::class,
'options' => [
'use_upload_extension' => true,
'randomize' => false,
'overwrite' => true,
'target' => 'public/files',
],
],
],
'validators' => [ // Validators.
[
'name' => \Zend\Validator\File\Extension::class,
'options' => [
'extension' => 'xls, xlsx',
'message' => 'File extension not match',
],
],
[
'name' => \Zend\Validator\File\MimeType::class,
'options' => [
'mimeType' => 'text/xls', 'text/xlsx',
'message' => 'File type not match',
],
],
[
'name' => \Zend\Validator\File\Size::class,
'options' => [
'max' => '4MB',
'message' => 'File too large',
],
],
]
]);
And here for controller
if($this->getRequest()->isPost()) {
// merge post and files
$request = $this->getRequest();
$data = array_merge_recursive(
$request->getPost()->toArray(),
$request->getFiles()->toArray()
);
// passing data
$form->setData($data);
// execute validator
if($form->isValid()) {
// execute file filters.
$data = $form->getData();
}
}
By using \Zend\Validator\File\Extension, \Zend\Validator\File\MimeType and \Zend\Validator\File\FileSize you don't need to check manually in your contoller using this code.
if (0 === $data['DCL_Path']['error'] && in_array($extension, $allowedExtension)) {}
Because validation will be executed when we call $form->isValid().
And by using \Zend\Filter\File\RenameUpload, you don't need to use move_uploaded_file() anymore. Because this filter will move the uploaded file to destination foder we defined in 'target' => 'public/files' option.
Filtering is executed when we call $form->getData();
And about explanation for Validator and Filter, I suggest you to create another post. By using a separate question, it will be easy to search in search engine and will help another to find it.
Related
I am failing to locate where I am missing something. My application is uploading some files into the server. However, when I retrieve the files (images), all the links are broken and I am failing to pick up where the error is.
index() method to send the services to the view:
public function index()
{
$services = Service::all();
foreach($services as $service) {
$service->feature_image = Storage::url($service->feature_image);
}
return view('services.index')->with([
'services' => $services,
]);
}
store method:
public function store(Request $request)
{
$validate = Validator::make($request->all(), [
'title' => 'required|string',
'feature_image' => 'required|file|mimes:png,jpg,jpeg',
'description' => 'required|string|min:30|max:150',
'merchant_id' => 'required|string',
]);
if( $validate->fails() ){
return response($validate->errors(), 400);
}
//image storing before
try {
$image = $request->feature_image;
$extension = $image->extension();
if (! in_array($extension, ['jpg', 'jpeg', 'png'])) {
throw new Exception('File format not supported');
}
$imageName = time().'_'.rand(1000, 9999).'.'.$extension;
$imageName = $request->file('feature_image')->storeAs(
'feature_images',
$imageName,
'local'
);
$service = new Service();
$service->name = $request->title;
$service->feature_image = $imageName;
$service->short_description = $request->description;
$service->merchant_id = $request->merchant_id;
$service->save();
} catch (Exception $e) {
return response()->with('error', $e->getMessage());
}
$services = Service::where('merchant_id', '=', $request->merchant_id )
->get();
return response()->json([
'services' => $services,
], 200);
}
View that's not displaying the images:
<td>
<img src="{{$service->feature_image}}" style="max-width:300px !important; max-height:100px !important; border-radius:none !important;" />
</td>
filesystems configuration:
'local' => [
'driver' => 'local',
'root' => storage_path('app/private'),
'visibility' => 'private',
],
'permissions' => [
'file' => [
'public' => 0644,
'private' => 0600,
],
'dir' => [
'public' => 0755,
'private' => 0700,
],
],
Images are uploading perfectly but just won't display
But, nothing showing on the view
In the database, image is stored as feature_images/1675377529_1402.png and on the frontend, application is trying to load https://my_domain/storage/feature_images/1675377529_1402.png
UPDATE
When I change the disk am writing to public, the images show
$imageName = $request->file('feature_image')
->storeAs(
'feature_images',
$imageName,
'public'
);
I decided to put the validations and messages inside the HunterModel.php model. My createHunter() method inside the HunterController.php file should insert a record.
The following snippet shows the problem i'm having: Apparently $this->$data->listError();, doesn't reveal the message (or messages) i defined in $validationMessages.
HunterModel.php
// Validation
protected $validationRules = [
'name_hunter' => 'required|max_length[30]',
'age_hunter' => 'required|integer',
'height_hunter' => 'required|decimal',
'weight_hunter' => 'required|decimal',
'type_hunter' => 'required|max_length[30]',
'type_nen' => 'required|max_length[30]',
'type_blood' => 'required|max_length[3]'
];
protected $validationMessages = [
'name_hunter' => [
'required' => 'Hunter name cannot be empty.',
'max_length' => 'The hunter name must have a maximum of 30 characters.'
],
'age_hunter' => [
'required' => 'Hunter age cannot be empty.',
'integer' => 'The hunter's age must be an integer.'
],
'height_hunter' => [
'required' => 'Hunter height cannot be empty.',
'decimal' => 'The hunter height must be a decimal number.'
],
'weight_hunter' => [
'required' => 'Hunter weight cannot be empty.',
'decimal' => 'The hunter weight must be a decimal number.'
],
'type_hunter' => [
'required' => 'It is necessary to define the type of hunter.',
'max_length' => 'The hunter type must be a maximum of 30 characters.'
],
'type_nen' => [
'required' => 'It is necessary to define the nen of the hunter.',
'max_length' => 'The hunter's nen must have a maximum of 30 characters.'
],
'type_blood' => [
'required' => 'It is necessary to define the hunter's blood type.',
'max_length' => 'The hunter's blood type must be a maximum of 3 characters.'
]
];
HunterController.php
public function createHunter()
{
try {
$hunter = new HunterModel();
$data = [
'name_hunter' => $this->request->getPost('name_hunter'),
'age_hunter' => $this->request->getPost('age_hunter'),
'height_hunter' => $this->request->getPost('height_hunter'),
'weight_hunter' => $this->request->getPost('weight_hunter'),
'type_hunter' => $this->request->getPost('type_hunter'),
'type_nen' => $this->request->getPost('type_nen'),
'type_blood' => $this->request->getPost('type_blood')
];
if ($hunter->insert($data)){
return $this->response->redirect(site_url('/read_hunters'));
} else {
$this->$data->listError();
}
} catch (\Exception $e) {
exit($e->getMessage());
}
}
Create Validations.php in Libraries folder if it's does not exist.
Validations.php must be like:
<?php
namespace App\Libraries;
class Validations
{
public $hunter = [
'rules' => [
'name_hunter' => 'required|max_length[30]',
//other rules...
],
'error' => [
'name_hunter' => [
'required' => 'Hunter name cannot be empty.',
'max_length' => 'The hunter name must have a maximum of 30 characters.'
],
//other error messages....
]
];
}
HunterController.php must be like:
<?php
namespace App\Controllers;
use App\Libraries\Validations;
class HunterController extends BaseController
{
public function __construct()
{
$this->validator = new Validations();
}
public function createHunter()
{
$response = [];
$val = $this->validate(
$this->validator->hunter['rules'],
$this->validator->hunter['error']
);
if (!$val) {
$response = [
'success' => false,
'msg' => addslashes((preg_replace('/\s+/', ' ', $this->validation->listErrors())))
];
}else {
try {
$hunter = new HunterModel();
$data = [
'name_hunter' => $this->request->getPost('name_hunter'),
'age_hunter' => $this->request->getPost('age_hunter'),
'height_hunter' => $this->request->getPost('height_hunter'),
'weight_hunter' => $this->request->getPost('weight_hunter'),
'type_hunter' => $this->request->getPost('type_hunter'),
'type_nen' => $this->request->getPost('type_nen'),
'type_blood' => $this->request->getPost('type_blood')
];
if ($hunter->insert($data)){
return redirect()->to(site_url('/read_hunters'));
} else {
$response = [
'success' => false,
'msg' => //your custom error message
];
}
} catch (\Exception $e) {
exit($e->getMessage());
}
//if you are using ajax
return $this->response->setJSON($response);
}
}
I'm using the repeatable, from Laravel-Backpack I can save the data into the two tables. However, I can not load these data when trying to edit a sale. It does not load the data in the form that were saved through the Repeatable.
Example:
When viewing the example of the demo through the link.
https://demo.backpackforelaravel.com/admin/dummy/create
It converts the data from the fields from the REPEATABLE to JSON, and saves in the database in a field called Extra.
Saved format in the extra field in the database:
{
"simple": "[{\"text\":\"TesteTesteTesteTeste\",\"email\":\"admin#admin\",\"textarea\":\"teste\",\"number\":\"1\",\"float\":\"1\",\"number_with_prefix\":\"1\",\"number_with_suffix\":\"0\",\"text_with_both_prefix_and_suffix\":\"1\",\"password\":\"123\",\"radio\":\"1\",\"checkbox\":\"1\",\"hidden\":\"6318\"}]",
}
In my case I am saving the data in different tables without using JSON.
//My Model
class Sales extends Model
protected $casts = [
'id' => 'integer',
'user_id' => 'integer',
'date_purchase' => 'date',
'client_id' => 'integer',
];
public function getProductsAttribute()
{
$objects = ItensProducts::where('product_id', $this->id)->get();
$array = [];
if (!empty($objects)) {
foreach ($objects as $itens) {
$obj = new stdClass();
$obj->product_id = "" . $itens->product_id;
$obj->quantity = "" . $itens->quantity;
$categoryProduct = CategoryProduct::where('product_id', $itens->product_id)->get();
$arrayCategoryProduct = [];
foreach ($categoryProduct as $stItens) {
$arrayCategoryProduct[] = $stItens->name;
}
$obj->categories_product = $arrayCategoryProduct;
$array[] = $obj;
}
}
//Converts JSON to the example of the extra database field
$array_result = json_encode(\json_encode($array), JSON_HEX_QUOT | JSON_HEX_APOS);
$array_result = str_replace(['\u0022', '\u0027'], ["\\\"", "\\'"], $array_result);
return $array_result;
}
My form:
//SalesCruController.php
protected function setupCreateOperation()
{
CRUD::addField([ // repeatable
'name' => 'products',
'label' => 'Produtos(s)',
'type' => 'repeatable',
'fields' => [
[
'name' => 'product_id', 'type' => 'select2', 'label' => 'Produtos',
'attribute' => "name",
'model' => "App\Models\Product",
'entity' => 'products',
'placeholder' => "Selecione o Produto",
'wrapper' => [
'class' => 'form-group col-md-6'
],
],
[
'name' => 'category_id', 'type' => 'select2', 'label' => "Categoria",
'attribute' => "name",
'model' => "App\Models\CategoryProduct",
'entity' => 'categories',
'placeholder' => "Selecione uma Categoria",
],
[
'name' => 'quantity',
'label' => "Quantidade",
'type' => 'text',
],
],
// optional
'new_item_label' => 'Adicionar',
'init_rows' => 1,
'min_rows' => 1,
'max_rows' => 3,
],);
}
}
Method Store
public function store()
{
$item = $this->crud->create($this->crud->getRequest()->except(['save_action', '_token', '_method']));
$products = json_decode($this->crud->getRequest()->input('products'));
$this->validateRepeatableFields($categoryProduct);
if (is_array($products)) {
foreach ($products as $itens) {
$obj = new ItensProduct();
$obj->sale_id = $item->getKey();
$obj->product_id = $itens->product_id;
$obj->quantity = $itens->quantity;
$obj->save();
$categoryProduct = json_decode($itens->categories);
foreach ($categoryProduct as $cItens) {
$objCat = new CategoryProduct();
$objCat->product_id = $obj->getKey();
$objCat->name = $cItens;
$objCat->save();
}
}
} else {
\Alert::add('warning', '<b>Preencha os campos de pelo menos um produto.</b>')->flash();
return redirect('admin/sales/create');
}
\Alert::success(trans('backpack::crud.insert_success'))->flash();
return redirect('admin/sales');
}
function validateRepeatableFields($categoryProduct)
{
foreach ($categoryProduct as $group) {
Validator::make((array)$group, [
'sale_id' => 'required',
'product_id' => 'required',
'quantity' => 'required',
], [
"product_id.required" => "O campo Produto é obrigatório",
"quantity.required" => "O campo quantidade é obrigatório",
])->validate();
}
}
I was able to solve the problem of returning the fields to the Repeatable form.
I want to share the solution if someone needs it. The error occurred when I tried to put the data from the category_id field which is a vector in a json it has to return like this, as shown below.
{"product_id": "4", quantity: "3", "category_id": "[10, 4, 8, 8]"}
The vector would have to be inside a string, I was passing the fields but was not converting the whole vector to a string in the format that the repeatable expected. Then I conceded the IDs in a string and in the end I conceded with the cohets and used the substring to remove the last virgulation, as the code below shows.
In this way I was able to return the fields with the appropriate information that were saved in the database in the Repeatable form.
public function getProductsAttribute()
{
$objects = ItensProducts::where('product_id', $this->id)->get();
$response = [];
if (!empty($objects)) {
foreach ($objects as $itens) {
$categoryProduct = CategoryProduct::where('product_id', $itens->product_id)->get();
$itensCatProd = '';
foreach ($categoryProduct as $itensCatProd) {
$itensCatProd .= $itensCatProd->id . ',';
};
$response[] = [
'product_id' => $itens->product_id,
'category_id' => '[' . substr($itensCatProd, 0, -1) . ']',
'quantity' => $itens->quantity,
];
return json_encode($response);
}
}
}
I am attempting to create a custom image field within Magento CMS pages.
This is the steps I have taken,
Created an additional column with cms_page within the database called 'banner' - this is a varchar (255).
Amended "app/code/core/Mage/Adminhtml/controllers/Cms/PageController.php" with the uploader code (see at bottom).
Amended "app/code/core/Mage/Adminhtml/Block/Cms/Page/Edit/Tab/Content.php" to add the new field called 'banner' of which is a field type of 'image'.
Deleted everything within "var/cache/" and "var/session/"
It's just simply not uploading/saving the filename within the database. To try and diagnose what's going on I added print_r($_FILES) just below saveAction() and it returned an empty array.
Am I missing a crucial step?
Here is the relevant code,
app/code/core/Mage/Adminhtml/controllers/Cms/PageController.php -
public function saveAction()
{
if ($data = $this->getRequest()->getPost()) {
$data = $this->_filterPostData($data);
//init model and set data
$model = Mage::getModel('cms/page');
if(isset($data['banner']['delete']) && $data['banner']['delete']=='1'){
if(!empty($data['banner']['value'])){
$path = Mage::getBaseDir('media') . DS;
if(#unlink($path.$data['banner']['value'])){
$data['banner']='';
}
}
}
if(isset($_FILES['banner']['name']) && !empty($_FILES['banner']['name'])) {
try {
$uploader = new Varien_File_Uploader('banner');
$uploader->setAllowedExtensions(array('jpg','jpeg','gif','png')); // or pdf or anything
$uploader->setAllowRenameFiles(true);
// setAllowRenameFiles(true) -> move your file in a folder the magento way
// setAllowRenameFiles(false) -> move your file directly in the $path folder
$uploader->setFilesDispersion(true);
$path = Mage::getBaseDir('media') . DS;
//$uploader->saveresized($path, $_FILES['nfile']['name'],100,72);
//$_tmp_nfilethumb = $uploader->getUploadedFileName();
$uploader->save($path, $_FILES['banner']['name']);
$_tmp_nfile = $uploader->getUploadedFileName();
//$data['nfilethumb'] = $_tmp_nfilethumb;
$data['banner'] = $_tmp_nfile;
}catch(Exception $e) {
}
}elseif(isset($data['banner']['value']) && !empty($data['banner']['value'])){
$data['banner']=$data['banner']['value'];
}
if ($id = $this->getRequest()->getParam('page_id')) {
$model->load($id);
}
$model->setData($data);
Mage::dispatchEvent('cms_page_prepare_save', array('page' => $model, 'request' => $this->getRequest()));
//validating
if (!$this->_validatePostData($data)) {
$this->_redirect('*/*/edit', array('page_id' => $model->getId(), '_current' => true));
return;
}
// try to save it
try {
// save the data
$model->save();
// display success message
Mage::getSingleton('adminhtml/session')->addSuccess(
Mage::helper('cms')->__('The page has been saved.'));
// clear previously saved data from session
Mage::getSingleton('adminhtml/session')->setFormData(false);
// check if 'Save and Continue'
if ($this->getRequest()->getParam('back')) {
$this->_redirect('*/*/edit', array('page_id' => $model->getId(), '_current'=>true));
return;
}
// go to grid
$this->_redirect('*/*/');
return;
} catch (Mage_Core_Exception $e) {
$this->_getSession()->addError($e->getMessage());
}
catch (Exception $e) {
$this->_getSession()->addException($e,
Mage::helper('cms')->__('An error occurred while saving the page.'));
}
$this->_getSession()->setFormData($data);
$this->_redirect('*/*/edit', array('page_id' => $this->getRequest()->getParam('page_id')));
return;
}
$this->_redirect('*/*/');
}
app/code/core/Mage/Adminhtml/Block/Cms/Page/Edit/Tab/Content.php -
protected function _prepareForm()
{
$model = Mage::registry('cms_page');
/*
* Checking if user have permissions to save information
*/
if ($this->_isAllowedAction('save')) {
$isElementDisabled = false;
} else {
$isElementDisabled = true;
}
$form = new Varien_Data_Form();
$form->setHtmlIdPrefix('page_');
$fieldset = $form->addFieldset('content_fieldset', array('legend'=>Mage::helper('cms')->__('Content'),'class'=>'fieldset-wide'));
$wysiwygConfig = Mage::getSingleton('cms/wysiwyg_config')->getConfig(
array('tab_id' => $this->getTabId())
);
$fieldset->addField('content_heading', 'text', array(
'name' => 'content_heading',
'label' => Mage::helper('cms')->__('Content Heading'),
'title' => Mage::helper('cms')->__('Content Heading'),
'disabled' => false,
));
$content999Field = $fieldset->addField('banner', 'image', array(
'name' => 'banner',
'label' => Mage::helper('cms')->__('Banner'),
'title' => Mage::helper('cms')->__('Banner'),
));
$contentField = $fieldset->addField('content', 'editor', array(
'name' => 'content',
'label' => Mage::helper('cms')->__('Layout 1'),
'title' => Mage::helper('cms')->__('Layout 1'),
'style' => 'height:36em;',
//'required' => true,
'disabled' => $isElementDisabled,
'config' => $wysiwygConfig
));
$content2Field = $fieldset->addField('content2', 'editor', array(
'name' => 'content2',
'label' => Mage::helper('cms')->__('Layout 2'),
'title' => Mage::helper('cms')->__('Layout 2'),
'style' => 'height:36em;',
//'required' => true,
'disabled' => $isElementDisabled,
'config' => $wysiwygConfig
));
$content3Field = $fieldset->addField('content3', 'editor', array(
'name' => 'content3',
'label' => Mage::helper('cms')->__('Content'),
'title' => Mage::helper('cms')->__('Content'),
'style' => 'height:36em;',
//'required' => true,
'disabled' => $isElementDisabled,
'config' => $wysiwygConfig
));
// Setting custom renderer for content field to remove label column
//$renderer = $this->getLayout()->createBlock('adminhtml/widget_form_renderer_fieldset_element')
// ->setTemplate('cms/page/edit/form/renderer/content.phtml');
// $contentField->setRenderer($renderer);
$form->setValues($model->getData());
$this->setForm($form);
Mage::dispatchEvent('adminhtml_cms_page_edit_tab_content_prepare_form', array('form' => $form));
return parent::_prepareForm();
}
Try to add this line below $form->setValues($model->getData());:
$form->setEnctype(Zend_Form::ENCTYPE_MULTIPART);
I added,
'enctype' => 'multipart/form-data' within the Form.php and it fixed it.
class Mage_Adminhtml_Block_Cms_Page_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
{
protected function _prepareForm()
{
$form = new Varien_Data_Form(array('id' => 'edit_form', 'action' => $this->getData('action'), 'method' => 'post', 'enctype' => 'multipart/form-data'));
$form->setUseContainer(true);
$this->setForm($form);
return parent::_prepareForm();
}
}
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!