I'm doing some simple content maintenance on a site built on CakePHP 1.2. I did not develop the site. I'm unable to set up a localhost instance of the site because the framework is ancient, and I'm a hack. Consequently, I'm unable to test before deployment. Not a best case scenario, but it is what it is.
The text content updates are complete. However, the client has requested that a .vcf file be linked to for download from a static .thtml file.
My first attempt to implement this saw plain text returned when the a href was clicked.
In consulting the 1.2 manual I see there's a Media Views function:
function download () {
$this->view = 'Media';
$params = array(
'id' => 'example.zip',
'name' => 'example',
'download' => true,
'extension' => 'zip',
'path' => APP . 'files' . DS
);
$this->set($params);
}
which I have mod'd thus:
function download () {
$this->view = 'Media';
$params = array(
'id' => 'emp-name.vcf',
'name' => 'emp-name',
'download' => true,
'extension' => '.vcf',
'path' => APP . '/webroot/files' . DS
);
$this->set($params);
}
Can someone confirm that I'm heading in the right direction with this by adding this function to /app/controllers/pages_controller.php
As I say, I'm unable to test before deployment, and am concerned about breakage. Yes, I'm making .baks to fall back on.
tia
update:
Pushed /app/controller/pages_controller.php live.
Nothing broke, but the .vcf still displays as text when the link is clicked.
Maybe this controller isn't affecting the page: /app/views/pages/contact.thtml ?
Related
I'm trying to create a XML import module that will convert given file to CSV format and then use that CSV to import categories and products.
I have a working configuration page made with getContent() it basically calls a method that generates this form via $helper->generateForm(). $helper is a HelperForm() object.
protected function getConfigForm()
{
return array(
'form' => array(
'legend' => array(
'title' => $this->l('Settings'),
'icon' => 'icon-cogs',
),
'input' => array(
array(
'type' => 'file',
'label' => $this->l('XML file'),
'name' => 'XMLIMPORT_XML_FILE',
'desc' => $this->l('Select file you wish to import.'),
'required' => true
),
array(
'col' => 3,
'type' => 'text',
'prefix' => '<i class="icon icon-envelope"></i>',
'desc' => $this->l('Enter a valid email address'),
'name' => 'XMLIMPORT_LINES',
'label' => $this->l('Records per file'),
),
),
'submit' => array(
'title' => $this->l('Save'),
),
),
);
}
I need to get this data to my XML converter. How do I upload a file (around 10-20MB) to Prestashop to be then able to do other stuff with it? How to save it permanently on the server?
I tried doing this:
return array(
'XMLIMPORT_XML_FILE' => Configuration::get('XMLIMPORT_XML_FILE', null),
'XMLIMPORT_LINES' => Configuration::get('XMLIMPORT_LINES', 1000)
);
And after that this:
$form_values = $this->getConfigFormValues(); // returned array from above
foreach (array_keys($form_values) as $key)
Configuration::updateValue($key, Tools::getValue($key));
And later using my own class for XML conversion like this, hoping that it will give me file handle.
$xml_converter = new XMLToCSVConverter(Configuration::get('XMLIMPORT_XML_FILE'), 'output', 'example_products.php');
Apparently it didn't as nothing happens. The class itself is working fine outside of Prestashop module. The constructor is __construct($xml_file, $csv_filename, $template_file).
I need to pass the file I upload to that constructor. I've been struggling for days now.
#edit: I can see the contents of the file inside the HTTP call when submit is clicked. But how do I pass that file to my class?
As far as I remember 'type' => 'file', doesn't actually save any values in the database. This type is only meant to output a file field in your form.
After submitting, you should then do you custom processing with $_FILES['XMLIMPORT_XML_FILE'] : move to upload/ or whereever you want.
'XMLIMPORT_XML_FILE' => Configuration::get('XMLIMPORT_XML_FILE', null), won't return you anything. After uploading you my wish to save the uploaded file path here, but it won't show up next time in the form unless you build the output yourself.
Module configratuon is meant to save text config values. Handling files is trickier and you have to do them yourself each time.
EDIT:
To intercept the saving process, look up the submit button name and make an if statement:
public function getContent() {
if(Tools::isSubmit('submitButtonName')) {
error_log(print_r($_FILES, 1));
}
}
There's probably a function postProcess which does the same (it looks like you copied the methods from a default module).
prestashop handles the image upload with ImageManager class, this class contains more methods which are useful for handling image upload, resize etc.. so its better refer the default homeslider module for the image upload using a module. This module is handling the image upload process in postProcess method with the help of ImageManager class, this class methods will do the all the processes related to upload.
I'm using cakephp-upload plugin of jose gonzalez to upload images to our app. By default, they're being saved in a directory like this: webroot/files/user/photo/{user_id} which is fine, except for when we want to display such images using $this->Html->image() which searches for images in the webroot/img directory.
I have already tried to display the images with
echo $this->Html->image('../files/user/photo/' .
$user['User']['photo_dir'] . '/' .
$user['User']['photo']);
which works but I was wondering if there's some way to tell this plugin to save into the img directory? The documentation doesn't mention any of that.
And also, is there any way to tell the $this->Form->input('User.photo', array('type' => 'file')); to accept only image files?
as you can see in this file, path is set like:
public $defaults = array(
'rootDir' => null,
'pathMethod' => 'primaryKey',
'path' => '{ROOT}webroot{DS}files{DS}{model}{DS}{field}{DS}',
...
you could change it to make:
'path' => '{ROOT}webroot{DS}img{DS}'
and for your second question, you could use accept attribute, like:
$this->Form->input('User.photo',
array(
'type' => 'file',
'options' => array('accept' => 'image/*')
)
);
I want to open up pdfs in browser with cakephp. I am saving the files within webroot/files folder. I know how to use media which is direct downloads. but how do I open pdfs in browser directly ?
As per the MediaView book page, simply set autoRender to false and set a view variable named download to false in your controller. Also make sure to specify the mimeType as most browsers will force downloads for unknown mime types.
Example:
function download () {
$this->view = 'Media';
$this->autoRender = false; // Disable auto-render.
$params = array(
'download' => false, // Don't force download.
'id' => 'example.docx',
'name' => 'example',
'extension' => 'docx',
'mimeType' => array('docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'), // extends internal list of mimeTypes
'path' => APP . 'files' . DS
);
$this->set($params);
}
I'm making a custom "video" field that is supposed to accept several files (for different video formats) and a caption. So far the schema is fine, but I can't get it to upload and store the actual files.
My code in hook_field_widget_form looks like this (only pasting relevant bits):
$element['mp4'] = array(
'#type' => 'file',
'#title' => 'MP4 file',
'#delta' => $delta,
);
$element['ogg'] = ... /* similar to the mp4 one */
$element['caption'] = array(
'#type' => 'textfield',
'#title' => 'Caption',
'#delta' => $delta,
);
Also, in my .install file:
function customvideofield_field_schema($field) {
return array(
'columns' => array(
'mp4' => array(
'type' => 'int',
'unsigned' => TRUE,
'not null' => TRUE,
'default' => 0,
),
'ogg' => ... /* similar to mp4 */
'caption' => array(
'type' => 'varchar',
'length' => 255,
),
)
);
}
And the error I'm getting is when I try to store data. I get the form ok, and the database looks fine (the fields Drupal generates at least), but when it tries to do an INSERT, it fails because the value it tries to get into those integer fields is an empty string.
From what I understand, they have to be integers, right? (fids?) But I'm guessing the files are not being uploaded, even though I do get the right interface for uploading files.
Drupal shows you the INSERT query it tries to do, which is too long to post here, but I can see there that the value for the caption field (which is just a text field), is fine in the query, so it's only a problem with the file fields.
You probably want to use the managed_file field type instead, it handles uploading the file and registering it in the managed_files table for you. Then you would just add a submit function to your widget form and put the following code (from the FAPI page linked to above):
// Load the file via file.fid.
$file = file_load($form_state['values']['mp4']);
// Change status to permanent.
$file->status = FILE_STATUS_PERMANENT;
// Save.
file_save($file);
// Record that the module (in this example, user module) is using the file.
file_usage_add($file, 'customvideofield', 'customvideofield', $file->fid);
Hope that helps
EDIT
The core file module handles the actual submission for this using hook_field_presave(), my best guess is that this code would work:
function customvideofield_field_presave($entity_type, $entity, $field, $instance, $langcode, &$items) {
// Make sure that each file which will be saved with this object has a
// permanent status, so that it will not be removed when temporary files are
// cleaned up.
foreach ($items as $item) {
$file = file_load($item['mp4']);
if (!$file->status) {
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
}
}
}
That assumes the file ID column for your field is the one called mp4.
Remember to clear Drupal's caches when you implement the new hook or it won't be registered.
I haven't tried file uploading in my Drupal modules yet, but can you check does your form tag have the attribute enctype
="multipart/form-data"?
I would expect Drupal ought to include this automatically, but without it the file fields won't work, which seems to be what you're experiencing.
James
I want to download 4 different files through 4 different links. I am using the Media view to download the files, but I have to hardcode the file name in the download functions in the controller:
function download () {
$this->view = 'Media';
$params = array(
'id' => 'example.zip',
'name' => 'example',
'download' => true,
'extension' => 'zip',
'path' => APP . 'files' . DS
);
$this->set($params);
}
This works fine for one file. Now, for links number 2,3,4, do I need to create 3 different actions and give different file names in them, or is there a way in which I can use download() to only download the respective file depending on which link has been clicked?
That's what variables are for. Generic example:
function download($fileId) {
$file = // find the file you want to serve based on $fileId
$pathInfo = pathinfo($file['path']);
$this->view = 'Media';
$params = array(
'id' => $file['name'],
'name' => $pathInfo['filename'],
'extension' => $pathInfo['extension'],
'download' => true,
'path' => APP . 'files' . DS
);
$this->set($params);
}
In CakePhp 2.x you will get error The view for YourController::download() was not found.
Use viewClass field in CakePHP 2.x:
$this->viewClass = 'Media';
See Media Views — CakePHP Cookbook v2.x documentation
UPD: Media Views are deprecated since CakePHP 2.3, and CakeResponse::file() should be used:
$this->response->file($file['path'], array('download' => true, 'name' => 'foo'));
return $this->response;