I have a complex nested (order) Zend\Form, that can be edited multiple times. The user first creates an order, but doesn't need to place it immediately. He can just save the order (or more exact: its data) and edit it later. In this case the application loads an Order object (with all its nested structure) and binds it to the form. The important steps are:
get ID of the order from the request
get the Order object by ID
$orderForm->bind($orderObject)
...
Now I want to catch the data and serialize it to JSON. (The background: Forms cloning -- in the next step a empty new form should created and the should be passed to it; after saving we'll get a clone.) It should happen between 2 and 3. So I'm trying
$formData = $this->orderForm->getData();
$formJson = json_encode($formData, JSON_UNESCAPED_SLASHES);
and getting the error:
Zend\Form\Form::getData cannot return data as validation has not yet occurred
Well, I could try to work around it and validate the form:
$formIsValid = $this->orderForm->isValid();
but it only leads to further troubles:
Zend\InputFilter\BaseInputFilter::setData expects an array or Traversable argument; received NULL
Is there a way to get the form data before the validation?
Okay, the comment space is way too small to say everything about what you try to archive. Let 's refactor every single step you mentioned in the starting post. This will lead us to your goal. It 's all about hydration.
This will be a small example, how an order entity with products in it could look like. After the order entity follows the product entity, which we need for this example.
namespace Application\Entity;
class Order implements \JsonSerializable
{
/**
* ID of the order
* #var integer
*/
protected $orderID;
/**
* Array of \Application\Entity\Product
* #var array
*/
protected $products;
public function getOrderID() : integer
{
return $this->orderID;
}
public function setOrderID(integer $orderID) : Order
{
$this->orderID = $orderID;
return $this;
}
public function getProducts()
{
if ($this->products == null) {
$this->products = [];
}
return $this->products;
}
public function setProducts(array $products) : Order
{
$this->products = $products;
return $this;
}
/**
* #see \JsonSerializable::jsonSerialize()
*/
public function jsonSerialize()
{
return get_object_vars($this);
}
}
The following entity represents a product.
class Product implements \JsonSerializable
{
protected $productID;
protected $name;
public function getProductID() : integer
{
return $this->productID;
}
public function setProductID(integer $productID) : Product
{
$this->productID = $productID;
return $this;
}
public function getName() : string
{
return $this->name;
}
public function setName(string $name) : Product
{
$this->name = $name;
return $this;
}
/**
* #see \JsonSerializable::jsonSerialize()
*/
public function jsonSerialize()
{
return get_object_vars($this);
}
}
Above you see our entity, wich represents a single order with several possible products in it. The second member products can be an array with Product entities. This entity represents the data structure of our simple order.
At this point we need a form, which uses this entites as objects for the data it contains. A possible factory for our form could look like this.
namespace Application\Form\Factory;
class OrderFormFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$parentLocator = $serviceLocator->getServiceLocator();
$inputFilter = $parentLocator->get('InputFilterManager')->get(OrderInputFiler::class);
$hydrator = new ClassMethods(false);
$entity = new OrderEntity();
return (new OrderForm())
->setInputFilter($inputFilter)
->setHydrator($hydrator)
->setObject($entity);
}
}
This is the factory for our form. We set a hydrator, an input filter and an entity for the form. So you don 't have to bind something. The following code shows, how to handle data with this form.
// retrieve an order from database by id
// This returns a order entity as result
$order = $this->getServiceLocator()->get(OrderTableGateway::class)->fetchById($id);
// Extract the order data from object to array assumed the
// retrieved data from data base is an OrderEntity object
// the hydrator will use the get* methods of the entity and returns an array
$data = (new ClassMethods(false))->extract($order);
// fill the form with the extracted data
$form = $this->getServiceLocator()->get('FormElementManager')->get(OrderForm::class);
$form->setData($data);
if ($form->isValid()) {
// returns a validated order entity
$order = $form->getData();
}
It is absolutely not possible to get data from a form, that is not validated yet. You have to validate the form data and after that you can get the filtered / validated data from the form. Hydrators and entities will help you a lot when you have to handle a lot of data.
I am creating a web application, where you have to read a list of objects / entities from a DB and populate it in a JSF <h:selectOneMenu>. I am unable to code this. Can someone show me how to do it?
I know how to get a List<User> from the DB. What I need to know is, how to populate this list in a <h:selectOneMenu>.
<h:selectOneMenu value="#{bean.name}">
...?
</h:selectOneMenu>
Based on your question history, you're using JSF 2.x. So, here's a JSF 2.x targeted answer. In JSF 1.x you would be forced to wrap item values/labels in ugly SelectItem instances. This is fortunately not needed anymore in JSF 2.x.
Basic example
To answer your question directly, just use <f:selectItems> whose value points to a List<T> property which you preserve from the DB during bean's (post)construction. Here's a basic kickoff example assuming that T actually represents a String.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{bean.names}" />
</h:selectOneMenu>
with
#ManagedBean
#RequestScoped
public class Bean {
private String name;
private List<String> names;
#EJB
private NameService nameService;
#PostConstruct
public void init() {
names = nameService.list();
}
// ... (getters, setters, etc)
}
Simple as that. Actually, the T's toString() will be used to represent both the dropdown item label and value. So, when you're instead of List<String> using a list of complex objects like List<SomeEntity> and you haven't overridden the class' toString() method, then you would see com.example.SomeEntity#hashcode as item values. See next section how to solve it properly.
Also note that the bean for <f:selectItems> value does not necessarily need to be the same bean as the bean for <h:selectOneMenu> value. This is useful whenever the values are actually applicationwide constants which you just have to load only once during application's startup. You could then just make it a property of an application scoped bean.
<h:selectOneMenu value="#{bean.name}">
<f:selectItems value="#{data.names}" />
</h:selectOneMenu>
Complex objects as available items
Whenever T concerns a complex object (a javabean), such as User which has a String property of name, then you could use the var attribute to get hold of the iteration variable which you in turn can use in itemValue and/or itemLabel attribtues (if you omit the itemLabel, then the label becomes the same as the value).
Example #1:
<h:selectOneMenu value="#{bean.userName}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.name}" />
</h:selectOneMenu>
with
private String userName;
private List<User> users;
#EJB
private UserService userService;
#PostConstruct
public void init() {
users = userService.list();
}
// ... (getters, setters, etc)
Or when it has a Long property id which you would rather like to set as item value:
Example #2:
<h:selectOneMenu value="#{bean.userId}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>
with
private Long userId;
private List<User> users;
// ... (the same as in previous bean example)
Complex object as selected item
Whenever you would like to set it to a T property in the bean as well and T represents an User, then you would need to bake a custom Converter which converts between User and an unique string representation (which can be the id property). Do note that the itemValue must represent the complex object itself, exactly the type which needs to be set as selection component's value.
<h:selectOneMenu value="#{bean.user}" converter="#{userConverter}">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
with
private User user;
private List<User> users;
// ... (the same as in previous bean example)
and
#ManagedBean
#RequestScoped
public class UserConverter implements Converter {
#EJB
private UserService userService;
#Override
public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
if (submittedValue == null || submittedValue.isEmpty()) {
return null;
}
try {
return userService.find(Long.valueOf(submittedValue));
} catch (NumberFormatException e) {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid User ID", submittedValue)), e);
}
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
if (modelValue == null) {
return "";
}
if (modelValue instanceof User) {
return String.valueOf(((User) modelValue).getId());
} else {
throw new ConverterException(new FacesMessage(String.format("%s is not a valid User", modelValue)), e);
}
}
}
(please note that the Converter is a bit hacky in order to be able to inject an #EJB in a JSF converter; normally one would have annotated it as #FacesConverter(forClass=User.class), but that unfortunately doesn't allow #EJB injections)
Don't forget to make sure that the complex object class has equals() and hashCode() properly implemented, otherwise JSF will during render fail to show preselected item(s), and you'll on submit face Validation Error: Value is not valid.
public class User {
private Long id;
#Override
public boolean equals(Object other) {
return (other != null && getClass() == other.getClass() && id != null)
? id.equals(((User) other).id)
: (other == this);
}
#Override
public int hashCode() {
return (id != null)
? (getClass().hashCode() + id.hashCode())
: super.hashCode();
}
}
Complex objects with a generic converter
Head to this answer: Implement converters for entities with Java Generics.
Complex objects without a custom converter
The JSF utility library OmniFaces offers a special converter out the box which allows you to use complex objects in <h:selectOneMenu> without the need to create a custom converter. The SelectItemsConverter will simply do the conversion based on readily available items in <f:selectItem(s)>.
<h:selectOneMenu value="#{bean.user}" converter="omnifaces.SelectItemsConverter">
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
See also:
Our <h:selectOneMenu> wiki page
View-Page
<h:selectOneMenu id="selectOneCB" value="#{page.selectedName}">
<f:selectItems value="#{page.names}"/>
</h:selectOneMenu>
Backing-Bean
List<SelectItem> names = new ArrayList<SelectItem>();
//-- Populate list from database
names.add(new SelectItem(valueObject,"label"));
//-- setter/getter accessor methods for list
To display particular selected record, it must be one of the values in the list.
Roll-your-own generic converter for complex objects as selected item
The Balusc gives a very useful overview answer on this subject. But there is one alternative he does not present: The Roll-your-own generic converter that handles complex objects as the selected item. This is very complex to do if you want to handle all cases, but pretty simple for simple cases.
The code below contains an example of such a converter. It works in the same spirit as the OmniFaces SelectItemsConverter as it looks through the children of a component for UISelectItem(s) containing objects. The difference is that it only handles bindings to either simple collections of entity objects, or to strings. It does not handle item groups, collections of SelectItems, arrays and probably a lot of other things.
The entities that the component binds to must implement the IdObject interface. (This could be solved in other way, such as using toString.)
Note that the entities must implement equals in such a way that two entities with the same ID compares equal.
The only thing that you need to do to use it is to specify it as converter on the select component, bind to an entity property and a list of possible entities:
<h:selectOneMenu value="#{bean.user}" converter="selectListConverter">
<f:selectItem itemValue="unselected" itemLabel="Select user..."/>
<f:selectItem itemValue="empty" itemLabel="No user"/>
<f:selectItems value="#{bean.users}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>
Converter:
/**
* A converter for select components (those that have select items as children).
*
* It convertes the selected value string into one of its element entities, thus allowing
* binding to complex objects.
*
* It only handles simple uses of select components, in which the value is a simple list of
* entities. No ItemGroups, arrays or other kinds of values.
*
* Items it binds to can be strings or implementations of the {#link IdObject} interface.
*/
#FacesConverter("selectListConverter")
public class SelectListConverter implements Converter {
public static interface IdObject {
public String getDisplayId();
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (value == null || value.isEmpty()) {
return null;
}
return component.getChildren().stream()
.flatMap(child -> getEntriesOfItem(child))
.filter(o -> value.equals(o instanceof IdObject ? ((IdObject) o).getDisplayId() : o))
.findAny().orElse(null);
}
/**
* Gets the values stored in a {#link UISelectItem} or a {#link UISelectItems}.
* For other components returns an empty stream.
*/
private Stream<?> getEntriesOfItem(UIComponent child) {
if (child instanceof UISelectItem) {
UISelectItem item = (UISelectItem) child;
if (!item.isNoSelectionOption()) {
return Stream.of(item.getValue());
}
} else if (child instanceof UISelectItems) {
Object value = ((UISelectItems) child).getValue();
if (value instanceof Collection) {
return ((Collection<?>) value).stream();
} else {
throw new IllegalStateException("Unsupported value of UISelectItems: " + value);
}
}
return Stream.empty();
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) return null;
if (value instanceof String) return (String) value;
if (value instanceof IdObject) return ((IdObject) value).getDisplayId();
throw new IllegalArgumentException("Unexpected value type");
}
}
I'm doing it like this:
Models are ViewScoped
converter:
#Named
#ViewScoped
public class ViewScopedFacesConverter implements Converter, Serializable
{
private static final long serialVersionUID = 1L;
private Map<String, Object> converterMap;
#PostConstruct
void postConstruct(){
converterMap = new HashMap<>();
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object object) {
String selectItemValue = String.valueOf( object.hashCode() );
converterMap.put( selectItemValue, object );
return selectItemValue;
}
#Override
public Object getAsObject(FacesContext context, UIComponent component, String selectItemValue){
return converterMap.get(selectItemValue);
}
}
and bind to component with:
<f:converter binding="#{viewScopedFacesConverter}" />
If you will use entity id rather than hashCode you can hit a collision- if you have few lists on one page for different entities (classes) with the same id
Call me lazy but coding a Converter seems like a lot of unnecessary work. I'm using Primefaces and, not having used a plain vanilla JSF2 listbox or dropdown menu before, I just assumed (being lazy) that the widget could handle complex objects, i.e. pass the selected object as is to its corresponding getter/setter like so many other widgets do. I was disappointed to find (after hours of head scratching) that this capability does not exist for this widget type without a Converter. In fact if you supply a setter for the complex object rather than for a String, it fails silently (simply doesn't call the setter, no Exception, no JS error), and I spent a ton of time going through BalusC's excellent troubleshooting tool to find the cause, to no avail since none of those suggestions applied. My conclusion: listbox/menu widget needs adapting that other JSF2 widgets do not. This seems misleading and prone to leading the uninformed developer like myself down a rabbit hole.
In the end I resisted coding a Converter and found through trial and error that if you set the widget value to a complex object, e.g.:
<p:selectOneListbox id="adminEvents" value="#{testBean.selectedEvent}">
... when the user selects an item, the widget can call a String setter for that object, e.g. setSelectedThing(String thingString) {...}, and the String passed is a JSON String representing the Thing object. I can parse it to determine which object was selected. This feels a little like a hack, but less of a hack than a Converter.
I am writing an ASP.NET MVC (C#, SQL Server) web site and would like to write a function in my controller in which I pass a table name, a column name, and a value to check against the passed in column name in the passed in table.
If the record is found, I want to return the primary key of the record.
If the value is not found in the table, I want to create it and then return the primary key of that record.
private int FindRecord(string tableName, string FieldToCheck, string LookupValue)
{
/* 1) How do I set the string 'tableName' to a table in my context */
/* How do I set the string FieldToCheck to a field in the 'tableName' */
/* How do I return the primary key if LookupValue is in 'FieldToCheck' */
/* How do I add a record and return primary key if it is now */
return PrimaryKeyOfFoundOrNewRecord;
}
I almost cannot imagine that this question is not a duplicate but I cannot find any examples - perhaps I'm not using the proper terms to search. Thank you in advance.
OK, based on the comment clarification of what is required, then what you might want is something like this:
void CreateLocation(string city,string state, string country)
{
var newLoc = new Location();
newLoc.City = GetCity(city);
if (newLoc.City == null)
{
newLoc.City = new City() { Name = city });
}
//Repeaat this for state and country.
_context.Locations.Add(newLoc);
_context.SaveChanges();
}
City GetCity(string city)
{
var city = from c in _context.Cities
where c.name.Equals(city)
select c;
return city.FirstOrDefault();
}
Apologies if the syntax is a little off, nearly quitting time here.
Sorry, some of this syntax might be entity framework as opposed to linq-to-sql - just noticed your tag. Syntax is different (marginally) but idea is the same.
I have a user table with a store id column (store) that correspondent with a store table.
I'm retrieving this store id with a custom entity object.
Application/Entity/User.php
namespace Thuiswinkelen\Entity;
class User extends \ZfcUser\Entity\User
{
/**
* #var int
*/
protected $store;
public function getStore()
{
return $this->store;
}
/**
* Set store.
*
* #param int $store
* #return UserInterface
*/
public function setStore($store)
{
$this->store = (int) $store;
return $this;
}
}
My question is: How to get the store name in the store table (with an inner join?)
It would be great when I can use something like:
<?php echo $this->zfcUserStoreId() ?>
<?php echo $this->zfcUserStoreName() ?>
If you're looking to map entity relationships; you will need an object relational mapper (ORM), such as Doctrine to accomplish this.
This will convert your foreign identifiers into objects in which you can then transverse.
$storeName = $user->getStore()->getName();
I'm guessing that the examples you have suggested $this->zfcUserStoreId() you have invented due to the already existing ZfcUser\View\Helper\ZfcUserDisplayName
This however is a view helper and simplify aids the rendering of a user's name based on other configuration.
This question already has answers here:
Validation Error: Value is not valid
(3 answers)
Closed 7 years ago.
I got this error many time.. i am using two h:selectonemenu in my JSF page, mediaList and Unitlist. while selecting any Media . my UnitList populate automatically, but some time it gives Validation Error: value is not valid;
My JSF code
<h:selectOneMenu id="media" value="#{workOrderMbean.selectedMedia}" converter="MediaConverter" onchange="submit()" valueChangeListener="#{workOrderMbean.onChangeMediaCombo}" immediate="true">
<f:selectItems value="#{workOrderMbean.mediaCombo}"/>
</h:selectOneMenu>
<h:selectOneMenu id="hUnit" value="#{workOrderMbean.selectedHeightUnit}" converter="UnitConverter" >
<f:selectItems value="#{workOrderMbean.unitCombo}"/>
</h:selectOneMenu>
onchane event of Mediacombo is
public void onChangeMediaCombo(ValueChangeEvent e) throws SearchBLException {
if (e.getNewValue() != null) {
Media media = (Media) e.getNewValue();
if (unitCombo != null && !unitCombo.isEmpty()) {
unitCombo.clear();
seclectedWidthUnit=new Unit();
selectedHeightUnit=new Unit();
}
unitCombo = ComboLoader.getUnitsComboByMediaid(media.getMediaId());
}
else
{
if (unitCombo != null && !unitCombo.isEmpty()) {
unitCombo.clear();
seclectedWidthUnit=null;
selectedHeightUnit=null;
}
unitCombo = ComboLoader.getUnitsComboByMediaid(-1);
}
}
i am also using converter for 'Unit'
my media converter is
#FacesConverter(value = "MediaConverter")
public class MediaConverter implements Converter{
MediaDAO mediadao=new MediaDAOImpl();
public Object getAsObject(FacesContext context, UIComponent component, String value) {
Media media=null;
try {
media=mediadao.getMedia(Integer.parseInt(value));
} catch (SearchBLException ex) {
Logger.getLogger(MediaConverter.class.getName()).log(Level.SEVERE, null, ex);
}
return media;
}
public String getAsString(FacesContext context, UIComponent component, Object value) {
String str = "";
if (value instanceof Media) {
str = "" + ((Media) value).getMediaId();
}
return str;
}
}
The problem is most likely in your converter and model class (Media).
You don't show how you exactly do the conversion, but I guess you're converting to String by returning the Media's Id, and converting back to Media by getting a new instance from some place like a DB?
In that case, your Media class needs to implement a custom equals and hashcode method.
JSF compares if the value send by the user corresponds with the values in the list you bind to the selectitems. It uses equals for that, which by default compares object Ids (kind of memory references). Unless you have the exact same instances, this will always be false.
Instead of defining an equals method, you can alternatively let your converter get the model object you need from the same list as the selectitems come from. There was an article on http://jdevelopment.nl a while back about this.