TYPO3 extension Model conflict with f:form.upload - typo3-extensions

For an own extension, I want o use the viewhelper f:form.upload
to retrieve the upload parameters I have to define the property for this viewhelper as an array. These work fine to get the name, type, tmp_name, error, and size parameters.
In the Domain Model, I read the parameters and save the uploaded file and store the file name inside the database. That works fine! Here the part of the Domain Modell for the variable iFile:
/**
* iFile
*
* #var array
* #TYPO3\CMS\Extbase\Annotation\ORM\Cascade("remove")
*/
protected $iFile = [];
/**
* Returns the iFile
*
* #return string iFile
*/
public function getIFile()
{
$temp = [];
$temp['image_name'] = $this->iFile;
error_log("Get_iFile: " . var_export($temp, true), 0);
error_log("Get_iFile0: " . var_export($this, true), 0);
return $temp;
}
/**
* Sets the iFile
*
* #param string $iFile
* #return void
*/
public function setIFile($iFile)
{
if($iFile['tmp_name'] != ""){
$docRoot = $_SERVER['DOCUMENT_ROOT'].'\\' ;
if (!is_dir($docRoot)) {
mkdir($docRoot, 07777, true);
}
$date = new \DateTime();
$fName = 'fileadmin\\Radio\\crNews\\' . $date->format('Ymd') . $iFile['name'];
if(copy($iFile['tmp_name'], $docRoot . $fName) == true);
unlink($iFile['tmp_name']);
}
error_log("Set _FILES: " . var_export($iFile, true), 0);
$this->iFile = $fName;
}
But if I try to read it from the database, I don't get back the file name from the database! Only an empty array.
'iFile' =>
array (
),
The problem seems to be, due to the definition of iFile as an array.
How can I solve the problem?
Is there any possibility, to add a new variable to the Model as an array, but not to store it in the database?

So I found a workaround. I only defined iFile as an string to read and save the file name in the database and used the $_FILES post variables to retrieve the name and tmp_name of the $_FILES.
In Typo3, access the $_FILES parameters is not so easy. So I recommend to use phpinstruction error_log("Create _FILES: " . var_export($_FILES, true), 0); to find out the structure of the array.

Related

Why is "deleteBlocks" not working in phpWord?

I´m trying to use blocks in my Word document but I´m having some problems. First of all, when I declare a block in my document, if I don´t use the function "cloneBlock", the result appears like this:
${sec}
example
${/sec}
Maybe I must use that function to appear properly. But my main problem is that "deleteBlock" is not working. If I don´t clone the block, the generated docx is corrupted. But if I clone the block, the function "deleteBlock" doesn´t delete the block and it appear the information that is inside that block in my final docx file.
This is my code:
//Word
// Creating the new document...
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor('../example.docx');
//set value
//$templateProcessor->setValue('title', 'Example');
//Triplicate block
$templateProcessor->cloneBlock('firstblock', 3, true, true);
$templateProcessor->setValue('firstname#1', 'John');
$templateProcessor->setValue('lastname#1', 'Doe');
$templateProcessor->setValue('firstname#2', 'John');
$templateProcessor->setValue('lastname#2', 'Doe');
$templateProcessor->setValue('firstname#3', 'John');
$templateProcessor->setValue('lastname#3', 'Doe');
//Delete Block
$templateProcessor->cloneBlock('sec', 1, true, true);
$templateProcessor->deleteBlock('sec');
$templateProcessor->saveAs('example.docx');
Docx template:
${firstblock}
Hello ${firstname} ${lastname}!
${/firstblock}
${sec}
example
${/sec}
UPDATE:
Instead of using the function "deleteBlock", I have use the function "cloneBlock" like this and it deletes the block:
//Delete Block
$templateProcessor->cloneBlock('sec', 0, true, true);
So, I have write to clone the block 0 times, so it disappears
But I have another problem. I don´t know why, but this only works sometimes
I'm not sure why user #d1845412 deleted their previous answer, but it actually solved my issue. I overwrote the deleteBlock method with the following code and it seems to work. I prefer this small change over larger changes to the replaceBlock method.
/**
* Override this method since deleteBlock doesn't seem to work.
* #param string $blockname
*/
public function deleteBlock($blockname)
{
$this->cloneBlock($blockname, 0, true, true);
}
Try this. I slightly changed the regexp in replaceBlock, I also added a function that removes unused patterns, it may come in handy) I'll warn you right away - not really testing so use it carefully
class PatchedTemplateProcessor extends TemplateProcessor
{
/**
* Remove ${*} and ${/*} from temporary document
*/
public function removeSearchPatterns()
{
preg_match_all(
'/(\$\{[^\}]*\})/',
$this->tempDocumentMainPart,
$matches,
PREG_SET_ORDER
);
foreach ($matches as $match){
$this->tempDocumentMainPart = str_replace(
$match,
'',
$this->tempDocumentMainPart
);
}
}
/**
* #param string $blockname
* #param string $replacement
*/
public function replaceBlock($blockname, $replacement)
{
$matches = array();
preg_match(
'/(<w:t.*>\${' . $blockname . '}<\/w:.*?t>)(.*)(<w:t.*\${\/' . $blockname . '}<\/w:.*?t>)/is',
$this->tempDocumentMainPart,
$matches
);
if (isset($matches[3])) {
$this->tempDocumentMainPart = str_replace(
$matches[2] . $matches[3],
$replacement,
$this->tempDocumentMainPart
);
}
}
/**
* Delete a block of text.
*
* #param string $blockname
*/
public function deleteBlock($blockname)
{
$this->replaceBlock($blockname, '');
}
}

