Doctrine QueryBuilder undefined method getQuery() - php

When I execute the method getMachineSettings I get an error:
Fatal error: Uncaught Error: Call to undefined method Doctrine\DBAL\Query\QueryBuilder::getQuery()
$data is an associative array:
$data['param'] = 'ip';
$data['value'] = '192.168.240.10';
If I replace getQuery()->getResult() with execute(), $result contains the query:
SELECT * FROM machine WHERE ip = ?
public function __construct()
{
try
{
$dbconf = parse_ini_file('.htLogin.ini');
$config = new \Doctrine\DBAL\Configuration();
$connectionParams = array
(
'dbname' => $dbconf['infoDb'],
'user' => $dbconf['infoLogin'],
'password' => $dbconf['infoPw'],
'host' => $dbconf['infoHost'],
'driver' => 'pdo_mysql',
'charset' => 'utf8',
'driverOptions' => array
(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'
)
);
$this->mysql = \Doctrine\DBAL\DriverManager::getConnection($connectionParams, $config);
}
catch(PDOException $e)
{
echo $e -> getMessage();
}
public function getMachineSettings($data)
{
$qb = $this->mysql->createQueryBuilder();
$qb->SELECT('*')
->FROM('`machine`')
->WHERE($data['param'] . ' = :value');
$qb->setParameters(
array
(
':value' => $data['value']
)
);
$results = $qb->getQuery()->getResult();
var_dump($result);
return $result;
}
Do you have any idea why the method getQuery() is not recognised?

Just do
$results = $qb->execute()->fetchAll();
Ignore the below - it assumes that your using the Doctrine ORM, which your not
The issue your having is that the QueryBuilder object your working with isn't the Doctrine ORM QueryBuilder - its the DBAL QueryBuilder.
You need to use the createQueryBuilder function from the EntityManager.
/** #var Doctrine\ORM\QueryBuilder $qb */
$qb = $this->entityManager->createQueryBuilder();
Then you can use the select / from etc methods and to get the result of the query you can run
$qb->getQuery()->getResult()
If I was to rewrite your function I would write it like this
public function getMachineSettings(string $field, string $value)
{
$qb = $this->entityManager->createQueryBuilder();
$qb->select('m')
->from('machine')
->where($field.' = :value');
$qb->setParameter('value', $value);
$results = $qb->getQuery()->getResult();
var_dump($result);
return $result;
}
Then you know that the function requires 2 parameters to function, passing an array doesn't let you immediately see what the function requires

Related

Passing a query to a module_hook that uses a second database

I would like to use another database connection that queries a database using a hook in my own module called 'connector'. This hook shall take a parameter that is a query which shall be executed using the secondary database before it switches back to the primary Drupal 7-database. The problem seems to be that the query is somehow generated for the (primary) Drupal database (as it's been created before switching to the secondary db), even though the SQL itself looks fine to me. What am I doing wrong here?
Hook:
function connector_api_db($query) {
$result = [];
$database_info = array(
'database' => variable_get('connector_db_name'),
'username' => variable_get('connector_db_user'),
'password' => variable_get('connector_db_pwd'),
'host' => variable_get('connector_db_host'),
'driver' => 'mysql',
);
Database::addConnectionInfo('secondary_db', 'default', $database_info);
db_set_active('secondary_db'); // Initialize the connection
/* This actually works but I can here not use my own query as a parameter in this function. Not what I want. */
//$query = db_select('registration')->fields('registration')
//->condition('id', 46, '=');
echo $query->__toString() . "<br />"; /* Get query string */
var_dump($query->getArguments()); /* Get the arguments passed to the string */
$result = $query->execute()->fetchAssoc();
echo "<pre>";
print_r($result);
echo "</pre>";
db_set_active(); // without the paramater means set back to the default for the site
drupal_set_message(t('The queries have been made.'));
return $result;
}
Invoking the hook:
$query = db_select('registration')
->fields('registration')
->condition('id', 46, '=');
$response = module_invoke('connector', 'api_db', $query);
This results into this:
SELECT registration.* FROM {registration} registration WHERE (id = :db_condition_placeholder_0)
array(1) { [":db_condition_placeholder_0"]=> int(46) }
Additional uncaught exception thrown while handling exception.
Original
PDOException: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'drupal.registration' doesn't exist: SELECT registration.* FROM {registration} registration WHERE (id = :db_condition_placeholder_0) ; Array ( [:db_condition_placeholder_0] => 46 ) in connector_api_db() (line 70 of /<path-to-drupal>/drupal-7.61/modules/connector/connector.main.inc).
This is not an answer, strictly speaking, but rather a suggestion.
The thing is that your hook receives a $query already built with the original database connection, this explains the errors. To be effective, db_set_active() should be called before calling the Query constructor.
Otherwise, you would have to override constructors for both the Select class and its parent class Query, or more precisely "reconstruct" the Query builder instance for Select statements (and probably others too if you need range query etc.).
Also, unless having explicit requirements to provide a dedicated hook in this situation, it is not necessary.
For example it would be simpler to do something like this :
connector.module :
/**
* Implements hook_init()
*
* Adds secondary database connection information.
*/
function connector_init() {
$database_info = array(
'database' => variable_get('connector_db_name'),
'username' => variable_get('connector_db_user'),
'password' => variable_get('connector_db_pwd'),
'host' => variable_get('connector_db_host'),
'driver' => 'mysql',
);
Database::addConnectionInfo('secondary_db', 'default', $database_info);
}
/**
* Switches from primary to secondary database and the other way round.
*/
function connector_switch_db($db_key = 'secondary_db') {
return db_set_active($db_key);
}
Example :
// Set secondary db active.
$primary_db_key = connector_switch_db();
$query = db_select('registration')
->fields('registration')
->condition('id', 46, '=');
$result = $query->execute()->fetchAssoc();
// Switch back to the primary database.
connector_switch_db($primary_db_key);
This softer approach also prevents hardcode like (...)->execute()->fetchAssoc() and let the implementation free to execute and fetch the results as needed.
For future reference, this is what I came up with (caching bits included):
function connector_init() {
foreach([
'connector_db_host',
'connector_db_name',
'connector_db_user',
'connector_db_pwd',
] as $var) {
drupal_static($var, variable_get($var, ''));
}
Database::addConnectionInfo('secondary_db', 'default', [
'host' => drupal_static('connector_db_host'),
'database' => drupal_static('connector_db_name'),
'username' => drupal_static('connector_db_user'),
'password' => drupal_static('connector_db_pwd'),
'driver' => 'mysql',
]);
}
function connector_api_db($query) {
$result = [];
$sql_query = $query->__toString();
$arguments = $query->getArguments();
if (count($arguments) > 0) {
ksort($arguments);
}
$cache_id = 'sql_' . md5($sql_query . '|' . print_r($arguments, 1));
$cache = cache_get($cache_id, 'cache_connector');
if ($cache && $cache->expire >= time()) {
$result = $cache->data;
} else {
db_set_active('secondary_db'); // Switch to secondary db */
$query_failed = FALSE;
try {
$db_result = db_query($sql_query, $arguments);
$db_result = (0 === $db_result->rowCount()) ? [] : $db_result->fetchAssoc();
} catch (\PDOException $e) {
$db_result = [];
$query_failed = TRUE;
} finally {
db_set_active(); /* switch back to default */
}
$result = (object)[
'query' => $sql_query,
'arguments' => $arguments,
'result' => (object)$db_result
];
if (!$query_failed) {
cache_set($cache_id, $result, 'cache_connector', strtotime('+10 minutes'));
}
}
return $result;
}

How should I prophesy the sort method?

I am using the DoctrineMongoDBBundle and I am not sure how to prophesy the sort method.
Source
$qb = $dm->createQueryBuilder('Article')
->sort('createdAt', 'desc');
My code is:
UserRepository - Method All
public function all(array $input = null)
{
$user = UserEntity::class;
$all = $this->dm->createQueryBuilder($user);
$search = $all->sort(['name' => 'asc'])
->getQuery();
return $search;
}
UserRepositoryTest - prophecy
public function testSortingResults()
{
$output = [
'name' => 'John',
'email' => 'john#email.com',
'phone' => '89564789547',
];
$document = $this->prophesize(DocumentManager::class);
$queryBuilder = $this->prophesize(QueryBuilder::class);
$queryBuilder->sort()->willReturn($output)->shouldBeCalled();
$queryBuilder->getQuery()->willReturn($output)->shouldBeCalled();
$document->createQueryBuilder(UsuarioEntidade::class)->willReturn($queryBuilder)->shouldBeCalled();
$repository = new UserRepository($document->reveal());
$all = $repository->all();
$this->assertNotNull($all);
$this->assertEquals($output, $all);
}
The error is always this
Prophecy\Exception\Doubler\MethodNotFoundException: Method Double\Doctrine\ORM\QueryBuilder\P2::sort() is not defined.
I do not understand how to test SORT, because it is not found in QueryBuilder.

Searching a set of records in Zend Framework

I have written code to search for the First name and last name and display those particular records if available and perform actions like update and delete on those records , I have written the following code to search , please tell me what is the correct approach to build a search controller .I am getting the following error :
Message: Method "select" does not exist and was not trapped in __call()
The code I have written in the controller is :
public function searchAction($params)
{
$query = $this->select()
->from(
array('EMPLOYEES'),
array('FIRST_NAME','LAST_NAME','SALARY','HIREDATE')
);
$query = $this->_makeParams($query,$params);
return $this->fetchAll($query);
}
private function _makeParams($query, $params)
{
$firstname = isset($params['firstname']) ? trim($params['firstname']) : '';
$lastname = isset($params['lastname']) ? trim($params['lastname']) : '';
$salary = isset($params['salary']) ? trim($params['salary']) : '';
$hiredate= isset($params['hiredate']) ? trim($params['hiredate']) : '';
if($firstname!='')
{
$name = '%'.$this->quote($firstname).'%';//quote is my own function
$query->where("EMPLOYEES.FIRST_NAME LIKE '?'",$firstname);
}
if($lastname!='')
{
$query->where("EMPLOYEES.LAST_NAME =?",$lastname);
}
if($salary!='')
{
$query->where("EMPLOYEES.SALARY=?",$salary);
}
if($hiredate!='')
{
$query->where("EMPLOYEES.HIRE_DATE=?",$hiredate);
}
}
your error comes from the fact that your calling select() against the controller object instead of the database object:
public function searchAction($params)
{
//$this in this context is a Zend_Controller_Action object
//you need to query against your database object.
$db = Zend_Db_Table::getDefaultAdapter();
$query = $db->select()
->from(
array('EMPLOYEES'),
array('FIRST_NAME','LAST_NAME','SALARY','HIREDATE')
);
$query = $this->_makeParams($query,$params);
//again make sure to query against the database object
return $db->fetchAll($query);
}
if you don't have a database object created in your bootstrap.php or application.ini you can create one with the Zend_Db:
$db = Zend_Db::factory('Pdo_Mysql', array(
'host' => '127.0.0.1',
'username' => 'webuser',
'password' => 'xxxxxxxx',
'dbname' => 'test'
));
public function searchAction($params)
{
$db = Zend_Registry :: get('db');
$select = $db->select();
$query = $select->from(
array('EMPLOYEES'),
array('FIRST_NAME','LAST_NAME','SALARY','HIREDATE')
);
$query = $this->_makeParams($query,$params);
return $this->fetchAll($query);
}
You are getting the error because you have not created the object of Zend registry.So copy the function and replace your code

SQL Join and Json encode joomla 2.5

Okay ill be honest im a little bit lost here, Im creating a component for joomla 2.5 and have two tables in the database, "managers" and another called "Branches". Im trying to join managers with branches.
I wish i could be more precise with my problem but i honestly dont understand it, heres my model file that calls to the database:
<?php
defined( '_JEXEC' ) or die;
jimport('joomla.application.component.model');
class LocateModelBranches extends JModel
{
public function getItem()
{
$branch_id = JRequest::getInt('id');
$row = JTable::getInstance('branches', 'LocateTable');
$row->load($branch_id);
return $row;
}
public function getBranches()
{
$branch_id = JRequest::getInt('id');
$db = $this->getDbo();
$query = $db->getQuery(true);
$query->select('*');
$query->from('#__branches');
$query->join('LEFT', '#__managers AS a USING(manager_id)');
$query->where("published = 1");
$db->setQuery($query);
$rows = $db->loadObjectList();
return $rows;
}
}
then my view.json.php file:
<?php
defined( '_JEXEC' ) or die;
jimport( 'joomla.application.component.view');
class LocateViewBranches extends JView
{
public function display($tpl = null)
{
$branch = $this->get('Branches');
$response = array();
foreach ($branch as $row) {
$response[] = array(
'lat' => $row->branch_latitude,
'lng' => $row->branch_longitude,
'data' => array(
'name' => $row->branch_name,
'address' => $row->branch_address,
'fax' => $row->branch_fax,
'email' => $row->branch_email,
'city' => $row->branch_city,
'telephone' => $row->branch_telephone,
'id' => $row->branch_id,
'lati' => $row->branch_latitude,
'lngi' => $row->branch_longitude,
'manager_id' => $row->manager_id,
),
);
}
echo json_encode($response);
}
}
then i get a response of:
[]
if i remove "$query->join('LEFT', '#__managers AS a USING(manager_id)');" my response then is (which is what i want along with the managers details :
[{"lat":"-33.9249","lng":"18.4241","data":{"name":"test 2","address":"greenpoint, Cape Town","fax":"044 382 0605","email":"test","city":"blah","telephone":"044 382 0605","id":"2","lati":"-33.9249","lngi":"18.4241"}},{"lat":"-34.0438","lng":"23.0759","data":{"name":"jam factory","address":"15 meeu street knysna","fax":"00000000","email":"00000000","city":"am factory","telephone":"0000000","id":"14","lati":"-34.0438","lngi":"23.0759"}}]
Im sure its just a problem with my view.json.php
also if i change from json_encode to print_r and keep "$query->join('LEFT', '#__managers AS a USING(manager_id)');" i get a response of:
Array
(
)
1
so surely its just the way im outputting the data
Easy as:
public function getBranches()
{
$branch_id = JRequest::getInt('id');
$db = $this->getDbo();
$query = $db->getQuery(true);
$query->select('*, a.manager_name,manager_mobile');
$query->from('#__branches AS t')
->join('LEFT', '#__managers AS a USING(manager_id)')
->where('t.published = 1');
$db->setQuery($query);
$rows = $db->loadObjectList();
return $rows;
}
Thanks For everyone's input. :)

zend_db and join

I am trying to understand how to use Zend_DB in my program but I have some problems. The class below (DatabaseService) works when I pass it a simple query. However, if I pass it a query with a join clause my page just hangs and no error is returned. I cut and paste the qry in a query browser and it is valid
Any help would be great
$SQL = "select name from mytable"
$db = new DatabaseService($dbinfo)
$db ->fetchall($SQL ) // works
-----------------------------------------------------------
$SQL = "select count(*) as cnt from EndPoints join CallID on EndPoints.`CallID` = CallID.CallID where EndPoints.LastRegister >= '2010-04-21 00:00:01' and EndPoints.LastRegister <= '2010-04-21 23:59:59' "
$db = new DatabaseService($dbinfo)
$db ->fetchall($SQL ) // DOES NO WORK
class DatabaseService
{
function DatabaseService($dbinfo,$dbname="")
{
try
{
$dbConfig = array(
'host' => $this->host,
'username' => $this->username,
'password' => $password,
'dbname' => $this->dbname );
$this->db = Zend_Db::factory($this->adapter, $dbConfig);
Zend_Db_Table::setDefaultAdapter($this->db);
}
catch(Zend_Exception $e)
{
$this->error = $e->getMessage();
Helper::log($this->error);
return false;
}
}
public function connnect()
{
if($this->db !=null)
{
try
{
$this->db->getConnection();
return true;
}
catch (Zend_Exception $e)
{
$err = "FAILED ::".$e->getMessage()." <br />";
}
}
return false;
}
public function fetchall($sql)
{
$res= $this->db->fetchAll($sql);
return $res;
}
}
I can't see why that wouldn't work. It could be a bug in a particular release of ZF but as far as I can tell there are no SQL syntax errors. What you could do is Bootstrap the Zend_Db class somewhere in your system like in the index.php file just as you were doing in your DatabaseService class:
$dbConfig = array(
'host' => 'hostname',
'username' => 'username',
'password' => 'password',
'dbname' => 'dbname'
);
$db = Zend_Db::factory('mysqli', $dbConfig);
$db->setFetchMode(Zend_Db::FETCH_OBJ);
Zend_Db_Table::setDefaultAdapter($db);
And then Zend Framework should handle the connection process for you. Then instead of having a DatabaseService class you just create a model for each table you need like so:
<?php
class EndPoints extends Zend_Db_Table_Abstract
{
protected $_name = 'EndPoints';
/**
* the default is 'id'. So if your table's primary key field name is 'id' you
* will not be required to set this. If your primary key is something like
* 'EndPointsID' you MUST set this.
* #var primary key field name
*/
protected $_primary = 'EndPointsID';
}
Doing this will automagically give you access to functions such as fetchRow(), fetchAll(), find(), etc. Then you can also use Zend_Db_Table_Select for your queries which can be quite useful. Like so:
<?php
$endPointsModel = new EndPoints();
$callIdCount = $endPointsModel->getCallIdCount('2010-04-21 00:00:01', '2010-04-21 00:00:01');
Then in your EndPoints model you would create that function like so:
...
public function getCallIdCount($fromDate, $toDate)
{
$cols = array('cnt' => 'count(*)');
$select = $this->select->setIntegrityCheck(false) // this is crucial
->from($this->_name, $cols)
->join('CallID', "{$this->_name}.CallID = CallID.CallID", array())
->where("{$this->_name}.LastRegister >= ?", $fromDate)
->where("{$this->_name}.LastRegister <= ?", $toDate);
// if you need to see what the whole query will look like you can do this:
// echo $select->__toString();
return $this->fetchAll($select);
{

Categories