How can I use a stored procedure in a MySql database with Zend Framework? - zend-framework

I'm recently have learned to use Zend Framework. I did a simple CRUD application. But now I want to use a existing database for a more complex application and I want to know how I call a stored procedure in the Model, how to send parameters, how to read the results and store them in an array in PHP. Please. I appreciate any kind of help :)

It's not too hard. Here's an example of a MySQL stored procedure with an IN parameter, an OUT parameter, and a result set:
CREATE PROCEDURE MyProc(IN i INTEGER, OUT o INTEGER)
BEGIN
SELECT i+10 INTO o;
SELECT i, o;
END
You can call this with the query() method, and pass a parameter:
$stmt = $db->query("CALL MyProc(?, #output)", array(25));
print_r( $stmt->fetchAll() );
The trick is that MySQL stored procs might return multiple result sets (if the proc had multiple SELECT queries for instance). So the API must advance through all result sets before you can execute another SQL query. Or else you get the "Commands out of sync" error.
If you use the PDO_MySQL adapter:
while ($stmt->nextRowset()) { }
If you use the MySQLi adapter, you'll find that Zend_Db_Statement_Mysqli doesn't implement nextRowset(), so you have to call the internal mysqli connection object:
while ($db->getConnection()->next_result()) { }
Once you clear the result sets, you can run subsequent SQL queries, for example to fetch the value of the procedure's OUT parameter:
$stmt = $db->query("SELECT #output");
print_r( $stmt->fetchAll() );

Great answer from Bill. Just for completeness, if you encounter:
SQLSTATE[HY000]: General error: 2053
When using this method to get a result set from your procedure, check your arguments. I refactored a method and was passing NULLs as arguments to the procedure as the variables I'd used were out of scope. Once I'd fixed this silly mistake the problem went away (to be replaced by another):
SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other
unbuffered queries are active. Consider using PDOStatement::fetchAll().
I'm using $stmt->fetchAll() though. I switched to using prepare() and execute() in place of query(). Switching to mysqli from pdo_mysql in my Zend_Db config finally got things working for me. I found this information from the following SO question:
Call Multiple Stored Procedures with the Zend Framework

If someone is looking for ZendFramework 2 \ Zend Expressive using Zend\Db :
There is another way to do this using createStatement() method.
// prepare create statement from adapter
$stmt = $this->getAdapter()->createStatement();
$stmt->prepare('CALL myproc("myVal")');
// execute sql query
$records = $stmt->execute();
// manipulate results
if ($records instanceof ResultInterface && $records->isQueryResult()) {
$resultSet = new ResultSet;
$resultSet->initialize($records);
// return records if found
if (count($resultSet)) {
// return array of result set
return $resultSet->toArray();
}
// if no records found
return array()
}

$db = Zend_Db_Table::getDefaultAdapter();
$stmt = $db->query("CALL procedure()");
$data = $stmt->fetchAll();

Related

How do you pass variables into Mirth Database Reader Channels for SQL expressions?

I can't find any documentation on how to manager parameters into Database Reader SQL statements?
-> this is a simplified example: I am not looking for scripting a variable to "yesterday" which is easy to express in SQL. That's not the point. I have have more complex variables in the actual SQL statement I'm trying to martial in. I just want to know how to get variables into the SQL form if possible.
-> "you can just do that in JavaScript": the actual queries I need to run are about a hundred lines long, I don't want to maintain and debug a query build by concatenating strings and then deal with escaping 'quoted' things everywhere in the SQL. I really prefer to maintain an actual SQL statement that copy/paste works in a SQL IDE.
How do we pass in parameters into the SQL block at the bottom of the Database Reader form?
SELECT patientsex, visitnumber, samplereceived_dt, sr_d, sr_t, orderpriority, orderrequestcode, orderrequestname
FROM mydata.somedata
WHERE sr_d = (${DateUtil.getCurrentDate('yyyyMMdd')})::integer;
JavaScript is the feasible way to achieve this, with SQL statements defined inside Mirth connect or have the SQL statements bundled in a stored procedure then use SQL server's Exec command within Mirth connect to call the stored procedure while passing the parameters (interestingly using JavaScript).
For example
var dbConn;
try {
dbConn = DatabaseConnectionFactory.createDatabaseConnection('','DB:Port\instance','user','pass');
var paramList = new java.util.ArrayList();
paramList.add($('patientId'));
paramList.add($('lastName'));
paramList.add($('firstName'));
var result = dbConn.executeCachedQuery("SELECT * FROM patients WHERE patientid = ? AND lastname = ? AND firstname = ?) ",paramList);
while (result.next()) {
//you can reference by column index like so...
//result.getString(1);
}
} finally {
if (dbConn) {
dbConn.close();
}
}
Should be noted that the parameters you add to the list MUST be in order.

How do I use a PostgreSQL function that returns a table as a CakePHP 3 Model?

Using Cake PHP 3.x and we have a PostgreSQL 9.6.3 db.
We make extensive use of PG functions that return tables - for example
select * from getStudies(cid,UID, SID);
Functions are used for various applications - one of them is more complex filtering of rows from a table - where Cake has difficulty.
One option is to implement the logic as a custom Cake Model method in PHP, but the SQL code and amount of joins makes it messy in PHP.
We think we should be able to create a Cake Model from the function and then pass the parameters via Cake Model methods but so far - it is unclear how to do that.
This code works but it returns the data without the columns and I have not been able to figure out how to use reflection to get the _columns properties from the Model schema.
public function getStudies($data = array()) {
$customer_id = $data['customer_id'];
$connection = ConnectionManager::get('default');
$sql = "select * from getStudies($customer_id)";
$results = $stmt->fetch();
return $results; }
So -
Option 1 - figure out how to model a function that returns tables as a cake model
Option 2 - use reflection to get the _columns and merge it with the query result
Thanks
As you've mentioned in the comments, the schema columns details can be accessed via its columns() method. You could process the results manually using the schema information, or use the function as the source, just like in your example.
The query builders from() method supports raw SQL as well as expressions, so you can basically add whatever you like, however expressions will be wrapped in parentheses, which will be invalid SQL in case of a function call, so you'd have to go with raw SQL, and bindings (please never inject (user)data into queries directly):
public function getStudies($customerId)
{
return $this
->find()
->from([
$this->alias() => 'getStudies(:customerId)'
])
->bind(':customerId', $customerId, 'integer');
}
That should generate a query similar to
SELECT
Alias.column1, Alias.column2, ...
FROM
getStudies(:customerId) Alias

