Doctrine inheritance and associations - symfony

I have entity Image with properties:
class Image {
private $id
private $name;
private $mimeType;
private $size; }
Now, I need to add new image type which will have all properties as existing class and some new properties like author name, external url, url to author... Let's call it ExternalImage. Existing images don't need these properties.
Then I need to add image property to Event class and it can be either Image or ExternalImage.
One other use case is that I need to list all images (both types at once, on some API endpoint).
My solution would be:
ExternalImage extends Image
.. add new properties
and use SINGLE TABLE Doctrine's inheritance. And then add OneToOne association to Event class (adding image_id property).
<one-to-one field="image" target-entity="App\Common\Entity\Image">
is inheritance appropriate for this example? I don't see any other solution from my perspective. We have strong "is a" relation between Image and ExternalImage.
I am aware of performance issue with using STI entity as target entity of one-to-one association - image entity won't be lazily loaded when I fetch Event object. Can I do something about that?

Related

How update dynamically a form when we add a new property to the entity related

I just read the documentation of Symfony about Form Events, but I don't really understand.
How to add dynamically fields in a form when whe add or edit a new property in the entity class ?
For example
I have a entity named Product with two properties : $name and $price.
I create a form related to this entity with all properties.
I add a new property $createdAt in the entity
The form added automatically a new line : ->add('createdAt')

Symfony2 - Saving child and parent from the same form

I'm new to Symfony2 and i've been struggling with an issue handling a form submission. I can't help feeling i'm missing something stupid, but after googling and not findind any solutions I thought i'd post my problem here.
So, I have a form to create a child entity and edit a couple fields on a parent entity. To build the form i've used the FormBuilder, where i added two form types (one for the child and one for the parent). The parent type includes the ID field for the parent.
On the action that handles the form submission i'm calling handleRequest which fails because:
Neither the property "id" nor one of the methods "setId()", "_set()" or "_call()" exist and have public access in class "Ahms\MyBundle\Entity\Parent".
This happens when the parent id field is part of the form, when it's not part of the form this runs smoothly.
What am I missing?
Thanks!
If you create the Form from child Controller, you have to declare id in child class and have to writ public function setId($id) and public function getId() method.

JSF 2.0 dynamically controlling which values get posted back based on CSS

