I'm developing a PHP application where I have a form in which the user should upload a text file and an other page works with this data. I'm also creating controller tests with CakePHP and PHPUnit. My question is, how can I make the test automatically upload a file for the tests of this action?
Thanks in advance.
update 1:
The question in more details: Basically I have a 'submit' action which has the form in its view which submits the parameters (and the uploaded file) to the 'curl' action. Here this curl action processes the uploaded text file and this is actually what I'd like to test. But to test this, I should have an uploaded file with its content, so a more specific question: how could I mock this uploaded file to 'submit' it to my curl controller?
Code snippet for the View:
...
echo '<fieldset><table>';
echo $this->Form->create('Job', array('type' => 'post','action' => 'curl', 'enctype' => 'multipart/form-data'));
echo $this->Form->input('user.name', array('type' => 'hidden', 'value' => $this->User->getCode1(),'name' => 'user.name'));
echo $this->Form->input('class', array('type' => 'hidden', 'value' => $this->Hadoop->getClass(), 'name' => 'class'));
...
update 2:
The test I've already written:
public function testCurl() {
$data = array(
'user_name' => ...,
'release' => ...,
'analysis_period_start' => ...,
'uploaded_file' => ???
);
$Jobs = $this->generate('Jobs', array('components' => array('Session')));
$Jobs->Session->expects($this->any())->method('setFlash');
$this->testAction('/jobs/curl', array('data' => $data, 'method' => 'post'));
}
So basically I'm trying to test my curl action with a POST method with the data provided in the $data variable. But I don't know how to mock/imitate an uploaded file into that array.
update 3:
The relevant cod snippet from my controller's given action:
public function curl() {
/* This action accepts only POST request */
if (!$this->isPOSTRequest())
return $this->redirect(array('controller' => 'jobs', 'action' => 'submit'));
/* Create a new entry in the database and get its ID */
$id = $this->createNewEntryInTheDatabase();
/* Inserts the new patterns into the DB and looks up the already existing
** patterns in the DB. Returns an array with the IDs of the submitted patterns */
$patternIds = $this->lookupPatternIDsAndInsertNewPatterns($_FILES['patterns']);
$curl = $this->initCURL();
...
$this->closeCURL($curl);
return $this->redirect(array('controller' => 'jobs', 'action' => 'submit'));
}
...
private function lookupPatternIDsAndInsertNewPatterns($patternsFile) {
$patternIDs = null;
/* One element for each row */
$patternsArray = $this->convertUploadedCSVFileIntoArray(
$patternsFile, $this->CSV->getDelimiter(),
$this->CSV->getEnclosure(), $this->CSV->getEscape());
...
return $patternIDs;
}
/* Returns the patterns from the CSV file in an array */
private function convertUploadedCSVFileIntoArray(
$patternsFile, $delimiter, $enclosure, $escape) {
$patternsArray = file($patternsFile['tmp_name']);
$patterns = null;
foreach ($patternsArray as $pattern)
$patterns[] = str_getcsv(
$pattern,
$delimiter,
$enclosure,
$escape);
return $patterns;
}
Related
I'v created a new module in Drupal 8, it is just a hello world example.
the code just like the following
class FirstController{
public function content(){
return array(
'#type' => 'markup',
'#markup' => t('G\'day.............'),
);
// <------I added the new node code here
}
}
and I added the following code to the content() function to create a node .
but I found that it can only create the node once, and after that no matter how many time I refresh the module page it won't be creating any more new node again.
use \Drupal\node\Entity\Node;
use \Drupal\file\Entity\File;
// Create file object from remote URL.
$data = file_get_contents('https://www.drupal.org/files/druplicon.small_.png');
$file = file_save_data($data, 'public://druplicon.png', FILE_EXISTS_REPLACE);
// Create node object with attached file.
$node = Node::create([
'type' => 'article',
'title' => 'Druplicon test',
'field_image' => [
'target_id' => $file->id(),
'alt' => 'Hello world',
'title' => 'Goodbye world'
],
]);
$node->save();
any thing I'm doing wrong here?
You forgot about caching :) Your output is just cached, and that's why your code is called only once (to be more precise, not once, but until cache is valid). Take a look here: Render API and here: Cacheability of render arrays.
To disable caching for current page request you may use the following code:
\Drupal::service('page_cache_kill_switch')->trigger();
So, your controller method may look like the following:
public function content() {
// Create file object from remote URL.
$data = file_get_contents('https://www.drupal.org/files/druplicon.small_.png');
/** #var FileInterface $file */
$file = file_save_data($data, 'public://druplicon.png', FILE_EXISTS_RENAME);
// Create node object with attached file.
$node = Node::create([
'type' => 'article',
'title' => 'Druplicon test',
'field_image' => [
'target_id' => $file->id(),
'alt' => 'Hello world',
'title' => 'Goodbye world'
],
]);
$node->save();
\Drupal::service('page_cache_kill_switch')->trigger();
return array(
'#markup' => 'Something ' . rand(),
);
}
I'm trying to perform validation with cake 2.3.8 on a file upload to make sure that only PDF's can be uploaded. I'm loosly basing this off of this tutorial.
My form is displaying the asterisk next to the input, and when I remove the validation from my model the asterisk goes away. I'm assuming this means it "sees" the input for validation, but I just can't figure out why even the custom validation isn't being triggered.
Here's the form
echo $this->Form->create('Upload', array('type' => 'file'));
echo $this->Form->input('file_upload', array('type' => 'file'));
echo $this->Form->input('file_title');
echo $this->Form->end(__('Upload File!', true));
Here's the code in my Upload model
public function checkUpload(){
echo "test"; //check to see if it reaches this...not displaying
return false; //the error message should be set just for testing, it's not displaying though
}
public $validate = array(
'file_upload' => array(
'extension' => array(
'rule' => array('extension', array('pdf')),
'message' => 'Only pdf files',
),
'upload-file' => array(
'rule' => array('checkUpload'),
'message' => 'Error uploading file'
)
)
);
Here is my answer (albeit for cakephp 1.3):
In your model add the following validation to your $validate variable.
$this->validate = array(...
// PDF File
'pdf_file' => array(
'extension' => array(
'rule' => array('extension', array('pdf')),
'message' => 'Only pdf files',
),
'upload-file' => array(
'rule' => array('uploadFile'), // Is a function below
'message' => 'Error uploading file'
)
)
); // End $validate
/**
* Used when validating a file upload in CakePHP
*
* #param Array $check Passed from $validate to this function containing our filename
* #return boolean True or False is passed or failed validation
*/
public function uploadFile($check)
{
// Shift the array to easily acces $_POST
$uploadData = array_shift($check);
// Basic checks
if ($uploadData['size'] == 0 || $uploadData['error'] !== 0)
{
return false;
}
// Upload folder and path
$uploadFolder = 'files'. DS .'charitylogos';
$fileName = time() . '.pdf';
$uploadPath = $uploadFolder . DS . $fileName;
// Make the dir if does not exist
if(!file_exists($uploadFolder)){ mkdir($uploadFolder); }
// Finally move from tmp to final location
if (move_uploaded_file($uploadData['tmp_name'], $uploadPath))
{
$this->set('logo', $fileName);
return true;
}
// Return false by default, should return true on success
return false;
}
You may have to display the error validation messages yourself, you can do this using:
<!-- The classes are for twitter bootstrap 3 - replace with your own -->
<?= $form->error('pdf_file', null, array('class' => 'text-danger help-block'));?>
if you try to debug sth in Cake, always use debug(sth) // sth could be variable could be string could be anything, cuz in Cake debug means
echo "<pre>";
print_r(sth);
echo "</pre>";`
it's already formatted very well.
then after that you have to put die() otherwise after echo sth it will load the view that's why you can't see it even there was an output.
How can I get the filename of the file uploaded in codeigniter. We get the values of the input fields as $this->input->post('name'), but how can i get the name of the file uploaded from the form??
public function create(){
//getting all the POST data in $data array
$data = array('title' => $this->input->post('title') ,
'content' => $this->input->post('content'),
'filename' => ?? HOW ??
);
}
1) make sure that you form is multipart. With helper its form_open_multipart()
2) use upload library for receiving the file
3) then with $this->upload->data() you get array with file info
Here is full how to and official documentation
public function create(){
//getting all the POST data in $data array.
$data = array('title' => $this->input->post('title') ,
'content' => $this->input->post('content'),
'filename' => $_FILES["file"]["name"]
);
}
I use sfWidgetFormInputFileEditable in my form for file handling purpose.
Here is the code:
/* File */
$this->widgetSchema['file_addr'] = new sfWidgetFormInputFileEditable(array(
'label' => 'File',
'file_src' => sfConfig::get('sf_root_dir').'...',
'is_image' => false,
'edit_mode' => !$this->getObject()->isNew(),
'delete_label' => 'Delete?',
'template' => '...',
'with_delete' => true
));
$this->validatorSchema['file_addr'] = new sfValidatorFile(array(
'required' => $this->getObject()->isNew(),
'path' => sfConfig::get('sf_root_dir') .'/files'
));
$this->validatorSchema['file_addr_delete'] = new deleteFileValidator(...);
/* File: END */
This way it stores generated file name in file_addr field. I want to access other file data like size, file name etc and store them in database too. How can I do that?
You can override the save() method.
public function save($con = null) {
$values = $this->getValues();
$fileAddr = $values['file_addr'];
// ... Do stuff with the values ...
return parent::save($con);
}
I didn't test it, but something like that should work.
Additional uploaded file data is available in form processValues method. So I override it like this:
public function processValues($values)
{
/* File data */
if ($values['file_addr'] instanceof sfValidatedFile)
{
$file = $values['file_addr'];
$this->getObject()->setFileSize($file->getSize());
$this->getObject()->setFileType($file->getType());
$this->getObject()->setFileHash(md5_file($file->getTempName()));
}
return parent::processValues($values);
}
I am using http://milesj.me/code/cakephp/uploader#configuration to upload images. I got it to work fine (in terms of uploading images) but I can't get it to save title/description in my db.
so I have Image.php model that has the following code
<?php
class Image extends AppModel {
var $name = 'Image';
public $actsAs = array('Uploader.Attachment', 'Uploader.FileValidation');
public $validate = array(
'title' => array( 'rule' => 'notEmpty')
);
}
In my view I have bunch of fields such as
echo $this->Form->input('title');
My ImagesController.php add function looks like this
function add($number_of_images = 1){
if (!empty($this->data)) {
var_export($this->data);
exit();
$count = 1;
foreach($this->data['Images'] as $entry){
$file_name = "file" . $count;
if ($data_s = $this->Uploader->upload($file_name)) {
$this->Image->saveAll($data_s);
}
$count++;
}
$this->Session->setFlash("Your image(s) has been saved");
$this->redirect(array('action'=>'index'));
}else{
// make sure 10 is max amount of images a user can upload
if($number_of_images <= 10 ){
$this->set('number_of_images', $number_of_images);
}else{
// set to default 1
$this->set('number_of_images', '1');
}
}
}
When I click save, the image gets uploaded but title/description doesnt get uploaded or validated. This is how my var_export($this->data) looks like
array ( 'selectImages' => '1', 'Images' => array ( 'title' => 'adsafdas', 'description' => 'asdfasd', 'tags' => '', 'file1' => array ( 'name' => '308462_926071922398_11704522_41424436_637322498_n.jpg', 'type' => 'image/jpeg', 'tmp_name' => '/tmp/php7tycbu', 'error' => 0, 'size' => 81638, ), ), )
How can I fix this?
According with the link, $this->Uploader->upload() returns only data of file uploaded. So, you need merge this array with the other fields of your form $this->data before saveAll.
However, if you need validate form data before upload the file, use $this->Image->validates($this->request->data).