EF Core FromSQL query does not get executed immediately (PostgreSQL)

I have written a function in PostgreSQL for insertion as follows:
CREATE OR REPLACE FUNCTION public.insert_blog("Url" character)
RETURNS void AS
$BODY$Begin
Insert Into "Blogs"("Url") Values("Url");
End$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
ALTER FUNCTION public.insert_blog(character)
OWNER TO postgres;
The above function adds an entry into the Blogs table (Url is a parameter).
I am trying to use this function in .Net Core (Npgsql.EntityFrameworkCore.PostgreSQL) as follows:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Blog blog)
{
if (ModelState.IsValid)
{
//This works fine
var count = _context.Blogs.FromSql("Select insert_blog({0})", blog.Url).Count();
//This doesn't work -- it gives an error of "42601: syntax error at or near "insert_blog""
//var count = _context.Blogs.FromSql("insert_blog #Url={0}", blog.Url).Count();
return RedirectToAction("Index");
}
return View(blog);
}
Can someone tell me why the second command is not working? Also, even if the first command is working, is it the right way?
Since I have to write .FromSql(...).Count() in order for it to work, if I remove .Count() item doesn't get inserted. Can someone tell me why this is happening?
Is there any good article on using .FromSql() or "Using Postgres functions in entity framework core" (I'd guess that this is a new feature and that that's why I couldn't find much data on this)?
Can some one tell me why the second command is not working? Also even if the first command is working, is it the right way?
It's simply just not the way PostgreSQL syntax works. Select insert_blog({0}) is indeed the right way.
Since I have to write .FromSql(...).Count() in order for it to work. If I remove ".Count()" item doesn't get inserted. Can someone tell me why this is happening?
FromSql behaves just like Where and other functions on an IQueryable. Execution is postponed until the results are requested, because it will try to do everything in one database query.
To make sure your query actually gets executed, you need to call a method that returns something other than IQueryable such as .Count() or .ToList(). More info can be found here: https://learn.microsoft.com/en-us/ef/core/querying/overview#when-queries-are-executed

result return in zend

I am writing query like this in zend but I am not getting return result in controller file, then what I have to do for this.
$result=$db->query("insert into geofences (`name`,`description`,`polygon`,
`created_timestamp`,`company_id`)
values ('".$formData ['name']."',
'".$formData['description']."',
GeomFromText('POLYGON(($polygon))'),
now(),'".$formData ['company_id']."')
");
return $result;
after a query() statment you have to fetch the results (if you have a SELECT, SHOW, DESCRIBE and EXPLAIN statement).... i think it uses the standard mysqli classes of PHP!
In your case (an insert statement) you have no result to fetch...i think (i'm not sure but i think this is the case) that it returns true on success and false if the query fails.
Look here and here for reference

Zend Framework how to echo value of SUM query

I created a query for the zend framework, in which I try to retrieve the sum of a column, in this case the column named 'time'. This is the query I use:
$this->timequery = $this->db_tasks->fetchAll($this->db_tasks->select()->from('tasks', 'SUM(time)')->where('projectnumber =' . $this->value_project));
$this->view->sumtime = $this->timequery;
Echoing the query tells me this is right. But I can't echo the result properly. Currently I'm using:
echo $this->sumtime['SUM(time)'];
Returning the following error:
Catchable fatal error: Object of class Zend_Db_Table_Row could not be converted to string in C:\xampp\htdocs\BManagement\application\views\scripts\tasks\index.phtml on line 46
Line 46 being the line with the echo in my view.
I've been searching now for two days on how to figure this out, or achieve the same result in a different way. Tried to serialize the value, but that didn't work either.
Is there somebody who knows how to achieve the total sum of a database column?
Any help is greatly appriciated!
note: Pretty new to zend framework...
Zend_Db has some nice utility methods like fetchAll (which you're using) to fetch different types of data:
fetchAll - for a set of rows
fetchRow - for a single row
fetchOne - for a single cell
Most simply:
$sum = $db->fetchOne('SELECT SUM(time) FROM tasks WHERE project_number = ?', $this->value_project);
You can use Zend_Db_Select with these methods too, like in your question:
//note that the SUM(time) part is passed as a Zend_Db expression, as it is not a column
$select = $this->db_tasks->select()
->from('tasks', new Zend_Db_Expr('SUM(time)'))
->where('projectnumber =' . $this->value_project);
$this->timequery = $this->db_tasks->fetchOne($select);
This works because the Zend_Db_Select object implements a toString method, to produce SQL.
$timequery= $timequeriestb->select(Zend_Db_Table::SELECT_WITH_FROM_PART)
->columns('SUM(time) AS Totaltime')
->where('projectnumber ='. $this->value_project));
The SQL you want is probably:
SELECT SUM(time) AS time_sum FROM tasks ...
Not sure how to do this in Zend. Then:
echo $this->sumtime['time_sum'];