Retrieving every field of a database row as object in zend framework 2 - database

I know we have result set to get a row as object But How can I get every field as a separate object ? consider of this database row :
user_id address_id product_id shop_id
5 3 134 2
I want to retrieve and save the row as follows :
userEntity AddressEntity ProductEntity ShopEntity

This is not how the TableDataGateway is supposed to be used, since what you are looking for are more complex features such as the ones of Doctrine 2 ORM and similar data-mappers.
Here is one possible solution to the problem, which involves using a custom hydrator (docs). My example is simplified, but I hope it clarifies how you are supposed to build your resultset.
First, define your entities (I'm simplifying the example assuming that UserEntity is the root of your hydration):
class UserEntity {
/* fields public for simplicity of the example */
public $address;
public $product;
public $shop;
}
class AddressEntity { /* add public fields here for simplicity */ }
class ProductEntity { /* add public fields here for simplicity */ }
class ShopEntity { /* add public fields here for simplicity */ }
Then, build hydrators specific for the single entities:
use Zend\Stdlib\Hydrator\HydratorInterface as Hydrator;
class AddressHydrator implements Hydrator {
// #TODO: implementation up to you
}
class ProductHydrator implements Hydrator {
// #TODO: implementation up to you
}
class ShopHydrator implements Hydrator {
// #TODO: implementation up to you
}
Then we aggregate these hydrators into one that is specifically built to hydrate a UserEntity:
class UserHydrator extends \Zend\Stdlib\Hydrator\ObjectProperty {
public function __construct(
Hydrator $addressHydrator,
Hydrator $productHydrator,
Hydrator $shopHydrator
) {
$this->addressHydrator = $addressHydrator;
$this->productHydrator = $productHydrator;
$this->shopHydrator = $shopHydrator;
}
public function hydrate(array $data, $object)
{
if (isset($data['address_id'])) {
$data['address'] = $this->addressHydrator->hydrate($data, new AddressEntity());
}
if (isset($data['product_id'])) {
$data['product'] = $this->productHydrator->hydrate($data, new ProductEntity());
}
if (isset($data['shop_id'])) {
$data['shop'] = $this->shopHydrator->hydrate($data, new ShopEntity());
}
return parent::hydrate($data, $object);
}
}
Now you can use it to work with your resultset. Let's define the service for your UserEntityTableGateway:
'UserEntityTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new UserHydrator());
return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
},
These are all simplified examples, but they should help you understanding how powerful hydrators can be, and how you can compose them to solve complex problems.
You may also check the chapters in the documentation about the Aggregate Hydrator and Hydration Strategies, which were designed specifically to solve your problem.

Related

Unable to Correctly Serialize RangeSet<Instant> with Flink Serialization System

