Doctrine2 DQL and stored procedure issue - postgresql

I need to execute with doctrine a query like this
SELECT convert_currency(p.amount) FROM policy p
convert_currency is a stored procedure I developed, waiting for a numeric argument.
I follow the DQL steps and create on CoreBundle/DQL the convertCurrency function:
<?php
namespace DeltaRM\CoreBundle\DQL;
use \Doctrine\ORM\Query\AST\Functions\FunctionNode;
use \Doctrine\ORM\Query\Lexer;
class ConvertCurrency extends FunctionNode
{
public $value = null;
/**
* Parse DQL Function
*
* #param Parser $parser
*/
public function parse(\Doctrine\ORM\Query\Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->value = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* Get SQL
*
* #param SqlWalker $sqlWalker
* #return string
*/
public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
{
return "convert_currency(" . $this->value->dispatch($sqlWalker) . ")";
}
and declare it on my config.yml
And on a repository, I use this function
$qBuilder = $this->getEntityManager()
->createQueryBuilder()
->select("convertCurrency (p.amount)")
->from("DeltaRMAssuranceBundle:Police", "p")
;
It works perfectly, the generated sql statement is
SELECT convert_currency(a0_.amount) AS sclr0 FROM police a0_
But I get an sql error while doctrine execute it :
SQLSTATE[42883]: Undefined function: 7 ERROR: function convert_currency(numeric) does not exist
If I execute directly on pgadmin the same sql, it works, the function is well known
If I do the exact same thing with max instead of convert_currency, it works perfectly.
What did I miss?

Related

TYPO3 - Scheduler task with custom query

I'm using TYPO3 6.2.
I created a custom Extbase Task in order to execute it automatically every day.
<?php
namespace Myextension\Scheduler;
use TYPO3\CMS\Core\Utility\GeneralUtility;
class Task extends \TYPO3\CMS\Scheduler\Task\AbstractTask {
public function execute()
{
// Custom MySQL query here
}
}
?>
I need to develop a complicated mysql query with a lot of conditions, datas and joins : is it possible not to use $GLOBALS['TYPO3_DB']->exec_SELECTquery but a method like $GLOBALS['TYPO3_DB']->sql_query(' SELECT * FROM ... ') ?
Yes, that's definitely possible.
This is the complete function:
/**
* Executes query
* MySQLi query() wrapper function
* Beware: Use of this method should be avoided as it is experimentally supported by DBAL. You should consider
* using exec_SELECTquery() and similar methods instead.
*
* #param string $query Query to execute
* #return boolean|\mysqli_result|object MySQLi result object / DBAL object
*/
public function sql_query($query) {
$res = $this->query($query);
if ($this->debugOutput) {
$this->debug('sql_query', $query);
}
return $res;
}
And you find it in the file:
typo3/sysext/core/Classes/Database/DatabaseConnection.php
And you can call it like you wrote:
$GLOBALS['TYPO3_DB']->sql_query(' SELECT * FROM ... ')

Invalid text representation: 7 ERROR: invalid input syntax for uuid: "test"

I'm using Symfony 3.2 with doctrine and postgresql.
I've created an entity with a uuid as primary key.
My entity definition:
/**
* Booking
*
* #ORM\Table(name="booking")
* #ORM\Entity(repositoryClass="AppBundle\Repository\BookingRepository")
* #ORM\EntityListeners({"AppBundle\EventListener\BookingListener"})
*/
class Booking {
/**
* #var string
*
* #ORM\Column(type="guid")
* #ORM\Id
* #ORM\GeneratedValue(strategy="UUID")
*/
private $id;
}
In my controller I have a show action like this:
/**
* #Route("booking/{id}", name="booking_show")
* #Method({"GET"})
*/
public function showAction(Request $request, Booking $booking) {
...
}
Everything seems to work fine, but when I try to load a route putting an wrong value as an ID (i.e. /booking/hello123), I receive a:
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for uuid: "hello123"
Instead I would expect a 404.
Is there a way to capture this exception and redirect to a 404 page?
You can make use of Route Requirements - you can specify what conditions your parameter need to match to "qualify" to a certain route. This requirement is a regex, so all you need to do is to write a regex for an UUID
/**
* #Route("booking/{id}", name="booking_show", requirements={"id": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"})
* #Method({"GET"})
*/
public function showAction(Request $request, Booking $booking) {
...
}
NOTE: Regex used above is just first result I found in Google for UUID regex, I didn't verify if it works
In the end if your id does not match regex, it does not match route and you should get 404.
you need to change the showaction
/**
* #Route("booking/{id}", name="booking_show")
* #Method({"GET"})
*/
public function showAction(Request $request,$bookingID) {
$em = $this->getDoctrine()->getManager();
$booking = $em->getRepository('AppBundle:Entity')->find(bookingID);
if(!$booking)
$this->createNotFoundException('No entity found with id :'.$bookingID);
...
}

Doctrine annotation exception when using parse query in Symfony2

I'm trying to make an API Rest in Symfony2 using Parse as cloud database.
If I try to retrieve the Parse users it works fine and returns the expected data.
Local url example: http://www.foo.local/app_dev.php/getUsers/
Here is the code I use in the Users controller (I use annotations in order to set the routes in the controller):
namespace Foo\ApiBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\Controller\Annotations\View;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Parse\ParseClient;
use Parse\ParseObject;
use Parse\ParseQuery;
use Parse\ParseUser;
class UsersController extends Controller
{
/**
* #return array
* #View()
* #Route("/getUsers/")
*/
public function getUsersAction(Request $request) {
ParseClient::initialize(<my Parse keys>);
$query = ParseUser::query();
$results = $query->find();
return array('users' => $results);
}
}
However if I try the same with my Products ParseObjects, I get the following error message:
error code="500" message="Internal Server Error" exception
class="Doctrine\Common\Annotations\AnnotationException"
message="[Semantical Error] The annotation "#returns" in method
Parse\ParseFile::getData() was never imported. Did you maybe forget to
add a "use" statement for this annotation?"
Local url example: http://www.foo.local/app_dev.php/getProducts/
The Products controller code:
namespace Foo\ApiBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use FOS\RestBundle\Controller\Annotations\View;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Parse\ParseClient;
use Parse\ParseObject;
use Parse\ParseQuery;
use Parse\ParseUser;
use Parse\ParseFile;
class ProductsController extends Controller
{
/**
* #return array
* #View()
* #Route("/getProducts/")
*/
public function getProductsAction(Request $request) {
ParseClient::initialize(<my Parse keys>);
$query = new ParseQuery("Products");
$results = $query->find();
return array('products' => $results);
}
}
If instead of returning $results I return other dummy data, like return array('products' => 'fooProducts'), I no longer get the error message.
Also if I make a var_dump of the $results variable, I get the expected array of ParseObjects.
Here is my routing.yml file in case there is something wrong with it:
api:
resource: "#FooApiBundle/Controller/"
type: annotation
prefix: /
users:
type: rest
resource: Foo\ApiBundle\Controller\UsersController
products:
type: rest
resource: Foo\ApiBundle\Controller\ProductsController
By the error message it seems that the problem is related to Doctrine, but since I'm not using it, I don't know exactly how there can be a conflict or how to fix it. Any suggestions?
There are a few DocBlock typos of #returns in the Parse\ParseFile class that is causing Doctrine's Annotations class to attempt to identify them as a class. This is not your fault but a bug in the Parse PHP SDK library.
I've made a fix in this commit and submitted a pull request back to the original devs, so it should be a simple matter of eventually running composer update to bring your Parse library to the latest correct version.
You can read more about DocBlock and the part specifically on Annotations here
Here is a copy/paste of the resulting diff for src/Parse/ParseFile.php:
## -31,7 +31,7 ## class ParseFile implements \Parse\Internal\Encodable
/**
* Return the data for the file, downloading it if not already present.
*
- * #returns mixed
+ * #return mixed
*
* #throws ParseException
*/
## -50,7 +50,7 ## public function getData()
/**
* Return the URL for the file, if saved.
*
- * #returns string|null
+ * #return string|null
*/
public function getURL()
{
## -112,7 +112,7 ## public function getMimeType()
* #param string $name The file name on Parse, can be used to detect mimeType
* #param string $mimeType Optional, The mime-type to use when saving the file
*
- * #returns ParseFile
+ * #return ParseFile
*/
public static function createFromData($contents, $name, $mimeType = null)
{
## -132,7 +132,7 ## public static function createFromData($contents, $name, $mimeType = null)
* #param string $name Filename to use on Parse, can be used to detect mimeType
* #param string $mimeType Optional, The mime-type to use when saving the file
*
- * #returns ParseFile
+ * #return ParseFile
*/
public static function createFromFile($path, $name, $mimeType = null)
{
The correct way to initialize Parse using Symfony, is on the setContainer method of your controller:
class BaseController extends Controller
{
....
public function setContainer(ContainerInterface $container = null)
{
parent::setContainer( $container );
ParseClient::initialize( $app_id, $rest_key, $master_key );
}
}
Depending of your needs, you can create a BaseController and extend it in your rest of controllers.
class UsersController extends Controller
In addition, you could add your keys in the parameters.yml file.
parameters:
#your parameters...
ParseAppId: your_id
ParseRestKey: your_rest_key
ParseMasterKey: your_master_key
TIP: Note you can add have different Parse projects (dev and release
version). Add your parameters in your different parameters
configuration provides an easy way to handle this issue.
class BaseController extends Controller
{
....
public function setContainer(ContainerInterface $container = null)
{
parent::setContainer( $container );
$app_id = $container->getParameter('ParseAppId');
$rest_key = $container->getParameter('ParseRestKey');
$master_key = $container->getParameter('ParseMasterKey');
ParseClient::initialize( $app_id, $rest_key, $master_key );
}
}

SphinxQL & Phalcon\Mvc\Model

I have a Sphinx search engine running on MySQL protocol and I use Phalcon\Db\Adapter\Pdo\Mysql to connect to it. Sphinx tables are implemented as models.
When I try to select (using SpinxQL) I, obviously, get an error when database adapter attempts to extract table metadata running queries against tables which are not supported and not present respectively in SpinxQL. There is a workaround in the documentation showing how to manually assign metadata... But being to lazy by nature I want to try to automate metadata generation.
I assume that metadata is produced by the database adapter, probably as a result of calling getColumnsList() on the instance following getColumnDefinition() or something else (???). Is this my assumption correct? I want is to extend Phalcon\Db\Adapter\Pdo\Mysql and override those methods to be compatible with Sphinx.
Thanks in advance for your suggestions!
Ok, you need to override at least two methods to make this work, the following class would work:
<?php
class SphinxQlAdapter extends Phalcon\Db\Adapter\Pdo\Mysql implements Phalcon\Db\AdapterInterface
{
/**
* This method checks if a table exists
*
* #param string $table
* #param string $schema
* #return boolean
*/
public function tableExists($table, $schema=null)
{
}
/**
* This method describe the table's columns returning an array of
* Phalcon\Db\Column
*
* #param string $table
* #param string $schema
* #return Phalcon\Db\ColumnInterface[]
*/
public function describeColumns($table, $schema=null)
{
}
}
Then in your connection, you use the new adapter:
$di->set('db', function(){
return new SphinxQlAdapter(
//...
);
});

doctrine 2 Annotations and Zend Framework underscore convention

I am working through the doctrine 2 (Beta3) sandbox and trying to apply the Zend Framework coding convention of placing a leading underscore to private class members. When I query Address, while its private members are NOT underscored, i retrieve the object as expected. When I add the underscores, regenerate and repopulate the db, and then run the same query I get the following error messages:
PHP Notice: Undefined index: id in ... Doctrine/ORM/Internal/Hydration/AbstractHydrator.php on line 184
PHP Fatal error: Uncaught exception 'Doctrine\DBAL\DBALException' with message 'Unknown column type requested.' in ... Doctrine/DBAL/DBALException.php:81
The DQL query:
$q = $em->createQuery('select u from Entities\Address u where u.id = ?1');
$q->setParameter(1, '1');
$address = $q->getSingleResult();
The ZFed Address class:
<?php
namespace Entities;
/** #Entity #Table(name="addresses") */
class Address
{
/**
* #Id #Column(type="integer", length=11, name="id")
* #GeneratedValue(strategy="AUTO")
*/
private $_id;
/** #Column(type="string", length=255, name="street") */
private $_street;
public function getId()
{
return $this->_id;
}
public function getStreet()
{
return $this->_street;
}
public function setStreet($street)
{
$this->_street = $street;
}
}
You would have to write _ in front of all your DQL Queries yes.
Underscores in front of variables are some kind hungarian notation, which we as Doctrine team don't like. Even Zend Framework will drop that style for new code as far as i understood. Many other projects did the same and PEAR2 even changed their standard in this regard.