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.
Related
I just wasted half a day trying to figure this out, reading about some workarounds, and thinking "it can't be that bad - there must be a straightforward to do edit a collection in Grails, whethere using scaffolded views or my own."
Let's say I have this domain object:
class TreeGroup {
String name
List<Tree> trees
static hasMany = ['trees': MyTree]
}
Just to explain the choice of data structure - I need my records to be unique, but in the order I set. That's why I chose List, AFAIK one cannot rely on order in a Set. So there are 2 pieces to this question - 1) how to remove from any Collection, for example a Set, 2) is List the best replacement for Set in this context (preserving order).
I want to be able to create a group record with no trees in it and make 4 updates:
edit/save
edit the group record to reference 2 trees A and B
add another tree C
remove A
remove B and C
And obviously, I want the desired state after every step. Currently though, I can only add records, and if I even edit/save to list, the list elements are added to it again.
I am using the multiple select tag for this. It looks like this:
<g:select name="trees" from="${allTrees}" optionKey="id"
multiple="true" class="many-to-many"
value="${trees ? trees*.id : treeGroupInstance?.trees*.id}" />
and that's fine, in the sense that it generates an HTTP header with these variables on update:
_method:PUT
version:19
name:d5
trees:1
_action_update:Update
But the data binder only adds new elements, it never lets you edit a list.
What is the cleanest way to do it ? Is it me, not reading something obvious, or is this a design flaw of grails data binding (and of so, when/how will it be fixed) ?
Is there a way perhaps via a hidden HTTP parameter to clear the list before (re)adding elements ?
Thanks
I ended up doing this:
private repopulate(def domainObject, String propertyName, Class domainKlaz) {
if (params[propertyName] != null) {
domainObject[propertyName].clear()
domainObject[propertyName].addAll(
params[propertyName].collect { domainKlaz.get(it) }
)
}
}
and I am calling it in update controller method before save(), for every collection. OMG how ugly.
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.
If you create a checkbox list in symfony 1.2 you get an array with the checked options back in the form. If you save the form, your database now contains the words "Array". Is there a way around this? Or should I just json_encode / json_decode the array as ncecessary and save it manually? Seems awfully tedious.
Thanks for reading.
You can use serialize() and unserialize() functions when saving and getting data.
I don't know which orm using but i can explain with propel way.
For example you have post table and Post class. And post table has options column with text or varchar data type.
in Post.class.php your model directory you can define two override methods
setOptions($v)
{
parent::setOptions(serialize($v));
}
getOptions()
{
return unserialize($this->options);
}
Just like that.
In your view or action you can get all options with $post->getOptions() and you have an Array that contains all option related to your database record.
I'm working on an application at the moment in ASP.NET MVC which has a number of look-up tables, all of the form
LookUp {
Id
Text
}
As you can see, this just maps the Id to a textual value. These are used for things such as Colours. I now have a number of these, currently 6 and probably soon to be more.
I'm trying to put together an API that can be used via AJAX to allow the user to add/list/remove values from these lookup tables, so for example I could have something like:
http://example.com/Attributes/Colours/[List/Add/Delete]
My current problem is that clearly, regardless of which lookup table I'm using, everything else happens exactly the same. So really there should be no repetition of code whatsoever.
I currently have a custom route which points to an 'AttributeController', which figures out the attribute/look-up table in question based upon the URL (ie http://example.com/Attributes/Colours/List would want the 'Colours' table). I pass the attribute (Colours - a string) and the operation (List/Add/Delete), as well as any other parameters required (say "Red" if I want to add red to the list) back to my repository where the actual work is performed.
Things start getting messy here, as at the moment I've resorted to doing a switch/case on the attribute string, which can then grab the Linq-to-Sql entity corresponding to the particular lookup table. I find this pretty dirty though as I find myself having to write the same operations on each of the look-up entities, ugh!
What I'd really like to do is have some sort of mapping, which I could simply pass in the attribute name and get out some form of generic lookup object, which I could perform the desired operations on without having to care about type.
Is there some way to do this to my Linq-To-Sql entities? I've tried making them implement a basic interface (IAttribute), which simply specifies the Id/Text properties, however doing things like this fails:
System.Data.Linq.Table<IAttribute> table = GetAttribute("Colours");
As I cannot convert System.Data.Linq.Table<Colour> to System.Data.Linq.Table<IAttribute>.
Is there a way to make these look-up tables 'generic'?
Apologies that this is a bit of a brain-dump. There's surely imformation missing here, so just let me know if you'd like any further details. Cheers!
You have 2 options.
Use Expression Trees to dynamically create your lambda expression
Use Dynamic LINQ as detailed on Scott Gu's blog
I've looked at both options and have successfully implemented Expression Trees as my preferred approach.
Here's an example function that i created: (NOT TESTED)
private static bool ValueExists<T>(String Value) where T : class
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
Expression value = Expression.Equal(Expression.Property(pe, "ColumnName"), Expression.Constant(Value));
Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(value, pe);
return MyDataContext.GetTable<T>().Where(predicate).Count() > 0;
}
Instead of using a switch statement, you can use a lookup dictionary. This is psuedocode-ish, but this is one way to get your table in question. You'll have to manually maintain the dictionary, but it should be much easier than a switch.
It looks like the DataContext.GetTable() method could be the answer to your problem. You can get a table if you know the type of the linq entity that you want to operate upon.
Dictionary<string, Type> lookupDict = new Dictionary<string, Type>
{
"Colour", typeof(MatchingLinqEntity)
...
}
Type entityType = lookupDict[AttributeFromRouteValue];
YourDataContext db = new YourDataContext();
var entityTable = db.GetTable(entityType);
var entity = entityTable.Single(x => x.Id == IdFromRouteValue);
// or whatever operations you need
db.SubmitChanges()
The Suteki Shop project has some very slick work in it. You could look into their implementation of IRepository<T> and IRepositoryResolver for a generic repository pattern. This really works well with an IoC container, but you could create them manually with reflection if the performance is acceptable. I'd use this route if you have or can add an IoC container to the project. You need to make sure your IoC container supports open generics if you go this route, but I'm pretty sure all the major players do.
I am using ASP.NET-MVC and nHibernate for the first time. Great tools, but big learning curve!
I have a list view of objects that are quite large (each has about 60 properties). In the list view I am only using about 10 of these properties. Performance is not too bad, but it seems a waste to fully hydrate these objects. What is the recommended practice?
I tried using HQL to select fewer properties, but it seems like it won't partially hydrate an object. I also tried making property on the main object that was a header class with the list view properties, but I couldn't seem to get it mapped properly. I think this should be easy but I've really been struggling with it.
EDIT:
I kept coming back to this because I knew Anton had given me the answer and I just couldn't see it.
There are three things you need to do:
Make an object with the properties you want.
Make a mapping file to import this object.
<hibernate-mapping
xmlns="urn:nhibernate-mapping-2.2"
namespace="Core.Entities"
assembly="Core"
default-access="property">
<import class="RequestHeader" />
</hibernate-mapping>
If you are using HQL, your object must contain a constructor with all the properties, in the same order, as your select new statement. If you use the Criteria API, you don't need to do this.
public IList<RequestHeader> ListAll()
{
using (ISession session = GetSession())
{
using (ITransaction tx = session.BeginTransaction())
{
IList<RequestHeader> results = session.CreateCriteria(typeof (Request), "r")
.CreateCriteria("Requestor", "req", JoinType.InnerJoin)
.CreateCriteria("r.Grant", "g", JoinType.InnerJoin)
.SetProjection(Projections.ProjectionList()
.Add(Projections.Property("r.Id"), "Id")
.Add(Projections.Property("r.Status"), "Status")
.Add(Projections.Property("r.SubmissionDate"), "SubmissionDate")
.Add(Projections.Property("req.Name"), "Requestor")
.Add(Projections.Property("g.Number"), "Number"))
.SetResultTransformer(Transformers.AliasToBean(typeof (RequestHeader)))
.SetMaxResults(10000)
.List<RequestHeader>();
tx.Commit();
return results;
}
}
}
60 properties is too much. See Component mapping.
As for selecting a subset of properties, see this: you need a select new HQL construct. Be aware, though, that you need an appropriate constructor and that an object you'll get cannot be saved back to the DB.