I've implemented a RichFunction with following type:
RichMapFunction<GeofenceEvent, OutputRangeSet>
the class OutputRangeSet has a field of type:
com.google.common.collect.RangeSet<Instant>
When this pojo is serialized using Kryo I get null fields !
So far, I tried using a TypeInfoFactory<RangeSet>:
public class InstantRangeSetTypeInfo extends TypeInfoFactory<RangeSet<Instant>> {
#Override
public TypeInformation<RangeSet<Instant>> createTypeInfo(Type t, Map<String, TypeInformation<?>> genericParameters) {
TypeInformation<RangeSet<Instant>> info = TypeInformation.of(new TypeHint<RangeSet<Instant>>() {});
return info;
}
}
That annotate my field:
public class OutputRangeSet implements Serializable {
private String key;
#TypeInfo(InstantRangeSetTypeInfo.class)
private RangeSet<Instant> rangeSet;
}
Another solution (that doesn't work either) is registring a third party serializer:
env.getConfig().registerTypeWithKryoSerializer(RangeSet.class, ProtobufSerializer.class);
You can get the github project here:
https://github.com/elarbikonta/tonl-events
When you run the test you can see (in debug) that the rangeSet beans I get from my RichFunction has null fields, see test method com.tonl.apps.events.IsVehicleInZoneTest#operatorChronograph :
final RangeSet<Instant> rangeSet = resultList.get(0).getRangeSet(); // rangetSet.ranges = null !
Thanks for your help

Salesforce : Apex test class for the getting trending articles of Knowledge from Community

I need to get trending articles from the community. I created a apex class for that by using ConnectApi.Knowledge.getTrendingArticles(communityId, maxResult).
I need to create a test class for that. I am using test class method provided by Salesforce for that. setTestGetTrendingArticles(communityId, maxResults, result) but I am getting this error "System.AssertException: Assertion Failed: No matching test result found for Knowledge.getTrendingArticles(String communityId, Integer maxResults). Before calling this, call Knowledge.setTestGetTrendingArticles(String communityId, Integer maxResults, ConnectApi.KnowledgeArticleVersionCollection result) to set the expected test result."
public without sharing class ConnectTopicCatalogController {
#AuraEnabled(cacheable=true)
public static List<ConnectApi.KnowledgeArticleVersion> getAllTrendingArticles(){
string commId = [Select Id from Network where Name = 'Customer Community v5'].Id;
ConnectApi.KnowledgeArticleVersionCollection mtCollection = ConnectApi.Knowledge.getTrendingArticles(commId, 12);
System.debug('getAllTrendingTopics '+JSON.serializePretty(mtCollection.items));
List<ConnectApi.KnowledgeArticleVersion> topicList = new List<ConnectApi.KnowledgeArticleVersion>();
for(ConnectApi.KnowledgeArticleVersion mtopic : mtCollection.items)
{
topicList.add(mtopic);
}
return topicList;
}
}
Test class that I am using for this
public class ConnectTopicCatalogControllerTest {
public static final string communityId = [Select Id from Network where Name = 'Customer Community v5'].Id;
#isTest
static void getTrendingArticles(){
ConnectApi.KnowledgeArticleVersionCollection knowledgeResult = new ConnectApi.KnowledgeArticleVersionCollection();
List<ConnectApi.KnowledgeArticleVersion> know = new List<ConnectApi.KnowledgeArticleVersion>();
know.add(new ConnectApi.KnowledgeArticleVersion());
know.add(new ConnectApi.KnowledgeArticleVersion());
system.debug('know '+know);
knowledgeResult.items = know;
// Set the test data
ConnectApi.Knowledge.setTestGetTrendingArticles(null, 12, knowledgeResult);
List<ConnectApi.KnowledgeArticleVersion> res = ConnectTopicCatalogController.getAllTrendingArticles();
// The method returns the test page, which we know has two items in it.
Test.startTest();
System.assertEquals(12, res.size());
Test.stopTest();
}
}
I need help to solve the test class
Thanks.
Your controller expects the articles to be inside the 'Customer Community v5' community, but you are passing the communityId parameter as null to the setTestGetTrendingArticles method.

Populating a table from a file only last column is populated JavaFX [duplicate]

This has baffled me for a while now and I cannot seem to get the grasp of it. I'm using Cell Value Factory to populate a simple one column table and it does not populate in the table.
It does and I click the rows that are populated but I do not see any values in them- in this case String values. [I just edited this to make it clearer]
I have a different project under which it works under the same kind of data model. What am I doing wrong?
Here's the code. The commented code at the end seems to work though. I've checked to see if the usual mistakes- creating a new column instance or a new tableview instance, are there. Nothing. Please help!
//Simple Data Model
Stock.java
public class Stock {
private SimpleStringProperty stockTicker;
public Stock(String stockTicker) {
this.stockTicker = new SimpleStringProperty(stockTicker);
}
public String getstockTicker() {
return stockTicker.get();
}
public void setstockTicker(String stockticker) {
stockTicker.set(stockticker);
}
}
//Controller class
MainGuiController.java
private ObservableList<Stock> data;
#FXML
private TableView<Stock> stockTableView;// = new TableView<>(data);
#FXML
private TableColumn<Stock, String> tickerCol;
private void setTickersToCol() {
try {
Statement stmt = conn.createStatement();//conn is defined and works
ResultSet rsltset = stmt.executeQuery("SELECT ticker FROM tickerlist order by ticker");
data = FXCollections.observableArrayList();
Stock stockInstance;
while (rsltset.next()) {
stockInstance = new Stock(rsltset.getString(1).toUpperCase());
data.add(stockInstance);
}
} catch (SQLException ex) {
Logger.getLogger(WriteToFile.class.getName()).log(Level.SEVERE, null, ex);
System.out.println("Connection Failed! Check output console");
}
tickerCol.setCellValueFactory(new PropertyValueFactory<Stock,String>("stockTicker"));
stockTableView.setItems(data);
}
/*THIS, ON THE OTHER HAND, WORKS*/
/*Callback<CellDataFeatures<Stock, String>, ObservableValue<String>> cellDataFeat =
new Callback<CellDataFeatures<Stock, String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<Stock, String> p) {
return new SimpleStringProperty(p.getValue().getstockTicker());
}
};*/
Suggested solution (use a Lambda, not a PropertyValueFactory)
Instead of:
aColumn.setCellValueFactory(new PropertyValueFactory<Appointment,LocalDate>("date"));
Write:
aColumn.setCellValueFactory(cellData -> cellData.getValue().dateProperty());
For more information, see this answer:
Java: setCellValuefactory; Lambda vs. PropertyValueFactory; advantages/disadvantages
Solution using PropertyValueFactory
The lambda solution outlined above is preferred, but if you wish to use PropertyValueFactory, this alternate solution provides information on that.
How to Fix It
The case of your getter and setter methods are wrong.
getstockTicker should be getStockTicker
setstockTicker should be setStockTicker
Some Background Information
Your PropertyValueFactory remains the same with:
new PropertyValueFactory<Stock,String>("stockTicker")
The naming convention will seem more obvious when you also add a property accessor to your Stock class:
public class Stock {
private SimpleStringProperty stockTicker;
public Stock(String stockTicker) {
this.stockTicker = new SimpleStringProperty(stockTicker);
}
public String getStockTicker() {
return stockTicker.get();
}
public void setStockTicker(String stockticker) {
stockTicker.set(stockticker);
}
public StringProperty stockTickerProperty() {
return stockTicker;
}
}
The PropertyValueFactory uses reflection to find the relevant accessors (these should be public). First, it will try to use the stockTickerProperty accessor and, if that is not present fall back to getters and setters. Providing a property accessor is recommended as then you will automatically enable your table to observe the property in the underlying model, dynamically updating its data as the underlying model changes.
put the Getter and Setter method in you data class for all the elements.

How to get the date when an entity was persisted

I want to sort a celltable by the last ones added on top, now , to do this, i need to sort them by the date they were added to the application. Is there a way to get this date? or i have to create a new attribute for each class?. Thanks!
You need to create your own attribute.
If I'm understanding well, you can use a comparator. For example, suppose you have some clas into gwt.shared.model package such as:
public class SomeClass implements IsSerializable {
private Date date;
// some stuff...
}
Then, implement a comparator for that class
import java.util.Comparator;
public class SomeClassComparator implements Comparator<SomeClass> {
#Override
public int compare(SomeClass someObject1, SomeClass someObject2) {
if (someObject1.getDate().getTimeInMillis() > someObject2.getDate().getTimeInMillis()) return 1
else if someObject1.getDate().getTimeInMillis() > someObject2.getDate().getTimeInMillis() return 0;
else return 0;
}
}
Before adding objects into the table you must do:
List<SomeClass> someObjects = ... // list of objects
Collection.sort(someObjects);
Then you can show them in the cell table.
Edit 1: the comparator must be included in gwt.shared.model

How to change and entity type in Doctrine2 CTI Inheritance

How (if possible at all) do you change the entity type with Doctrine2, using it's Class Table Inheritance?
Let's say I have a Person parent class type and two inherited types Employe and Client. My system allows to create a Person and specify it's type - that's fairly easy to implement - but I'd also like to be able to change the person from an Employe to a Client, while maintaining the Person-level information (it's id and other associated records).
Is there a simple way to do this with Doctrine2?
I was looking for this behaviour yesterday also.
In the end, after speaking with people in #doctrine on freenode, I was told that it is not possible.
If you want to do this, then you have to go through this:
Upgrading a User
Grab the Person Entity.
Update the discrimator column so that it is no longer a 'person' and change it to 'employee'
Create a corresponding row inyour Employee table for this inheritance.
Removing Inheritance
Likewise if you want to remove inheritance, you have to..
Grab the Person Entity.
Update the discrimnator column so that it is no longer an 'employee' and change it to a 'person'.
Delete the corresponding row in your Employee table. (Yes you have to delete it, just change the discrimator coumn is not sufficient).
This might be 7 months late, but it is at least the correct answer for anything else looking to suport such a feature.
PHP doesn't have support for object casting, so Doctrine doesn't support it. To workaround the problem I write this static method into parent classes:
public static function castToMe($obj) {
$class = get_called_class();
$newObj = New $class();
foreach (get_class_vars(get_class($newObj)) as $property => $value) {
if (method_exists($obj, 'get' . ucfirst($property)) && method_exists($newObj, 'set' . ucfirst($property))) {
$newObj->{'set' . ucfirst($property)}($obj->{'get' . ucfirst($property)}());
}
}
return $newObj;
}
You can create this method in class Person and use it to cast from Employe to Client and viceversa:
$employe = New Employe();
$client = Client::castToMe($employe);
Now, if you want, you can remove the $employe entity.
You could do something like this though:
This Trait can be used on your Repository class:
namespace App\Doctrine\Repository;
trait DiscriminatorTrait
{
abstract public function getClassMetadata();
abstract public function getEntityManager();
private function updateDiscriminatorColumn($id, $class)
{
$classMetadata = $this->getClassMetadata();
if (!in_array($class, $classMetadata->discriminatorMap)) {
throw new \Exception("invalid discriminator class: " . $class);
}
$identifier = $classMetadata->fieldMappings[$classMetadata->identifier[0]]["columnName"];
$column = $classMetadata->discriminatorColumn["fieldName"];
$value = array_search($class, $classMetadata->discriminatorMap);
$connection = $this->getEntityManager()->getConnection();
$connection->update(
$classMetadata->table["name"],
[$column => $value],
[$identifier => $id]
);
}
}
There still might be some extra work you need to put in, like clearing values in fields that are only present on one of your sub-classes
In Doctrine2, when you have your parent entity class, Person set as:
/**
* #Entity
* #InheritanceType("JOINED")
* #DiscriminatorColumn(name="discr", type="string")
* #DiscriminatorMap({"person" = "Person", "employee" = "Employee", , "client" = "Client"})
*/
class Person
{
// ...
}
and sub classes such as Client set as:
/** #Entity */
class Client extends Person
{
// ...
}
when you instantiate Person as:
$person = new Person();
Doctrine2 checks your #DiscriminatorMap statement (above) for a corresponding mapping to Person and when found, creates a string value in the table column set in #DiscriminatorColumn above.
So when you decide to have an instance of Client as:
$client = new Client();
Following these principles, Doctrine2 will create an instance for you as long as you have declared the parameters in the #DiscriminatorMap. Also an entry will be made on the Person table, in the discr column to reflect that type of entity class that has just been instantiated.
Hope that helps. It's all in the documentation though
i use this method
trait DiscriminatorTrait
{
// ...
public function updateDiscriminatorColumn($id, $class)
{
// ... other code here
$connection->update(
"Person", // <-- just there i put my parent class
[$column => $value],
[$identifier => $id]
);
}
}
and i use call like this after :
$this->em->getRepository(Client::class)->updateDiscriminatorColumn($cCenter->getId(), Employe::class);
$this->em->close();
// I update the data directly without going through doctrine otherwise it will create a new Person
try {
$query = "
INSERT INTO Employe (id, /* ... other fields */)
VALUES ({$callCenter->getId()}, /* ... other fields */)
";
$results = $this->connection->executeQuery($query)->execute();
} catch (\Exception $exception) {
echo $exception->getMessage().PHP_EOL;
}
$this->em->close();
// i restart the connection
/** #var EntityManagerInterface $entityManager */
$entityManager = $this->em;
if ($this->em->isOpen() === false) {
$this->em = $entityManager->create(
$this->em->getConnection(),
$this->em->getConfiguration(),
$this->em->getEventManager()
);
}
// and there a get Employer en update him
$employe = $this->em->getRepository(Employe::class)->find($id);
$employe->setFirstname($callCenter->getFirstName());
// other code
And it is work for me

Resources