Why image from blob field displays only once? - doctrine

I overrided FOSUserBundle.
I changed my avatar field getter and setter in user Entity (This Entity extends FOSUser Entity) to this:
/**
* #ORM\Column(type="blob")
*/
protected $avatar;
public function setAvatar($avatar) {
if ($avatar != null) {
$strm = fopen($avatar->getRealPath(), 'rb');
$this->avatar = stream_get_contents($strm);
}
return $this;
}
public function getAvatar() {
if ($this->avatar != null) {
return base64_encode(stream_get_contents($this->avatar));
} else {
return $this->avatar;
}
}
And it works but only in first render
<img alt="User avatar" src="data:image;base64,{{app.user.avatar}}"/> //working
<img alt="User avatar" src="data:image;base64,{{app.user.avatar}}"/> //not working
If i try display this field first time all is ok and each next render shows empty string. Why? How fix this?
Other fields works fine.

Doctrine will not use your setters to populate your entity when it is loaded from the database. Thus, when you first call getAvatar(), stream_get_contents() is executed and reads everything from the stream. The next time this getter method is called, there is nothing left to read from the stream. You will probably want to save the string returned by stream_get_contents() in the $avatar property when getAvatar() is called like you do in setAvatar().

Related

TempData not kept between postback

I need some advice on how to proceed with the mvc app I'm building. On my page I type out who is logged in to the page. This I first did by creating a base class where I created a user class which contained the users name and a image representing the user. Then I passed this class on to my views. But I also need to pass other models to my views depending on what view I'm in. Sure I could build a class that contain all different models I need to use on each page but there should be a easy way to pass name and image values across the pages and be persistant? I tried TempData together with TempData.Keep() but that was not persistant. How can I pass theses values between pages?
public ActionResult Validate(AccountModels.LoginModel model)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
var mu = _repo.GetUser(Membership.GetUser().ProviderUserKey.ToString());
TempData["Name"] = mu.Name;
TempData["Image"] = mu.Image;
TempData.Keep();
FormsAuthentication.RedirectFromLoginPage(model.UserName, model.RememberMe);
}
}
return View("Index");
}
As #Jyoti said, you could use of Keep() method.
To make it easy to work with TempData, I wrote these methods in my BaseController, and I use it in every controller when I need to transfer data between actions or between view and controller.
protected TReturnType GetTempDataValue<TReturnType>(PsmConstants.TempDataKey sessionName, bool peekData =false )
{
object value = peekData ? TempData.Peek(sessionName.ToString()) : TempData[sessionName.ToString()];
return (TReturnType) value;
}
protected void RemoveTempData(PsmConstants.TempDataKey sessionName)
{
if (TempData.ContainsKey(sessionName.ToString()) && TempData[sessionName.ToString()] == null) return;
TempData[sessionName.ToString()] = null;
}
protected void SetTempDataValue(PsmConstants.TempDataKey sessionName, object value)
{
if(TempData.ContainsKey(sessionName.ToString()))
TempData[sessionName.ToString()]=null;
TempData[sessionName.ToString()] = value;
}
protected void KeepTempDataValue(PsmConstants.TempDataKey sessionName)
{
if (TempData.ContainsKey(sessionName.ToString()))
TempData.Keep(sessionName.ToString());
}
And this is the Keys enumeration :
public enum TempDataKey
{
PageError = 1,
PageInfo = 2
}
And this is, the usage of these methods(Set value and Get value from TempData):
SetTempDataValue(PsmConstants.TempDataKey.PageError , 'your error message' );
var originalValues = GetTempDataValue<MyModel>(PsmConstants.TempDataKey.Info, true);
Use session instead of Temp if it is not working.but i think it should work.
TempData["Name"] = mu.Name;TempData["Image"] = mu.Image;TempData.Keep();
How you are passing this into other models,Please share the source code so that it will easy to identify.

Tapestry 5.3: Component with form inside t:zone

I have a component for editing db entity. It has #CommitAfter on onSuccess(). When it is on the separate page it works fine. I click update button, it saves data and redirects to view page.
Now I want to reuse it on the list page. By clicking on item it should appear. After editing and clicking update button on the component it should save item to db and hide itself.
To achieve this I modified component so I can set zone id for its form. Put component inside zone on the list page, added links for each item with event onSelectItem, which sets zone id for component and returns body of the zone.
It did show component and I could edit fields and hit update button. It updated item but redirected whole page to view page. I tried to return null in onSuccess() – but in this case it didn’t save data to db and zone also wasn’t refreshed. I also tried call page class from a component by using #InjectPage and return page.zone.getBody() – this does reload zone but still doesn’t save data though all methods passed w/o exception. Also it too bad to call page specific code inside a component. My other custom ajax calls do save data to db in methods with #CommitAfter.
So my question what is the correct way of doing this in Tapestry?
ContactsList.tml
<html t:type="layout" xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd" xmlns:p="tapestry:parameter">
<t:form>
... list of contacts linked to onSelectContact()
</t:form>
<t:zone id="editContact" t:id="editContactZone">
<t:if test="selectedContact">
<t:contactform t:id="contactForm" />
</t:if>
</t:zone>
</html>
ListPage.java
public class ContactsList{
#InjectComponent
private Zone editContactZone;
#InjectComponent("contactForm")
private ContactForm contactForm;
#Property
private Contact selectedContact;
public Object onSelectContact(#RequestParameter(value = "id", allowBlank = false) Integer id) {
selectedContact = getContactById(id);
if (selectedContact != null) {
contactForm.setContact(selectedContact);
contactForm.setFormZone(editContactZone.getClientId());
}
return editContactZone.getBody();
}
}
ContactForm.tml
<div xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter">
<t:form t:id="editContactForm" zone="prop:zone">
.... contact fields
</t:form>
</div>
ContactForm.java
public class ContactForm{
#InjectComponent("editContactForm")
private Form editContactForm;
#Property
private String zone;
#InjectPage
private ContactList listPage;
#InjectPage
private ViewContact viewContact;
#Property
protected Contact contact;
public void setContact(Contact contact) {
this.contact = contact;
}
public void setFormZone(String zone){
this.zone = zone;
}
#CommitAfter
public Object onSuccess() {
parseContact();
storeContact(); // calls DAO.store(contact)
return zone == null ? viewContact : listPage.onSelectContact(0); //don't like this in component code but at least it returns zone's body
}
}
You could pass a Block component parameter to the ContactForm containing the markup to render after #OnSuccess.
Or perhaps a better separation of concerns is to fire an event in the ContactForm which bubbles up to the page? Eg:
ContactForm.java
#Inject ComponentResources resources;
#CommitAfter
public void onSuccess() {
storeContact();
resources.triggerEvent("contactSaved", new Object[] { contact }, null);
}
ContactsList.java
#Inject AjaxResponseRenderer ajaxRenderer;
#Inject Zone someZone;
#Property Contact contact;
public void onContactSaved(Contact contact) {
this.contact = contact;
ajaxRenderer.addRender(someZone);
}
Also, why are you using #RequestParameter? Why not use event context?
ContactsList.tml
<t:loop source="contacts" item="contact">
<t:eventlink event="selectContact" context="contact">Edit ${contact.name}</t:eventlink>
</t:loop>
ContactList.java
Block onSelectContact(Contact contact) {
// doStuff
}

