Zend Framework - fetchAll returns fatal error when it has no rows returned? - zend-framework

I know that when I try top use fetchAll and it returns a fatal error, the reason is because it has returned no records on the query. But my question is, how to treat it? How can I know if the query will not return any records, so i do not use toArray()?
For instance,
$table = new Application_Model_Proucts();
$products = $table->fetchAll()->toArray();
How can I do a verification of the query before I put the toArray method?

If there are no records returned from fetchAll() then you are passing nothing to toArray(), which is where the error is occurring.
Try wrapping the last but of your code in an if statement:
$products = $table->fetchAll();
if(count($products))
{
$products = $products->toArray();
}

wrap your query in a condition and/or throw a new exception when condition isn't met

Related

Hibernate Search 6 Scrollable returning results in a strange way

Since we upgraded from Hibernate Search 5.11 to Hibernate Search 6 we are having problems with Scrollable results
When we get a chunk of hits from the SearchScroll object each hit is stored in an Arrays.ArrayList
What we expected is that each chunk hits would be an ArrayList of say for example of type long
What we get is an ArrayList where where each hit is an Arrays.ArrayList with the Long value
Current code
SearchScroll scroll = searchSession
.search(scope)
.select(projectionArray)
.where(searchPredicate)
.sort(getSort(resultType))
.scroll(20);
Old code with Hibernate Search 5
FullTextQuery fullTextQuery = fullTextSession
.createFullTextQuery(query, resultType)
.setSort(getSort(resultType));
fullTextQuery.setProjection(fields);
ScrollableResults scrollableResults = fullTextQuery.scroll();
Any suggestions welcome
At worst we can loop through the results and convert the Arrays.ArrayList item to a long but cannot find a way to make that work either
The acual search results are correct just coming back in a different format that what we expect
Changing the code to
SearchScroll<Long> scroll = searchSession
.search(scope)
.select(projectionArray)
.where(searchPredicate)
.sort(getSort(resultType))
.scroll(20);
Makes no difference which seems to match the example in the docs
try ( SearchScroll<Book> scroll = searchSession.search(
Book.class )
.where( f -> f.matchAll() )
.scroll( 20 ) ) {
for ( SearchScrollResult<Book> chunk = scroll.next();
chunk.hasHits(); chunk = scroll.next() ) {
for ( Book hit : chunk.hits() ) {
// ... do something with the hits ...
}
totalHitCount = chunk.total().hitCount();
entityManager.flush();
entityManager.clear();
}
}
Not sure if the projection is what is causing the problem
Tested further if I remove the projection I get the results as an ArrayList of the object as expected so obviously I am doing something wrong with the use of projections in Hibernate Search 6
Without projection everything is good
With projection the results are Arrays.ArrayList
If I understand correctly, you are surprised that you get a List for each hit instead of just a Long.
First, I would recommend that you don't ignore raw type warnings.
I'll wager that your projectionArray is defined this way:
SearchProjection[] projectionArray = new SearchProjection[1];
That's wrong because you're using a "raw" type for SearchProjection, which basically disables all kinds of type-checking for all the code afterwards.
The correct way of defining that array is as follows:
SearchProjection<?>[] projectionArray = new SearchProjection<?>[1];
If you do that, then you'll get a compile-time error with the following code, telling you something like "cannot convert SearchScroll<List<?>> to SearchScroll<Long>":
SearchScroll<Long> scroll = searchSession
.search(scope)
.select(projectionArray)
.where(searchPredicate)
.sort(getSort(resultType))
.scroll(20);
Now, the reason you're getting a SearchScroll<List<?>> is you're passing an array of projections to .select(), so you're calling this method from SearchQuerySelectStep:
SearchQueryWhereStep<?, List<?>, LOS, ?> select(SearchProjection<?>... projections);
This method takes an array of projections as an argument, and (ultimately) returns a query whose hits are lists, with the results of requested projections in the same order as your array of projections.
You want to call that method instead:
<P> SearchQueryWhereStep<?, P, LOS, ?> select(SearchProjection<P> projection);
That method takes a single projection as an argument, and (ultimately) returns a query whose hits are directly the result of the requested projection.
To call that method, pass a single projection instead of an array of projections; then you will get the Long values you expect instead of Lists:
SearchProjection<Long> projection = ...;
SearchScroll<Long> scroll = searchSession
.search(scope)
.select(projection)
.where(searchPredicate)
.sort(getSort(resultType))
.scroll(20);

Laravel: BadMethodCallException with message 'Method update does not exist.'

When I try to update a model with this code:
public function updateMixedtape($slug, Request $request)
{
$mix = Mix::where('slug', $slug)->get();
$mix->update($request->all());
return redirect('dashboard/mixes');
}
I get an error that method update doesn't exist. However if I modify my view to send a radio_show_id instead of slug and try to change the code to something like this:
public function updateMixedtape(Request $request)
{
$mix = Mix::findOrFail($request->radio_show_id);
$mix->update($request->all());
return redirect('dashboard/mixes');
}
The code executes without any errors.
What puzzles me is that if I do something like return $mix; before the line where I call the update method, I get similar data for both methods.
As shock_gone_wild has suggested in the comment section of my question $mix = Mix::where('slug', $slug)->get(); is returning a collection and not a model. This is because a Model::where() method can return zero, one or many records depending on whether or not there are records that meet the set condition.
As suggested I used $mix = Mix::where('slug', $slug)->first(); instead to get the first record that meets the condition.

using unset in CakePHP MongoDB