I have this form with ~170 individual text boxes with values in a session scoped bean. There is a requirement to only submit values when the component has a certain CSS class.
The way I originally approached this was to create a PhaseListener at the UPDATE_MODEL_VALUES and test the CSS class there. If the class was the affected class I set the value of the component to null. Then on the front end, I switched the class on focus using a generic JavaScript method. This meant in terms of changes to each componenet I only needed to add:
... styleClass="examfieldgrey" onfocus="whiteField(this);"
which is kind of nice given how many components I need to change.
This was working fine until I re-factored my e form to use multiple h form tags. Now the CSSclass is switching on the front end, but this change is not being saved. The phase listener is getting the old class.
I'm thinking this is obviously related to me switching the class in jQuery/javascript. What I am wondering is:
Is there a better way to do this arachatectually? One that preferably means I don't have to modify 170+ componenets?
If I do have to continue with using Javascript to switch the class, is there a way I can post that change back from javascript?
Sorry if this is an obvious question, I'm still a little green with the JSF lifecycle.
I'm using JSF 2.0 MyFaces
For reference here is an example of a component on my form that needs to be filtered:
<h:inputTextarea
id="inputVal"
styleClass="midTextArea examfieldgrey"
onfocus="whiteField(this);"
value="#{bean.form.val}"/>
where "examfieldgrey" is the class I test for when determining if I'm going to block a component.
And the whiteField method:
function whiteField(field){
if(! jQuery(field).hasClass("examfieldgrey")){
return;
}
jQuery(field).removeClass("examfieldgrey");
jQuery(field).addClass("examfieldwhite");
}
And my phase listener before phase method where I filter:
// TODO: make whatever mode allows ghosting to be configurable outside of
// the system (perhaps in the config file)
/**
* Before the model is updated, test each component's CSS on the form. If the
* CSS style is 'examfieldgrey' set the value to null so it doesn't get submitted
*/
#Override
public void beforePhase(PhaseEvent arg0) {
//We need the session to get the backing bean
if (arg0.getFacesContext().getExternalContext().getSessionMap() == null) {
return;
}
//get the measurements bean so we can determine the form mode
if (arg0.getFacesContext().getExternalContext().getSessionMap()
.get("measurements") == null) {
return;
}
//ensure the bean is the expected data type, it should always be this type. I'm just paranoid ;)
if (!(arg0.getFacesContext().getExternalContext().getSessionMap()
.get("measurements") instanceof MeasurementsController)) {
return;
}
//get, convert and check the backing bean's mode. We only filter if the mode is COPY
if (((MeasurementsController) arg0.getFacesContext()
.getExternalContext().getSessionMap().get("measurements"))
.getMode() != FormMode.COPY) {
return;
}
//recursivly traverse the componenets and filter the ones who have the CSS class
traverseChildren(arg0.getFacesContext().getViewRoot().getChildren());
}
/**
* Traverse a List of UIComponenets and check the CSS. If it's the 'examfieldgrey' class
* and the component is a UIInput component, set the value to null.
* #param children a List of the componenets to filter on the form.
*/
private void traverseChildren(List<UIComponent> children) {
debugLevelCount++;
if (children == null || children.size() == 0) {
debugLevelCount--;
return;
}
for (UIComponent component : children) {
if (component instanceof UIInput) {
if (component.getAttributes() != null
&& component.getAttributes().get("styleClass") != null
&& component.getAttributes().get("styleClass")
.toString().contains("examfieldgrey")) {
((UIInput) component).setValue(null);
} else {
debugPrintAllow(component);
}
continue;
}
traverseChildren(component.getChildren());
}
debugLevelCount--;
}
Ignore the print functions, they don't do anything ;)
Thanks guys!
Edit
This is a copy operation so the backing bean has values in it after construction of the bean. The option of using the primefaces selector is great if I hit submit and the backing bean is not already populated. But I'm not sure if it will be able to actually clear out those values.
One other thing to note is that I am referencing values inside an instance of my form object. I don't know if that helps but it wasn't present in my original post.
There is a requirement to only submit values when the component has a certain CSS class.
If you happen to use PrimeFaces already or are open to use it, since the latest 3.3 version you can use the new #() selector syntax which accepts jQuery based CSS selectors in process and update attributes of PrimeFaces ajax components (which are equivalent to execute and render attributes of JSF standard <f:ajax> component).
For example
<p:commandButton ... process="#(.foo)" />
or
<p:ajax ... process="#(.foo)" />
will instruct JSF to process only the HTML input elements having classname of foo.
Now the CSSclass is switching on the front end, but this change is not being saved. The phase listener is getting the old class.
That's because you didn't keep JSF component tree in the server side in sync with the HTML DOM tree in the client side. You're making changes in the client side only without notifying JSF about this. CSS classes are not been sent as a request parameter to the server side, only the HTML form input values are. You basically need to change the CSS classes by JSF instead of by JS/jQuery so that the change is also reflected in the JSF component tree.
Implementing this is however not exactly trivial and potentially wasteful. Easiest is thus to use PrimeFaces with its #() selector support. This selector is evaluated in the client side and converted to a string of JSF-understandable component client IDs matching the selector. This thus takes client side changes fully into account.
I was able to get this one solved by creating a map of boolean values for each field on the form with string keys that are the ids of the fields. Each value represented weather or not to copy the field. I update this value using ajax on blur. And I set the CSS class to be based on the boolean value in the map for that field.
Rendering didn't work out so well. Originally I was doing this all on focus but it quickly became apparent that attempting to rendering a textbox on focus would actually lose focus to the textbox. So, on focus I just call a quick js function to switch the class as I had been doing originally.
Since the css class is chosen based on the map on the front end, it gets updated before the phase listener is called and the components get filtered properly.
Thanks for the help BalusC!

Exposing properties to a Spark Skin class

