zendframework 2 select max of a column - select

I'm using ZendFramework 2 and TableGateway which is fine for normal select statements. But I can't seem to find how to get a max of a column using ZendFramework 2 select.
My select should look something like
SELECT MAX( `publication_nr` ) AS maxPubNr FROM `publications`
and my code looks like:
use Zend\Db\TableGateway\TableGateway;
class PublicationsTable
{
protected $tableGateway;
...
public function getMaxPubicationNr()
{
$rowset = $this->tableGateway->select(array('maxPubNr' => new Expression('MAX(publication_nr)')));
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not retrieve max Publication nr");
}
return $row;
}

If you look at the TableGateway you will notice the parameters for the Select method are actually passed to the Where part of the Query, which is making your query incorrect.
You need to modify the Select Object directly as the TableGateway won't give you any proxy methods to do this.
You could try something like this:
public function getMaxPubicationNr()
{
$select = $this->tableGateway->getSql()->select();
$select->columns(array(
'maxPubNr' => new Expression('MAX(publication_nr)')
));
// If you need to add any where caluses you would need to do it here
//$select->where(array());
$rowset = $this->tableGateway->selectWith($select);
$row = $rowset->current();
if (!$row) {
throw new \Exception("Could not retrieve max Publication nr");
}
return $row;
}
I've not tested it, but that should just about get you there :)
You will probably bump into another issue though, and that will be due to the TableGateway trying to build you an object from the result, but you aren't bringing back a full row to build an object, you're just bringing back a single Column.
I would just add use the Db/Select objects to do this and not bother with the GateWay to be honest, I don't think it's supposed to be used like this.

Related

Sort Childobjects by specific value

im currently trying to sort all Childobjects i can get by their validity time.
my current code is not sorting anything:
$children = $this->productRepository->findByParent($product->getNumber());
foreach ($children as $child) {
//debug::debug($child->getvalidityPeriod());
$product->addChild($child);
}
As allready to see in the debug, $child->getvalidityPeriod() is there to get the needed info as integer. I thought, there must be a way to sort this object array by their validityPeriod, but how do i manage that? Do i need to create a new method and filter it there or can i use something BEFORE the ForEach Loop?
Pseudo like:
$children = $this->productRepository->findByParent($product->getNumber());
ObjectSortFunction($children, 'getvalidityPeriod');
...and then for each...
Would be awesome if somebody would help me!
Okay after several tries i have a workaround, that can be used as answer, as well ;)
I wrote this method in my repo:
public function findByParentSorted($parentId)
{
$query = $this->createQuery();
$query->matching($query->equals('parent', $parentId));
$query->setOrderings(
[
'validity_period' => \TYPO3\CMS\Extbase\Persistence\QueryInterface::ORDER_ASCENDING
]
);
return $query->execute();
}

zf2 When I do addFeature(new Feature\SequenceFeature,...) for Postgres PDO, insert fails because columns and values are nulled out