custom Yii validation class

I've created this custom class to validate some numbers on my website.
class EPriceValidator extends CValidator
{
public $number_type;
/*
* Regular Expressions for numbers
*/
private $default_pattern = '/[^0-9,.]/';
private $price_pattern = '/[^0-9,.]/';
/*
* Default error messages
*/
private $default_msg = '{attribute} is an invalid number.';
private $price_msg = '{attribute} is an invalid price.';
/**
* Validates the attribute of the object.
* If there is any error, the error message is added to the object.
* #param CModel $object the object being validated
* #param string $attribute the attribute being validated
*/
protected function validateAttribute($object,$attribute)
{
// check the strength parameter used in the validation rule of our model
if ($this->number_type == 'price')
{
$pattern = $this->price_pattern;
$error_message = $this->price_msg;
}
else {
$pattern = $this->default_pattern;
$error_message = $this->default_msg;
}
// extract the attribute value from it's model object
$value=$object->$attribute;
if(!preg_match($pattern, $value))
{
$this->addError($object,$attribute, $error_message);
}
}
/**
* Implementing Client Validation
*
* Returns the JavaScript needed for performing client-side validation.
* #param CModel $object the data object being validated
* #param string $attribute the name of the attribute to be validated.
* #return string the client-side validation script.
* #see CActiveForm::enableClientValidation
*/
public function clientValidateAttribute($object,$attribute)
{
// check the strength parameter used in the validation rule of our model
if ($this->number_type == 'price')
{
$pattern = $this->price_pattern;
$error_message = $this->price_msg;
}
else
{
$pattern = $this->default_pattern;
$error_message = $this->default_msg;
}
$condition="value.match(".$pattern.")";
return "
if(".$condition.") {
messages.push(".CJSON::encode($error_message).");
}
";
}
}
it works fine. but how do i make it display the correct field name of the error? right now when there is an error detected on client side, the clientValidateAttribute() displays
{attribute} is an invalid number.
instead of
Total orders is an invalid number.
where Total orders is the input field that is in valid.
Any idea how to fix this?
I rechecked this in the Yii documentation, and it seems you have to add an array with parameters to replace the placeholders in your string. But if you only use the default placeholder for the attribute, it should work by default.
Do you have only the problem on client validation? Because I now checked also the Yii code, and it seems that your code is right, and should work (at least the server validation). But in the client validation you just pass the error mesasage to JSON without any processing, so the {attribute} is not replaces anywhere.
Try to add this to youc client validation before the return
$params['{attribute}']=$object->getAttributeLabel($attribute);
$error_message = strtr($error_message,$params));

Does Laravel Input::hasfile() work on input arrays?

