How can i write a query that returns all objects except a given one? - typo3-flow

im trying to write a simple query that would be easy if i had access to the persistence_object_identifier. I kickstarted my models and so i dont have them.
What i want to do is:
function getAllExcept($obj){
$query = $this->createQuery();
$query->matching(
$query->logicalNot(
$query->equals('persistence_object_identifier', $obj)
)
);
return $query->execute();
}
I tried a lot but i cannot make it work.
I could easily call ->toArray() and filter the one object out, but the fluid pagination widget needs the QueryResultInterface...

The property's name is Persistence_Object_Identifier (mind the case). It is injected by AOP in https://git.typo3.org/Packages/TYPO3.Flow.git/blob/HEAD:/Classes/TYPO3/Flow/Persistence/Aspect/PersistenceMagicAspect.php#l58.

replace
$query->equals('persistence_object_identifier', $obj);
with
$query->equals('Persistence_Object_Identifier', $obj);
It will work.

Related

PagedResultList .size() and .getTotalCount() return different values in grails gorm

I have the following code
PagedResultList res = myService.getPage(paginateParams, ...)
println res.size() // returns 2
println res.getTotalCount() // returns 1
getPage looks like:
def criteria = MyDomain.createCriteria()
criteria.list(max: paginateParams.max, offset: paginateParams.offset) { // max is 10, offset is 0, sortBy is updatedAt and sortOrder is desc
eq('org', org)
order(paginateParams.sortBy, paginateParams.sortOrder)
}
why do the two method return different values? The documentation doesn't explain the difference, but does mention that getTotalCount is for number of records
currently on grails 2.4.5
edits:
println on res prints out:
res: [
com.<hidden>.MyDomain: 41679f98-a7c5-4193-bba8-601725007c1a,
com.<hidden>.MyDomain: 41679f98-a7c5-4193-bba8-601725007c1a]
Yes, res has a SINGLE object twice - that's the bug I'm trying to fix. How do I know that? I have an primary key on MyDomain's ID, and when I inspect the database, it's also showing one record for this particular org (see my criteria)
edit 2: I found this comment (http://docs.grails.org/2.4.5/ref/Domain%20Classes/createCriteria.html)
listDistinct If subqueries or associations are used, one may end up
with the same row multiple times in the result set. In Hibernate one
would do a "CriteriaSpecification.DISTINCT_ROOT_ENTITY". In Grails one
can do it by just using this method.
Which, if I understand correctly, is their way of saying "list" method doesn't work in this scenario, use listDistinct instead but then they go on to warn:
The listDistinct() method does not work well with the pagination
options maxResult and firstResult. If you need distinct results with
pagination, we currently recommend that you use HQL. You can find out
more information from this blog post.
However, the blog post is a dead link.
Related: GORM createCriteria and list do not return the same results : what can I do?
Not related to actual problem after question edited but this quote seems useful
Generally PagedResultList .size() perform size() on resultList property (in-memory object represent database record), while .getTotalCount() do count query against database. If this two value didn't match your list may contain duplicate.
After viewing related issues (GORM createCriteria and list do not return the same results : what can I do?) I determined that there were several approaches:
Use grails projection groupBy('id') - doesn't work b/c i need the entire object
USe HSQL - Domain.executeQuery - actually this didn't work for my scenario very well because this returns a list, whereas criteria.list returns a PagedResultList from which I previously got totalCount. This solution had me learning HSQL and also made me break up my existing logic into two components - one that returned PagedResultList and one that didn't
Simply keep a set of IDs as I process my PagedResultList and make sure that I didn't have any duplicates.
I ended up going with option 3 because it was quick, didn't require me to learn a new language (HSQL) and I felt that I could easily write the code to do it and I'm not limited by the CPU to do such a unique ID check.

How can I match with the persistent_object_identifier?

Is there a way to use the query interface and limit the repository query by the persistent object identifier? Like ...
// $addTaskIds is an array with identifiers as strings
$query = $this->createQuery();
$query->matching(
$query->logicalOr(
$query->like('title', '%'.$searchstring.'%'),
$query->like('description', '%'.$searchstring.'%'),
$query->in('persistent_object_identifier', $addTaskIds)
)
);
return $query->execute();
I've tried the code above and it doesn't work. Did I forgot something? Does the query builder offer that anyway? Do I have to switch on a yaml setting?
The idea was good. But the table row persistent_object_identifier doesn't belong to the object itself. You can however use Persistence_Object_Identifier.
For that you need the identifiers as strings not as whole objects. And make sure that the second parameter of 'query in' is an array not a single string.

Hydrating Database

I am new to learning and understanding how Hydration works, just wanted to point that out first. I'm currently able to Hydrate Select and Insert queries without any problems.
I am currently stuck on trying to Hydrate Update queries now. In my entity I have setup the get/set options for each type of column in my database. I've found that the ObjectProperty() Hydrator works best for my situation too.
However whenever I try to update only a set number of columns and extract via the hydrator I am getting errors because all the other options are not set and are returning null values. I do not need to update everything for a particular row, just a few columns.
For example in my DB Table I may have:
name
phone_number
email_address
But I only need to update the phone_number.
$entity_passport = $this->getEntityPassport();
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => '1'
));
This returns an error because setName() and setEmailAddress() are not included in this update and the query returns that the values cannot be null. But clearly when you look at the DB Table, there is data already there. The data that is there does not need to be changed either, only in this example does the PrimaryPhone() number.
I've been looking and reading documentation all over the place but I cannot find anything that would explain what I am doing wrong. I should note that I am only using Zend\Db (Not Doctrine).
I'm assuming I've missed something someplace due to my lack of knowledge with this new feature I'm trying to understand.
Perhaps you don't Hydrate Update queries... I'm sort of lost / confused. Any help would be appreciated. Thank you!
I think you're having a fundamental misconception of hydration. A hydrator simply populates an entity object from data (hydrate) and extracts data from an entity object (extract). So there are no separate hydrators for different types of queries.
In your update example you should first retrieve the complete entity object ($entity_passport) and then pass it to the TableGateway's update method. You would retrieve the entity by employeeid, since that's the condition you're using to update. So something like this:
$entity_passport = $passportMapper->findByEmployeeId(1);
$entity_passport->setPrimaryPhone('5551239876');
$this->getTablePassport()->update($this->getHydrator()->extract($entity_passport), array(
'employeeid' => $entity_passport->getId()
));
This is assuming you have some sort of mapper layer. Otherwise you could use your passport TableGateway (I assume that's what getTablePassport() returns, no?).
Otherwise, if you think retrieving the object is too much overhead and you just want to run the query you could use just a \Zend\Db\Sql\Sql object, ie:
$sql = new \Zend\Db\Sql\Sql($dbAdapter);
$update = $sql->update('passport')
->set(array('primary_phone' => $entity_passport->getPrimaryPhone()))
->where(array('employeeid' => $employeeId));
Edit:
Maybe it was a mistake to bring up the mapper, because it may cause more confusion. You could simply use your TableGateway to retrieve the entity object and then hydrate the returned row:
$rows = $this->getTablePassport()->select(array('employeeid' => 1));
$entity_passport = $this->getHydrator($rows->current());
[...]
Edit 2:
I checked your gist and I noticed a few things, so here we go:
I see that your getTablePassport indeed does return an object which is a subclass of TableGateway. You have already set up this class for it to use a HydratingResultset. This means you don't need to do any manual hydrating when retrieving objects using the gateway.
You also already implemented a Search method in that same class, so why not just use that? However I would change that method, because right now you're using LIKE for every single column. Not only is it very inefficient, but it will also give you wrong results, for example on the id column.
If you were to fix that method then you can simply call it in the Service object:
$this->getTablePassport->Search(array('employeeid' => 1));
Otherwise you could just implement a separate method in that tablegateway class, such as
public function findByEmployeeId($employeeId)
{
return $tableGateway->select(array('employeeid' => $employeeId));
}
This should already return an array of entities (or one in this specific case). P.S. make sure to debug and check what is actually being returned when you retrieve the entity. So print_r the entity you get back from the PassportTable before trying the update. You first have to make sure the retrieval code works well.

CRUD approach practice

Following many tutorials from official and non-official docs, there is no such a clear vision for common approach for creating editing the entity and updating just specific fields.
The main questions are:
1 - Create the entity - fill the form, validate, create entity object and populate it with exchangeArray and then save, in save method via docs we must configure an array from passed object like:
$data = array(
'artist' => $album->artist,
'title' => $album->title,
);
Can we avoid this array re-configuring in save method?
2 - Update the entity - same logic
3 - What if we want to update only one specific field?
I pass the array to updateEntity method, but is it normal way to pass object(and configure array inside method) to save method and pass array to update method?
4 - Almost same thing with 3 but issue now when we have an array with another keys among our entity fields keys, we can strip 'bad' array keys using hydrator and make something like array_intersect style, but what you suggest?
You can use a smart combination of your entity, form, input filter and hydrator to have almost no logic to get CRUD things done. For an admin interface I usually generate my controller, form and other classes. I use Sublime Text 2 and the snippets to generate these classes can be found in my repository.
This results in:
A controller with index (listing), view (single item), create, update and delete
A form to contain all entity fields
A repository (Doctrine) to query entities
A service to persist to the database (either create one, save one or delete one)
This will solve #1 and #2. Due to the way ZF2 filtering and hydration works, this will also solve #4 for you. Then, it is possible to set only a select no. of fields to be filtered, but I have not implemented that (yet). I can only refer to the manual to know how to do that.
If you want to know the implementation of above snippets, take a look at Soflomo\Portfolio which uses a similar strategy.
PHP, contrary to other languages, is array centric than object centric. Most task could be done via Array. In this case, instead of use
<?php
class SomeClass {
public $artist;
public $title;
}
$album=new SomeClass();
$data = array(
'artist' => $album->artist,
'title' => $album->title,
);
?>
We should use
<?
$SomeObject=array("artist"=>xxx,"title"=>xxxx);
$data = $someObject;
?>
i.e. we should avoid to use classes when we are referencing a POCO class and instead we should use the (less elegant) array. Otherwise, sometimes we will be forced to do such conversion between array and object.
Anyways i we will need to keep it as a object then, we can do the conversion between object to array using:
<?php
class SomeClass {
public $artist;
public $title;
}
$album=new SomeClass();
$data = (array)$album;
?>
However, this conversion sometimes is tricky.

how to set Personalizable attribute to generic list in webpart?

I develop web part with custom editor part and faced with this question.
Is it possible in web part set Personalizable attribute to generic List?
For example I want something like this:
[WebBrowsable(false)]
[Personalizable(PersonalizationScope.Shared)]
public List<AnnouncementItem> Announcements
{
get { return _announcements; }
set { _announcements = value; }
}
Is it possible, and what kind of types at all can be used as "Personalizable"?
Thanks.
Solution:
I use a custom EditorPart to select multiple lists using AssetUrlSelector, but I need a way to personalize this collection for end user.List<of custom objects> doesn't work, but I found that List<string> (and only string) work perfectly. So, I get required lists in EditorPart and pass their to the web part using List<string>.
Try using a custom EditorPart to add/remove items from the collection. I've never built a web part that personalized a collection so I don't know if it works but I'd definitely try the collection with an EditorPart. If it doesn't work, serialize XML into a string property.
Your question does not seem to match your code. Your code shows a collection of custom objects. I doubt an end user will be able to set such a property. To have a property that points to a generic list, you would probably be better off defining the property as a string that contains the URL to a list.

Resources