I'm in Zend Framework 2, trying to get the last inserted id after inserting using postgresql PDO. The insert works fine unless I add a SequenceFeature, like this:
class LogTable extends AbstractTableGateway
{
protected $table = 'log';
public function __construct(Adapter $adapter)
{
$this->adapter = $adapter;
$this->featureSet = new Feature\FeatureSet();
$this->featureSet->addFeature(new Feature\SequenceFeature('id','log_id_seq'));
$this->resultSetPrototype = new ResultSet();
$this->resultSetPrototype->setArrayObjectPrototype(new Log());
print_r($this->getFeatureSet());
$this->initialize();
}
When I later do an insert like this:
$this->insert($data);
It fails, because INSERT INTO "log" () VALUES (), so for some reason zf2 is nulling out the columns and values to insert, but only if I add that SequenceFeature.
If I don't add that feature, the insert works fine, but I can't get the last sequence value. Debugging the Zend/Db/Sql/Insert.php, I found that the values function is accessed twice with the SequenceFeature in there, but only once when it's not in there. For some reason when the SequenceFeature is there, all the insert columns and values are nulled out, possibly because of this double call? I haven't investigated further yet, but maybe it's updating the sequence and then losing the data when making the insert?
Is this a bug, or is there just something I'm missing?
Screw it! We'll do it live!
Definitely not the best solution, but this works. I just cut and pasted the appropriate code from Zend/Db/TableGateway/Feature/SequenceFeature.php and added it as a function to my LogTable class:
public function nextSequenceId()
{
$sql = "SELECT NEXTVAL('log_id_seq')";
$statement = $this->adapter->createStatement();
$statement->prepare($sql);
$result = $statement->execute();
$sequence = $result->getResource()->fetch(\PDO::FETCH_ASSOC);
return $sequence['nextval'];
}
Then I called it before my insert in my LogController class:
$data['id'] = $this->nextSequenceId();
$id = $this->insert($data);
Et voila! Hopefully someone else will explain to me how I'm really supposed to do it, but this will work just fine in the interim.

Zend framework 1.11 Gdata Spreadsheets insertRow very slow

I'm using insertRow to populate an empty spreadsheet, it starts off taking about 1 second to insert a row and then slows down to around 5 seconds after 150 rows or so.
Has anyone experienced this kind of behaviour?
There aren't any calculations on the data in the spreadsheet that could be getting longer with more data.
Thanks!
I'll try to be strict.
If you take a look at class "Zend_Gdata_Spreadsheets" you figure that the method insertRow() is written in a very not optimal way. See:
public function insertRow($rowData, $key, $wkshtId = 'default')
{
$newEntry = new Zend_Gdata_Spreadsheets_ListEntry();
$newCustomArr = array();
foreach ($rowData as $k => $v) {
$newCustom = new Zend_Gdata_Spreadsheets_Extension_Custom();
$newCustom->setText($v)->setColumnName($k);
$newEntry->addCustom($newCustom);
}
$query = new Zend_Gdata_Spreadsheets_ListQuery();
$query->setSpreadsheetKey($key);
$query->setWorksheetId($wkshtId);
$feed = $this->getListFeed($query);
$editLink = $feed->getLink('http://schemas.google.com/g/2005#post');
return $this->insertEntry($newEntry->saveXML(), $editLink->href, 'Zend_Gdata_Spreadsheets_ListEntry');
}
In short, it loads your whole spreadsheet just in order to learn this value $editLink->href in order to post new row into your spreadsheet.
The cure is to avoid using this method insertRow.
Instead, get your $editLink->href once in your code and then insert new rows each time by reproducing the rest of behaviour of this method. I.e, in your code instead of $service->insertRow() use following:
//get your $editLink once:
$query = new Zend_Gdata_Spreadsheets_ListQuery();
$query->setSpreadsheetKey($key);
$query->setWorksheetId($wkshtId);
$query->setMaxResults(1);
$feed = $service->getListFeed($query);
$editLink = $feed->getLink('http://schemas.google.com/g/2005#post');
....
//instead of $service->insertRow:
$newEntry = new Zend_Gdata_Spreadsheets_ListEntry();
$newCustomArr = array();
foreach ($rowData as $k => $v) {
$newCustom = new Zend_Gdata_Spreadsheets_Extension_Custom();
$newCustom->setText($v)->setColumnName($k);
$newEntry->addCustom($newCustom);
}
$service->insertEntry($newEntry->saveXML(), $editLink->href, 'Zend_Gdata_Spreadsheets_ListEntry');
Don't forget to encourage this great answer, it costed me few days to figure out. I think ZF is great however sometimes you dont want to rely on their coode too much when it comes to resources optimization.

zend framework 1.11.5 is choking on search function - mysql db

ZF 1.11.5 is puking all over this search function. i've tried creating the query several different ways, sent the sql statement to my view, copied and pasted the sql statement into phpMyAdmin and successfully retrieved records using the sql that ZF is choking on. i have been getting a coupld of different errors: 1) an odd SQL error about 'ordinality' (from my Googling ... it seems this is a ZF hang up .. maybe?) and 2) Fatal error: Call to undefined method Application_Model_DbTable_Blah::query() in /blah/blah/blah.php on line blah
public function searchAction($page=1)
{
$searchForm = new Application_Model_FormIndexSearch();
$this->view->searchForm = $searchForm;
$this->view->postValid = '<p>Enter keywords to search the course listings</p>';
$searchTerm = trim( $this->_request->getPost('keywords') );
$searchDb = new Application_Model_DbTable_Ceres();
$selectSql = "SELECT * FROM listings WHERE `s_coursedesc` LIKE '%".$searchTerm."%' || `s_title` LIKE '%".$searchTerm."%'";
$selectQuery = $searchDb->query($selectSql);
$searchResults = $selectQuery->fetchAll();
}
here's my model ....
class Application_Model_DbTable_Ceres extends Zend_Db_Table_Abstract
{
protected $_name = 'listings';
function getCourse( $courseId )
{
$courseid = (int)$courseId;
$row = $this->fetchRow('id=?',$courseId);
if (!$row)
throw new Exception('That course id was not found');
return $row->toArray();
}
}
never mind the view file ... that never throws an error. on a side note: i'm seriously considering kicking ZF to the curb and using CodeIgniter instead.
looking forward to reading your thoughts. thanks ( in advance ) for your responses
You're trying to all a method called query() on Zend_Db_Table but no such method exists. Since you have built the SQL already you might find it easier to call the query on the DB adapter directly, so:
$selectSql = "SELECT * FROM listings WHERE `s_coursedesc` LIKE '%".$searchTerm."%' || `s_title` LIKE '%".$searchTerm."%'";
$searchResults = $selectQuery->getAdapter()->fetchAll($selectSql);
but note that this will give you arrays of data in the result instead of objects which you might be expecting. You also need to escape $searchTerm here since you are getting that value directly from POST data.
Alternatively, you could form the query programatically, something like:
$searchTerm = '%'.$searchTerm.'%';
$select = $selectQuery->select();
$select->where('s_coursedesc LIKE ?', $searchTerm)
->orWhere('s_title LIKE ?', $searchTerm);
$searchResults = $searchQuery->fetchAll($select);

Zend_Db - Building a Delete Query

I'm trying to recreate the following in Zend Framework and am not sure how to do it:
DELETE FROM mytablename WHERE date( `time_cre` ) < curdate( ) - INTERVAL 4 DAY
I was thinking something like:
$table = $this->getTable();
$db = Zend_Registry::get('dbAdapter');
$db->delete($table, array(
'date(`time_cre`) < curdate() - interval 4'
));
Does that seem correct?
What is the best way to handle something like this?
EDIT: Ack! Sorry, I was adapting this from a SELECT I was using to test and didn't change the syntax properly when I pasted it in. I've edited the example to fix it.
Figured it out...
public function pruneOld($days) {
$table = $this->getTable();
$db = Zend_Registry::get('dbAdapter');
$where = $db->quoteInto("DATE(`time_cre`) < CURDATE() - INTERVAL ? DAY", $days);
return $table->delete($where);
}
$table gets an reference of the table I want to edit...
$db grabs an instance of the database adapter so I can use quoteInto()...
$where builds the main part of the query accepting $days to make things a bit more flexible.
Create an action to call this method... something like:
public function pruneoldAction() {
// Disable the view/layout stuff as I don't need it for this action
$this->_helper->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
// Get the data model with a convenience method
$data = $this->_getDataModel();
// Prune the old entries, passing in the number of days I want to be older than
$data->pruneOld(2);
}
And now hitting: http://myhost/thiscontroller/pruneold/ will delete the entries. Of course, anyone hitting that url will delete the entries but I've taken steps not included in my example to deal with this. Hope this helps someone.
I usually do this to delete a row
$table = new yourDB;
$row = $table->fetchRow($table->select()->where(some where params));
$row->delete();
try:
$db->delete($table, array(
'date(time_cre) < ?' => new Zend_Db_Expr('curdate() - interval 4')
));