I'm working on a Laravel project that uses a form with multiple file inputs. If I submit the form with the first input empty and all other inputs with a file, then hasFile returns false. It will only return true if the first input contains a file.
if(Input::hasfile('file'))
{
// do something
}
This is the input array via Input::file('file). The small image input is empty, but the large is not. I'd like it to look at the whole array and if there any files present, then proceed with the "do something".
Array
(
[small] =>
[large] => Symfony\Component\HttpFoundation\File\UploadedFile Object
(
[test:Symfony\Component\HttpFoundation\File\UploadedFile:private] =>
[originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => image_name.jpg
[mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => image/jpeg
[size:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 44333
[error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0
[pathName:SplFileInfo:private] => /Applications/MAMP/tmp/php/phpHILgX2
[fileName:SplFileInfo:private] => phpHILgX2
)
)
Is this expected behavior? Or, should it be looking at the entire array?
You can check by using the array key for example like below :-
HTML Input type File Element :
<input type="file" name="your_file_name[]" />
Laravel 5 : $request->hasFile('your_file_name.'.$key)
Laravel 4.2 : Input::hasFile('your_file_name.'.$key)
Taken from source:
/**
* Determine if the uploaded data contains a file.
*
* #param string $key
* #return bool
*/
public function hasFile($key)
{
if (is_array($file = $this->file($key))) $file = head($file);
return $file instanceof \SplFileInfo;
}
It seems that it only checks the first one from the array, head returns the first item from the array.
Since I can't comment, seems I'll have to post.
Ronak Shah's answer really should be marked the correct one here, and when I figured out why, it instantly had me saying "Sonnofa--" after 30-40 minutes trying to figure this... "mess" out.
Turns out to use hasFile() on an input array, you need to use dot notation.
So (using my own example) instead of
$request->hasFile("img[29][file]")
it needs to be
$request->hasFile("img.29.file")
That's certainly an eye-opener, given that PHP and dot notation don't really go together. Input arrays really are problem children.
here is a snippet that may help
if(Input::hasFile('myfile')){
$file = Input::file('myfile');
// multiple files submitted
if(is_array($file))
{
foreach($file as $part) {
$filename = $part->getClientOriginalName();
$part->move($destinationPath, $filename);
}
}
else //single file
{
$filename = $file->getClientOriginalName();
$uploadSuccess = Input::file('myfile')->move($destinationPath, $filename);
}
} else {
echo 'Error: no file submitted.';
}
Taken from
http://forumsarchive.laravel.io/viewtopic.php?id=13291
At the time of writing (Laravel 8) the Request class now supports arrays for the hasFile method, as from the source code:
/**
* Determine if the request contains the given file.
*
* #param string $name
* #param string|null $value
* #param string|null $filename
* #return bool
*/
public function hasFile($name, $value = null, $filename = null)
{
if (! $this->isMultipart()) {
return false;
}
return collect($this->data)->reject(function ($file) use ($name, $value, $filename) {
return $file['name'] != $name ||
($value && $file['contents'] != $value) ||
($filename && $file['filename'] != $filename);
})->count() > 0;
}

In TYPO3 Extbase Repository use statement and like together

Following function works. But I wanna use "statement" and "like" together. If I comment out the line with constraint1 and try with:
$constraint1 = $query->statement("SELECT * FROM pages WHERE title LIKE '" . $text . "%'");
...the query doesn't work.
I got an error:
1: PHP Catchable Fatal Error: Argument 1 passed to TYPO3\CMS\Extbase\Persistence\Generic\Qom\QueryObjectModelFactory::_or() must implement interface TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface, instance of TYPO3\CMS\Extbase\Persistence\Generic\Query given, called in [...] on line 439 and defined in [...]\typo3\sysext\extbase\Classes\Persistence\Generic\Qom\QueryObjectModelFactory.php line 122
Function:
/**
* Test
*
* #param string $text
* #return Objects
*/
public function findWordsByText($text) {
$query = $this->createQuery();
$query->getQuerySettings()->setRespectStoragePage(FALSE);
$query->getQuerySettings()->setReturnRawQueryResult(TRUE);
$constraint1 = $query->like('title', $text . '%');
// $constraint1 = $query->statement("SELECT * FROM pages WHERE title LIKE '" . $text . "%'");
$constraint2 = $query->like('title', 'new');
$constraint = array($constraint1, $constraint2);
$query->matching(
$query->logicalOr($constraint)
);
$records = $query->execute();
return $records;
}
If I change follwing lines:
$query->matching(
$query->logicalOr($constraint)
);
To - logicalAnd:
$query->matching(
$query->logicalAnd($constraint)
);
...the query is empty.
I don't see your problem. You want to return all records that either contain the term $text in the title field or have 'new' in the title field. So just use a simple logicalOr query:
/**
* Test
*
* #param string $text
* #return Objects
*/
public function findWordsByText($text) {
$query = $this->createQuery();
$query->getQuerySettings()->setRespectStoragePage(FALSE);
$query->getQuerySettings()->setReturnRawQueryResult(TRUE);
$query->matching(
$query->logicalOr(
$query->like('title', '%' . $text . '%'),
$query->like('title', 'new')
)
);
return $query->execute();
}
$query->statement() is for raw SQL queries and cannot be combined with createQuery.
By the way, if $text comes from a POST or GET input, don't forget to sanitize the input.

CodeIgniter: Problem with variable sent to model

I'm inheriting someone else's project and I am trying to familiarize myself with it. I have little experience with CI.
On one of the views there's is a drop down form, on change calls a JS function:
$(document).ready(function()
{
// admin contorller drop down ajax
$("#catagoryDropDownList").change(function()
{
getCatagoriesItems();
});
// initiate table sort
TableSorter.prepareTable($("#dataResultsTable"));
});
// ajax request triggered by catagory drop down menu selection
function getCatagoriesItems()
{
blockPage();
// get base url of current site
var baseurl = $("#site_url_for_ajax").val();
// get adminType
var adminType = $("#admin_type").val();
// get catagory id
var catId = $("#catagoryDropDownList option:selected").attr("id");
var queryString = baseurl + "home/ajaxCatagorySelection/" + catId + "/" + adminType;
$.get(queryString, function(data)
{
var obj = jQuery.parseJSON(data);
// dump data into table when request is successful
$("#dataResultsTable tbody").html(JSONParser.parseHomeDropDownSelectedJSON(obj));
// unblock page when done
$.unblockUI();
});
}
I've logged the two values, catID and adminType, they're both integers, catID will be between 1-10 and adminType = 1. There both references to int values in a database. catID is referencing a field titled 'categoryID'. catID 6 = all. None of the entries in the db have 6 as their value, thus ensuring if you filtered for not equaling 6 you'd get all. They get passed to a function called ajaxCatagorySelection in the controller file home.php. So far, so good. Here's that function:
public function ajaxCatagorySelection($tableName, $id)
{
$vars = new DatabaseRetriever($id);
$resultsArray = $vars->getDataForSpecifiedTable($tableName, $id);
echo json_encode($resultsArray);
}
and that function itself is referencing a model (database_retriever.php) and the class DatabaseRetriever and I'm assuming passing the variables along to the function getDataForSpecifiedTable. I say assuming because the variable names have changed significantly from catID to $tableName and adminType to $id. Here is getDataForSpecifiedTable:
public function getDataForSpecifiedTable($catagoryInfo, $databaseID)
{
// connect to database
$sql = $this->connect($databaseID);
if ($catagoryInfo != 6) {
// build SQL Query and query the database
$result = $sql->query("SELECT fileId, fileTitle, filePath, fileTypeExt, fileDescription, fileModed from admin_files where catagoryId = '" . $catagoryInfo . "' and adminId = '" . $databaseID . "'");
} else {
$result = $sql->query("SELECT fileId, fileTitle, filePath, fileTypeExt, fileDescription, fileModed from admin_files where catagoryId = '" . $catagoryInfo . "' and adminId = '" . $databaseID . "'");
}
// declare array
$items = array();
// retriever rows from database and build array
while ($row = $result->fetch_row())
{
array_push($items, $row);
}
// disconnect from database
$this->disconnect();
// return data in array
return $items;
}
the variable names have changed again but you can tell they are suppose to do what I wrote above by looking at the query. Here's the problem. I added the conditional "if ($catagoryInfo != 6)...", if I don't put the else in there then CI throws out warning errors that no data is being returned. I return $categoryInfo and in the FireBug console I get the correct integer. I've tried the conditional as an integer and a string with both failing. Any ideas what might be happening here?
If database_retriever.php is a model, you should call it like so:
$this->load->model('database_retriever');
$resultsArray = $this->Database_retriever->getDataForSpecifiedTable($tableName, $id);
Also, make sure your model extends Model (or extends CI_Model in CodeIgniter 2).
NOTE: $.getJSON, will auto-parse JSON for you, so you don't need to call parseJSON.