I am having trouble wrapping my head around the spark skin class in relation to it's host component. Basically, from what I've seen with most every skin that comes in the Flex 4 framework they don't directly expose the properties that are dynamically being set in the host component. Instead, they define states that get exposed to the skin class to define when a component should look different. This is all fine and dandy when you have a very simple component with a standard set of states, but when you have twenty different properties (hypothetically) to set in your host component that should change how the skin looks it could get very complicated very fast.
The way that I've seen that they have used to get around this is by overriding the commitproperties and invalidate functions in the skin class, grabbing the values for the properties they want from there, and then setting them to a locally instantiated variable inside the skin class. This is fine, but I feel like that is just a patch workaround to it which makes things a lot more complicated than it needs to be.
HERE'S MY QUESTION:
Is there any way to directly expose a bindable property from the host component class so when you define your skin class it is directly ready to be read from? Let's say you have custom button with a boolean property of 'selected'. In the skin class, you want to add in a get and set function for the property 'selected' so you can perform some action upon your skin whenever it's set. How do you tell the skin class that this is an available property for you to work with from the host component?
This question exists at a very theoretical level. I'm not clear what you're trying to accomplish, nor what sort of properties you're setting on your component class. I suspect, there is an architecture problem if you have 20 properties and each one needs to correlate to a different skin states somehow.
However, I can try to answer your specific questions.
Is there any way to directly expose a bindable property from the
host component class so when you define your skin class it is directly
ready to be read from?
When building Flex MobileSkins, they recommend creating a property named hostComponent which gives the skin class a reference to the component class. MXML skins already have a similar property. If you're using a custom skin, this property is created automatically using the HostComponent metadata. Therefore from the skin class you can access properties on the component class using the hostComponent property.
Let's say you have custom button with a boolean property of
'selected'. In the skin class, you want to add in a get and set
function for the property 'selected' so you can perform some action
upon your skin whenever it's set.
I'm not envisioning the situation where you would want to do this. Generally you would not define any properties on the skin class which you intend to explicitly change on the instance of the skin class.
You could dispatch an event from the component class when the property changes. [This is very common]. Then listen for that event in the skin class using the hostComponent property and change things there.
There is also a way to access the skin class instance from within the component class. So you could change properties directly on the skin class using the skin property.
I wouldn't follow either approach without thinking it through. Ideally the component class and skin class should be encapsulated from each other; and each approach would provide dependencies.
When you affect a skin to a component, you can use metatags to store a reference to the skin part you actually use :
[SkinPart(required="false")]
public var resizeHandle:UIComponent;
Then, when overriding the partAdded and partRemoved methods, you will be able to set or unset whatever you want in these skin parts, from the basic properties to event listeners.
override protected function partAdded( partName:String, instance:Object):void
{
super.partAdded(partName, instance);
if (instance == resizeHandle) {
resizeHandle.addEventListener(MouseEvent.MOUSE_DOWN, resizeHandle_mouseDownHandler);
}
}
override protected function partRemoved(partName:String, instance:Object):void
{
if (instance == resizeHandle) {
resizeHandle.removeEventListener(MouseEvent.MOUSE_DOWN, esizeHandle_mouseDownHandler);
}
super.partRemoved(partName, instance);
}
Furthermore, since you have stored a reference to your skin parts, you can still access it whenever you want in your host component and update it. Am I clear ? :-)

custom flex component, visual controls in design view

Do you know how if you drag an <mx:Label> or <s:Label> component into your Flex project, when you go to design mode you get this panel on the right to set its properties like text etc.
I have a custom component that I can call with actionscript, or with mxml like this:
<comps:TheComp field1="OK" field2="Yes" />
The component takes this input and uses it for its internal operation
private var field1:String;
private var field2:String;
private function initializeit()
{
// component takes the input and lays it out as needed
}
When I go to design mode, I can see the component under custom components, I can drag it to the stage and see it, but can't set its values field1 and field visually on the right like a normal <s:Label> or <mx:Label> would have.
Any idea how I can add that? Do I need to make it inherit something or anything else
Try using the [Inspectable] metatag in your code
[Inspectable]
private var field1:String;
[Inspectable]
private var field2:String;
Not sure if inspectable members can be private. If [Inspectable] alone doesn't do it, try making the vars public or protected.
You need to put any custom components you want to view this way into a library project and make a swc out of it, then use the swc instead of just the source code http://blog.another-d-mention.ro/programming/create-professional-flex-components/ .
HTH;
Amy
Those variables must be public. Variables are accessible from properties panel after setting them public.
public var field1:String;
public var field2:String;

Resources