How can I filter fields before they reach Input::get("my_field")?

I want for example to remove the word "fck" of all input fields. I know I can do it after but it would be great if I can do it before so it applies to my entire app.
In other words, where do I have to modify the Input (or http or request) class of Laravel 4?
Well, there are a few possibilities. The easiest and simplest one is to simply make a new Input facade and override its get method. Something like this:
app/extensions/FilterableInput.php
use Illuminate\Support\Facades\Input as IlluminateInput;
class FilterableInput extends IlluminateInput {
public static function get($key = null, $default = null)
{
return static::filterInput(parent::get($key, $default));
}
// Filtering method
protected static function filterInput($value)
{
if (is_string($value))
{
return str_replace('fck', '***', $value);
}
return $value;
}
}
Don't forget to replace the Input alias on app/config/app.php with FilterableInput and to add app/extensions to your composer.json autoload.classmap settings.

ID in Spring-MVC 2.5 edit form using #Controller

I have a problem with the my Controller code. GET works fine (both empty form + form populated from db), POST works fine only for creating new object, but doesn't work for editing. Part of my #Controller class:
#RequestMapping(value = "/vehicle_save.html", method = RequestMethod.GET)
public String setUpForm(#RequestParam(value="id", required = false) Long id, ModelMap model) {
Vehicle v;
if (id == null) {
v = new Vehicle();
} else {
v = vehicleManager.findVehicle(id);
}
model.addAttribute("vehicle", v);
return "vehicle_save";
}
#RequestMapping(value = "/vehicle_save.html", method = RequestMethod.POST)
public String save(#ModelAttribute("vehicle") Vehicle vehicle, BindingResult result, SessionStatus status) {
vehicleValidator.validate(vehicle, result);
if (result.hasErrors()) {
return "vehicle_save";
}
if(vehicle.getId() == null) {
vehicleManager.createVehicle(vehicle);
} else {
vehicleManager.updateVehicle(vehicle);
}
status.setComplete();
return "redirect:vehicle_list.html";
}
The first method creates a vehicle object (including its ID). But the second method gets the same object without the ID field (set to null).
What could I do: manually set vehicle.setID(id from parameters) and then save it to database. This causes JPAOptimisticLockException + I don't like that solution.
Is there a way to pass my Vehicle object with ID to the second method? BTW, I would like to avoid adding hidden ID field to the JSP.
the example you suggested is using session to store the value. the #SessionAttribute is to bind an existing model object to the session. Look at the source code the class is annotated with #SessionAttributes("pet").Which means your model attribute named "pet" is getting stored in session.Also look at the code in processSubmit method of EditPetForm class
#RequestMapping(method = { RequestMethod.PUT, RequestMethod.POST })
public String processSubmit(#ModelAttribute("pet") Pet pet, BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "pets/form";
}
else {
this.clinic.storePet(pet);
status.setComplete(); //look at its documentation
return "redirect:/owners/" + pet.getOwner().getId();
}
}
I havnt used something like this before.But i guess putting ur id in session is the way
BTW, I would like to avoid adding hidden ID field to the JSP.
This is common solution. What's wrong with it ? You should create hidden input with id.
May be you can try using session, cause you cant store info between two request. But that will be uglier i guess.
Btw, Can you please explain a little why you want to avoid adding hidden fields? I'm little curious

Show graphic next to a textbox if it failed validation

I have a simple MVC form: First name, Email Address which are both required. If the user hits the submit button I would like to display a graphic next to the textboxes that failed validation.
I am using Data Annotations and Validation summary already.
Thank you!
I would try something like this:
//ViewModelClass
public class yourViewModel
{
//...
bool showPictureName {get;set;}
}
//controller
{
//...
var NameErrors = ModelState["yourViewModel.Name"].Errors;
if(!Modelstate.IsValid)
{
// put your code here
if(NameErrors.Count() != 0)
yourViewModelObject.showPictureName = true;
}
}
//View
#{ if(Model.showPictureName == true)
<img .../>
}

Resources