In TYPO3 Extbase Repository use statement and like together - repository

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.

Related

TYPO3 extension Model conflict with f:form.upload

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.

Raw SQL queries in TYPO3 9

Is there a way to perform raw SQL queries in TYPO3 9?
Something equivalent to $GLOBALS['TYPO3_DB']->sql_query($sql); in previous versions.
In your repository, you can use statement() for this.
Example:
$query = $this->createQuery();
$sql = '
SELECT fieldA, fieldB
FROM table
WHERE
pid = '.$pid.'
AND someField = 'something'
';
$query->statement($sql)->execute();
Make sure, that you take care of sanitizing the input!
THE ORM-concept seems to makes it difficult using raw SQL.
/**
* #param string $tableName
* #return bool
*/
public function createMySplitTable($newTableName = self::TABLENAME)
{
if ($newTableName !== self::TABLENAME) {
$baseTable = self::TABLENAME;
// make a structure-copy of the main table
$sql ="CREATE TABLE $newTableName SELECT * FROM $baseTable AS main LIMIT 0;";
// looky-looky at 20200609: https://www.strangebuzz.com/en/snippets/running-raw-sql-queries-with-doctrine
// seems to work
/** #var Connection $connection */
$connection = GeneralUtility::makeInstance(ConnectionPool::class)
->getConnectionForTable(self::TABLENAME);
/** #var DriverStatement $statement */
$statement = $connection->prepare($sql);
$statement->execute();
// // --- don't work for me :-(
// /** #var QueryBuilder $queryBuilder */
// $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
// ->getQueryBuilderForTable($baseTable);
// $queryBuilder->resetRestrictions();
// $queryBuilder->resetQueryParts();
// $queryBuilder->add($sql,'select'); // Tried some variations
// $queryBuilder->execute();
// // --- don't work for me :-(
// /** #var Query $query */ // Extbase won't work for this query
// $query = $this->createQuery();
// $query->statement($sql);
// $query->execute(true);
// // --- work only for TYPO3 8 and lower
// $GLOBALS['TYPO3_DB']->sql_query($sql); /// < TYPO3 8
//
}
}
Thanks to https://www.strangebuzz.com/en/snippets/running-raw-sql-queries-with-doctrine
you could use the querybuilder with it's method
TYPO3\CMS\Core\Database\Query\QueryBuilder::selectLiteral(string ... $selects).
Be aware:
Specifies items that are to be returned in the query result. Replaces any previously specified selections, if any. This should only be used for literal SQL expressions as no quoting/escaping of any kind will be performed on the items.
There also is
TYPO3\CMS\Core\Database\Query\QueryBuilder::addSelectLiteral(string ... $selects)
Adds an item that is to be returned in the query result. This should only be used for literal SQL expressions as no quoting/escaping of any kind will be performed on the items.

SilverStripe 3 Left Join Missing argument

I have a data object related to some other data objects and I am trying to build a reporting page for them.
So far I've got the code below in my page controller to display a form where I will begin to select filtering options for the report.
However I am getting this error due to the left join:
[Warning] Missing argument 2 for SQLQuery::addLeftJoin()
It would seem that the raw2sql is outputting this when I've debugged:
\'AgeRangeData\', \'CallEvent.AgeRangeData ID=AgeRangeData.ID)\'
I'm assuming that the backslashes is what is causing the error
public function ReportingFilter(){
$DataObjectsList = $this->dbObject('DataObjects')->enumValues();
$fields = new FieldList(
new DropdownField('DataObjects', 'Data Objects', $DataObjectsList)
);
$actions = new FieldList(
new FormAction("FilterObjects", "Filter")
);
return new Form($this, "ReportingFilter", $fields, $actions);
}
public function FilterObjects($data, $form){
$data = $_REQUEST;
$query = new SQLQuery();
$object = $data['DataObjects'];
$leftJoin = Convert::raw2sql("'" . $object . "', 'CallEvent." . $object . " ID={$object}.ID)'");
$query->selectField("CallEvent.ID", "ID");
$query->setFrom('`CallEvent`');
$query->setOrderBy('CallEvent.Created DESC');
$query->addLeftJoin($leftJoin);
return $query;
}
SQLQuery::addLeftJoin() takes two arguments. The first is the table to join on and the second is the "on" clause.
You want:
$query = new SQLQuery();
$query->addLeftJoin($object, '"CallEvent"."ID" = "' . $object . '"ID"');
You'd need to escape $object appropriately, of course.
NB: Your code looks a little fragile as you're not ensuring that you $object actually has a DB table. I recommend you use ClassInfo::baseDataClass($object). This will have the added benefit that it will also sanitise your class name and ensure it's a real class.

like operator with variable string

i am using LIKE operator in sql but is show some error.here is my code
<?php
header('Access-Control-Allow-Origin: *');
$con=mysqli_connect("url","xxxx","password","xxxx");
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: " . mysqli_connect_error();
exit();
}
$callback =$_GET['callback'];
DECLARE #alpha nchar(1)
SET #alpha = 'A'
$result= mysqli_query($con,"SELECT * FROM demo WHERE Name LIKE #alpha + '%'");
$var= array();
while($row = mysqli_fetch_assoc($result))
{
$var[]=$row;
}
echo $callback."(".json_encode($var).")";
mysqli_close($con);
?>
it works properly when i am using it without alpha i.e when i give string directly.but when i am useing with vaiable it shows an error "Unexpected token <"
I am not a PHP expert, so am not sure of the syntaxes...but you can try the following:
SET #alpha = "A"
$result= mysqli_query($con,"SELECT * FROM demo WHERE Name LIKE '" + #alpha + "%'");
i.e. use the PHP strings within double inverted commas (") and the SQL strings within single inverted commas (')
Also, changing the second line as above should result in the SQL query:
SELECT * FROM demo WHERE Name LIKE 'A%' which is what I think you want. I am not sure if using the variable name within the string will result in getting its value or embed it as it is in the query.

Is this little Doctrine2 dynamic SQL enough safe of injection?

I kwnow that using an ORM like Doctrine2 for building queries is safe, meaning that parameters are escaped by default.
But i'm guessing that this is not so obvious when using literals and when this literal comes directly from the query string:
$builder = $this->getRepository()->createQueryBuilder('e');
$request = $this->getRequest();
// Loop each allowed filter field and check if exists in $request
foreach($this->getFilterFields() as $filter) :
// Skip falsy values in $request
if(!$value = $request->get($filter)) continue;
// Add OR LIKE %$value% where $value is GET paramter
$like = $builder->expr()->literal("%$value%");
$builder->orWhere($builder->expr()->like("e.$filter", $like));
endforeach;
Should safety be improved in some way?
$queryBuilder->expr returns an ExpressionBuilder object. Inside ExpressionBuilder we find:
public function literal($input, $type = null)
{
return $this->connection->quote($input, $type);
}
So literals do get quoted and should be fine to use.
We also find:
public function like($x, $y)
{
return $this->comparison($x, 'LIKE', $y);
}
public function comparison($x, $operator, $y)
{
return $x . ' ' . $operator . ' ' . $y;
}
$y is fine because it goes through literal first. Do want to be a bit careful about $x. As long as your filterFields are internal then no problem. If they are coming from the user then you need to make sure they are valid.