I am using Ichikawa CakePHP MongoDB plugin. I have a problem in using unset in it. I have tried the command in shell:
db.patents.update({}, {$unset : {"lv.2" : 1 }},{'multi':true})
db.patents.update({},{$pull:{pid:"2"}},{'multi':true})
These are working fine.
But when I am converting them to CakePHP command as follows:
$this->Detail->updateAll(array('$unset'=>array('lv.2'=>1,array('multi'=>true))));
Then it doesn't work and gives error:
MongoCollection::update(): expects parameter 1 to be an array or object, boolean given
Can anyone help me to figure out the problem.
Thanks.
There are no conditions
The error message means that the query being generated is the equivalent of:
db.details.update(true
This can be confirmed by checking the query log (easy if you're using debug kit).
How is that happening
The second parameter for model updateAll is missing, which means it will have the default:
public function updateAll($fields, $conditions = true) {
^
return $this->getDataSource()->update($this, $fields, null, $conditions);
}
Therefore in the mongodb datasource class - the conditions passed are true:
public function updateAll(&$Model, $fields = null, $conditions = null) {
^
As a consequence, the resultant update statement has true as the first parameter, not an array.
Correct syntax
The correct syntax for such a query is:
$this->Detail->updateAll(
array('$unset'=>array('lv.2'=>1))
array() # <- do not omit this
);
Note that it's not necessary to specify 'multi'=>true as the datasource does that for you, especially not in the fields argument.

Zend_Framework 1.12 SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax

Before anything I am aware of the multiple questions asked concerning this exception. I have looked through them but have not found an answer for my particular problem. Most of the questions use the Zend_Db_Table::getDefaultAdapter(); , and I am not using that. Instead I am using an Application_Model_DbTable_Name and am left wondering if it´s possible to do so.
Also, I do have access since that´s the first thing I checked when I saw the error. The database is local and I access it with the same user/password through MySqlWorkBench.
My goal is to delete a row when two columns meet the criteria set in the controller action, like so:
public function deleteAction(){
$request = $this->getRequest();
$this->_validateDigit($request->getParam('id'));
// _validateDigit(..) checks that the variable is numeric and if it´s not it redirects to
// an error page
$db = new Application_Model_DbTable_BecasPerfiles();
$select = $db->select();
$select->where('unidad=?', $this->_getUnit())
->where('id=?', (int) $request->getParam('id'));
$db->delete($select->getPart(Zend_Db_Select::WHERE));
$this->_redirect('/profile/view-profiles/unit/'.$this->_getUnit());
}
private function _getUnit()
{
return Zend_Registry::getInstance()['session']->unit;
//unit is nothing but a string
}
Here is my DbTable class (real simple):
class Application_Model_DbTable_BecasPerfiles extends Zend_Db_Table_Abstract
{
protected $_name = 'becas_perfiles';
}
Here is the error that spits out:
Message: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in
your SQL syntax; check the manual that corresponds to your MySQL server version for
the right syntax to use near 'AND (id=7))' at line 1
Here is what calls my attention AND (id=7)), see the extra parenthesis? where is that coming from?
Here is the result of var_dump($select->getPart(Zend_Db_Select::WHERE));
array(2) { [0]=> string(33) "(unidad='Galería de Arte ULPGC')" [1]=> string(10) "AND (id=7)" }
Just for the fun of it, I tried switching the order of the where clause:
$select->where('id=?', (int) $request->getParam('id'))
->where('unidad=?', $this->_getUnit());
Here is the output:
Message: SQLSTATE[42000]: ...
syntax to use near 'AND (unidad='Galería de Arte ULPGC'))' at line 1
There it is again, AND (unidad='Galería de Arte ULPGC')) that second parenthesis. I don´t really know if that´s the problem (but I figure it is because otherwise I don´t know what could posssibly be wrong).
I tried just using one where condition (like id), and it deleted just fine. I´d really appreciate your help, thank you!
The problem here is that there is a mismatch between what getPart() returns and what delete() expects.
As you already pointed out, var_dump($select->getPart(Zend_Db_Select::WHERE)); also returns the logical operators in the where statement, but the delete() operator either expects an array in the form "field => value" or a string containing the full where clause.
So the simplest (untested) approach to fix your problem would be to pass $db->delete(implode(' ', $select->getPart(Zend_Db_Select::WHERE))); so that delete() receives a fully qualified where clause as string instead of an array it cannot handle.

findManyToManyRowset with Zend_Db_Table_Select

I'm trying to use a select object to filter the results of a many to many rowset. This call works great:
$articles = $this->model->findArticlesViaArticlesUsers();
This however does not:
$articles = new Default_Model_Articles();
$articleSelect = $articles->select();
$articleSelect->where("status = 'published'")
->order("date_published DESC")
->limit(1);
$articles = $this->model->findArticlesViaArticlesUsers($articleSelect);
That throws the following error:
exception 'Zend_Db_Select_Exception'
with message 'You cannot define a
correlation name 'i' more than once'
I can't figure out how to successfully get "articles that have the status of 'published'" using the magic many-to-many relationship (nor findManyToManyRowset). I'm at the end of my rope and thinking of just writing the sql manually. Any ideas?
When defining the select statement, you must use the same object that you call findManyToManyRowset (or whatever magic function you use) on.
Ex:
$articles = new Default_Model_Articles();
$user = $articles->find($userId)->current();
$select = $user->select();
$select->where('status = ?', 'published');
$articles = $user->findArticlesViaArticlesUsers($select);
Notice the select statement and findArticlesViaArticlesUsers are both extending $user. Thats the key.
I think you've misunderstood how the relationships work.
See this manual page - you should call the magic method, findArticlesViaArticlesUsers, on a Row object. In this case, I think you want to find a User, and then call findArticles... on that.