get image asset from postLoad doctrine event - doctrine-orm

I created an Entity Listener to upload pictures.
Entity Listener
<?php
namespace AppBundle\Listener;
use ...
class PictureListener
{
private $manager;
public function __construct(PictureManager $manager)
{
$this->manager = $manager;
}
public function prePersist(PictureInterface $entity, LifecycleEventArgs $event)
{
$this->uploadFile($entity);
}
public function preUpdate(PictureInterface $entity, LifecycleEventArgs $event)
{
$this->uploadFile($entity);
}
public function postLoad(PictureInterface $entity, LifecycleEventArgs $event)
{
$fileName = $entity->getPicture();
if($fileName == NULL) {
return;
}
$file = new File($this->manager->getUploadDir().'/'.$fileName);
$entity->setPicture($file);
}
private function uploadFile($entity)
{
$file = $entity->getPicture();
if (!$file instanceof UploadedFile) {
return;
}
$fileName = $this->manager->upload($file);
$entity->setPicture($fileName);
}
}
Picture Manager
<?php
namespace AppBundle\Utils;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class PictureManager
{
private $uploadDir;
public function __construct($uploadDir)
{
$this->uploadDir = $uploadDir;
}
public function upload(UploadedFile $file)
{
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$file->move($this->uploadDir, $fileName);
return $fileName;
}
public function getUploadDir()
{
return $this->uploadDir;
}
}
I use the postLoad to get the absolute path of my pic and just call:
<img class="img-thumbnail" src="{{ category.picture }}" alt="{{ category.name }}">
to display it.
The generating src is
/Users/*******/Projects/*******/app/../web/uploads/pictures/8fcdaf996f1a30c5b64423ebc1284391.jpeg
and Symfony seems to not like absolute path because it does not work. 404 error. The upload file is in the right place.

Please try asset() in twig. It will target web folder of your application.
Syntax:
{{ asset('<File Name>') }}
Replace:
<img class="img-thumbnail" src="{{ category.picture }}" alt="{{ category.name }}">
With
<img class="img-thumbnail" src="{{ asset('uploads/pictures/'~category.picture) }}" alt="{{ category.name }}">
I have used it in symfony 2.3. Hope it will solve your issue

Related

How to display foreign key name in list table in Blazor Client Side

I am trying to display a subject name for a course where I saved the subject from a database driven dropdown list in a client-side Blazor app. The value returns as a Guid instead of the subject name. Has anyone accomplished this with Blazor? I couldn't find anything in the Blazor documentation or any tutorials that could solve the issue I'm having. This is in Blazor client-side and I am using Entity Framework Core
This is what my Course model looks like in the Shared project:
public class Course
{
public Guid CourseID { get; set; }
[Required]
public string CourseCode { get; set; }
[Required]
public string CourseName { get; set; }
public string CourseSubject { get; set; }
public string CourseCredits { get; set; }
}
This is what my Subject model looks like in the Shared project:
public class Subject
{
public Guid SubjectID { get; set; }
public string SubjectName { get; set; }
}
This is my CourseData Data Access Model in the Server project:
ApplicationDbContext db = new ApplicationDbContext ();
public IEnumerable<Course> GetAllCourses()
{
try
{
return db.Courses.ToList();
}
catch
{
throw;
}
}
public void AddCourse(Course course)
{
try
{
db.Courses.Add(course);
db.SaveChanges();
}
catch
{
throw;
}
}
This is my SubjectData Data Access Model in the Server project:
ApplicationDbContext db = new ApplicationDbContext ();
public IEnumerable<Subject> GetAllSubjects()
{
try
{
return db.Subjects.ToList();
}
catch
{
throw;
}
}
public void AddSubject(Subject subject)
{
try
{
db.Subjects.Add(subject);
db.SaveChanges();
}
catch
{
throw;
}
}
This is my Course Controller in the Server project:
CourseData objcourse = new CourseData();
[HttpGet]
[Route("api/Courses/Courses")]
public IEnumerable<Course> Index()
{
return objcourse.GetAllCourses();
}
[HttpPost]
[Route("api/Courses/Create")]
public void Create([FromBody] Course course)
{
if (ModelState.IsValid)
objcourse.AddCourse(course);
}
This is how I save the value in my Course creation page in my Client project:
#page "/Courses/Create"
#inject HttpClient Http
#inject Microsoft.AspNetCore.Components.NavigationManager NavigationManager
<h1>Add Course</h1>
<hr />
<div class="row">
<div class="col-md-4">
<div>
<div class="form-group">
<label for="CourseCode" class="control-label">Course Code</label>
<input for="CourseCode" class="form-control" #bind="#course.CourseCode" />
</div>
<div class="form-group">
<label for="CourseName" class="control-label">Course Name</label>
<input for="CourseName" class="form-control" #bind="#course.CourseName" />
</div>
<div class="form-group">
<label for="CourseSubject" class="control-label">Subject</label>
<select class="form-control" #bind="#course.CourseSubject">
<option></option>
#foreach (var subject in subjectList)
{
<option value="#subject.SubjectID">#subject.SubjectName</option>
}
</select>
</div>
<div class="form-group">
<label for="CourseCredits" class="control-label">Course Credits</label>
<input for="CourseCredits" class="form-control" #bind="#course.CourseCredits" />
</div>
<div class="form-group">
<button type="submit" class="btn btn-default" #onclick="#CreateCourse">Save</button>
<button class="btn" #onclick="#cancel">Cancel</button>
</div>
</div>
</div>
</div>
#functions {
List<Subject> subjectList = new List<Subject>();
Course course = new Course();
protected override async Task OnInitializedAsync()
{
subjectList = await Http.GetJsonAsync<List<Subject>>("api/Subjects/Subjects");
}
protected async Task CreateCourse()
{
await Http.SendJsonAsync(HttpMethod.Post, "/api/Courses/Create", course);
NavigationManager.NavigateTo("/Courses/Courses");
}
void cancel()
{
NavigationManager.NavigateTo("/Courses/Courses");
}
}
And finally this is my Courses list page in my Client project where it returns the Guid for the subject name, for which I would like to show the subject name instead of it's Guid:
#page "/Courses/Courses"
#inject HttpClient Http
<h1>Courses</h1>
<p>
Create New
</p>
#if (courseList == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class='table'>
<thead>
<tr>
<th>Course Code</th>
<th>Course Name</th>
<th>Subject</th>
<th>Credits</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
#foreach (var course in courseList)
{
<tr>
<td>#course.CourseCode</td>
<td>#course.CourseName</td>
<td>#course.CourseSubject</td>
<td>#course.CourseCredits</td>
<td>
<a href='/Courses/Edit/#course.CourseID'>Edit</a> |
<a href='/Courses/Delete/#course.CourseID'>Delete</a>
</td>
</tr>
}
</tbody>
</table>
}
#functions {
Course[] courseList;
protected override async Task OnInitializedAsync()
{
courseList = await Http.GetJsonAsync<Course[]>
("/api/Courses/Courses");
}
}
Database Context as requested:
public class ApplicationDbContext : DbContext
{
public virtual DbSet<Course> Courses { get; set; }
public virtual DbSet<Subject> Subjects { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(#"REMOVED-FOR-SECURITY");
}
}
}
Help would be much appreciated.
Other answers are good but let me give you something else to think about...
When writing Blazor apps try to think in terms of components more often than of code.
For example, let's say that the Subjects are static data that doesn't change a lot. So if every time you show a list, or want to build a dropdown for them, you're potentially going to have to make a database call or a SQL JOIN? So my first thought would be to create a lookup cache for GUID-to-Subject-name. And since this is Blazor if it's cached on the client you no longer need to make a database or API call - it's loaded once.
Then, since we're in Blazor, I'd create a <SubjectName> component, e.g.
Subject: <SubjectName Id="#Model.SubjectId" />
The component uses the cache to get the value, it can handle a null value, it can handle an invalid subject ID. You've encapsulated a lot of behaviour and error handling in a single place, and can re-use that every time you need to map an ID to a subject name.
Similarly I'd create a <SubjectDropdown> component to show a list of subjects, again using the cache.
You set CourseSubject with the SubjectID with is a Guid, so you get a Guid.
If you want to display the subject name either, request the subject by its Guid, or return the Subject in your course:
public class Course
{
public Guid CourseID { get; set; }
[Required]
public string CourseCode { get; set; }
[Required]
public string CourseName { get; set; }
public string CourseSubject { get; set; }
public string CourseCredits { get; set; }
public virtual Subject Subject { get; set; }
}
public IEnumerable<Course> GetAllCourses()
{
try
{
return db.Courses
.Include(c => c.Subject)
.ToList();
}
catch
{
throw;
}
...
}
#foreach (var course in courseList)
{
<tr>
<td>#course.CourseCode</td>
<td>#course.CourseName</td>
<td>#course.Subject.SubjectName</td>
<td>#course.CourseCredits</td>
<td>
<a href='/Courses/Edit/#course.CourseID'>Edit</a> |
<a href='/Courses/Delete/#course.CourseID'>Delete</a>
</td>
</tr>
}

Vue.js: Inline if-else statement inside <form> with multiple conditions

Is there a way to make inline if-else statement with multiple conditions in Vue?
I have this code in vue:
<template>
<div class = "modal-dialog">
<div class = "modal-header"> <h5>Header</h5></div>
<div class="modal-body">
<form #submit.prevent="editMode ? updateParticipant() : addParticipant()">
/* actual form inside modal body */
</form>
</div>
</div>
</template>
However, I have another boolean variable queryMode. So, I want to also check its value before I execute the methods. More of a nested statement like this:
if(editMode) {
if(queryMode) {
updateParticipant();
} else {
//another method
}
} else {
addParticipant();
}
I have searched about v-if, v-else-if and v-else, but I don't know how to integrate them in my current code structure.
I would have a single handler:
<form #submit.prevent="onSubmit">
with:
methods: {
onSubmit () {
if (this.editMode) {
if (this.queryMode) {
this.updateParticipant();
} else {
//another method
}
} else {
this.addParticipant();
}
}
}
You could, in theory, write it all inline but it would be difficult to read:
<form #submit.prevent="editMode ? queryMode ? updateParticipant() : anotherMethod() : addParticipant()">
You could put some parentheses in but that wouldn't be much better.

Doctrine with ZF2 Annotation: how to clear a multi select field?

I've got a problem with my multi select fields. Here is the code:
In the Entity class
/**
* #Annotation\Options({ "disable_inarray_validator":"true", "label":"Bound Checkpoints", "target_class":"Checkpoint","property":"name"})
* #Annotation\Type("DoctrineORMModule\Form\Element\EntitySelect")
* #Annotation\Attributes({ "multiple":"true", "class":"form-control"})
* #Annotation\Required(false)
* #ORM\ManyToMany(targetEntity="Checkpoint", inversedBy="affectedByCheckpoints")
*/
private $boundCheckpoints;
public function __construct() {
$this->boundCheckpoints= new \Doctrine\Common\Collections\ArrayCollection();
}
public function addBoundCheckpoints( $items)
{
foreach($items as $item)
{
$this->boundCheckpoints->add($item);
}
}
public function removeBoundCheckpoints($items)
{
foreach($items as $item)
{
$this->boundCheckpoints->removeElement($item);
}
}
My issue is: if I set some stuff into the field, it save it well. If I remove one, still working. But if I remove all items I set and fire the form, the removeBoundCheckpoints method is never called.
I tried to set a required validator to the form, but If I do that, I've got a validation issue.
Any ideas ?
solved by adding this workaround into the template.
{% if field.getAttribute('multiple') == 'multiple' or field.getAttribute('multiple') == 'true' %}
<input type="hidden" name="{{field.getName()}}" value="" />
{% endif %}
{{formElement(field) }}

MVC 4 - sorting with LINQ doesn't work with Ajax.BeginForm and my For loop

I writing some code with C# and MVC and I have button for sorting a list of data by asc and desc. The logic works in my controller, I am able to call the method that sorts the list and in the breakpoint I can see that it has been sorted.
But it's weird because when I loop through my list in the partial view it never works. I use a breakpoint in my view to make sure it's the same order of items which it is. But it's like the new values don't render to the screen.
TeamManagement.cshtml
#model Website.Models.modelTeamSelect
#{
ViewBag.Title = "Football App";
}
#section featured {
}
#using (Ajax.BeginForm("_PartialTeams",
new
{
model = this.Model
},
new AjaxOptions
{
HttpMethod = "POST",
UpdateTargetId = "divCreatedTeams",
InsertionMode = InsertionMode.Replace
}))
{
<div id="divTeams" style="float: left; padding: 10px;">
<h3>Create a new team:</h3>
#Html.LabelFor(m => m.team.TeamName)
#Html.TextBoxFor(m => m.team.TeamName)
<input type="submit" value="Add Team" name="btnSubmit" />
</div>
Html.RenderPartial("~/Views/Partials/_PartialTeams.cshtml");
}
_PartialTeams.cshtml
#model Website.Models.modelTeamSelect
<div id="divCreatedTeams" style="float: left; padding: 10px;">
<h3>Your created teams:</h3>
<input type="submit" value="Asc" name="btnSubmit" />
<input type="submit" value="Desc" name="btnSubmit" />
<br />
#if (Model.teams.Count > 0)
{
for (int i = 0; i < Model.teams.Count; i++)
{
#Html.EditorFor(m => m.teams[i].TeamName)
<input type="button" value="Update team name" name="btnSubmit"/>
<input type="button" value="Remove team" name="btnSubmit"/>
<br />
}
}
</div>
Sorting logic in my controller
[HttpPost]
public PartialViewResult _PartialTeams(string BtnSubmit, modelTeamSelect modelTeamSelect)
{
switch (BtnSubmit)
{
case "Add Team":
modelTeamSelect.teams.Add(modelTeamSelect.team);
break;
case "Asc":
FootballRepository = new Repository.FootballRepository();
modelTeamSelect.teams = FootballRepository.Sort(modelTeamSelect, BtnSubmit);
break;
case "Desc":
FootballRepository = new Repository.FootballRepository();
modelTeamSelect.teams = FootballRepository.Sort(modelTeamSelect, BtnSubmit);
break;
}
return PartialView("~/Views/Partials/_PartialTeams.cshtml", modelTeamSelect);
}
public List<Models.modelTeam> Sort(Models.modelTeamSelect modelTeamSelect, string sort)
{
switch (sort)
{
case "Asc":
modelTeamSelect.teams = modelTeamSelect.teams.OrderBy(t => t.TeamName).ToList();
break;
case "Desc":
modelTeamSelect.teams = modelTeamSelect.teams.OrderByDescending(t => t.TeamName).ToList();
break;
}
return modelTeamSelect.teams;
}
My main model with team collection
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Website.Models
{
public class modelTeamSelect
{
public modelTeamSelect()
{
teams = new List<modelTeam>();
team = new modelTeam();
}
public List<modelTeam> teams { get; set; }
public modelTeam team { get; set; }
}
}
My method Sort does it's job but in the view it never displays correctly. e.g. always wrong order.
Anyone have any ideas because I am stuck.
Screenshots
In the screenshots I click sort by Asc and you can see it says Newcastle as the first item in the list. But when the page renders it will say West Ham first even though it is iterating using the for loop.
All the Html helpers are preferring to use the ModelState values over the actual model values.
So even you have sorted in place your modelTeamSelect.teams in your action in the view #Html.EditorFor(m => m.teams[i].TeamName) call will use the original (before sorting) values form the ModelState.
The solution: if you are updating your action parameters in-place then just clear the ModelState before returning the View/PartialView:
[HttpPost]
public PartialViewResult _PartialTeams(string BtnSubmit,
modelTeamSelect modelTeamSelect)
{
// ... Do the sorting, etc.
ModelState.Clear();
return PartialView("~/Views/Partials/_PartialTeams.cshtml", modelTeamSelect);
}
You can read more about why the helpers are working like this in this article: ASP.NET MVC Postbacks and HtmlHelper Controls ignoring Model Changes

Load PHP file with document.createElement()

How could I make this work? I want to load a php file like this:
Click button.
Call Javascript function.
In Javascript function create an img with src file.php.
This should force the loading of the php. Here is the code.
<script type="text/javascript">
var d;
function callSave() {
alert ('calling');
if (d) document.body.removeChild(d);
// d = document.createElement("script");
d = document.createElement("img");
d.src = "savepages.php";
//d.type = "text/javascript";
document.body.appendChild(d);
}
</script>
Then in savepages.php I do another alert to verify that the php is called and it isn't. Here is the savepages.php.
<?php
echo "alert('from the php');";
?>
The alert from the php doesn't happen. Is there a different element type that will force loading of the php? I don't have ajax installed, so I need a workaround like this.
Thanks.
You could use an iframe element
<script type="text/javascript">
var d;
function callSave() {
alert ('calling');
if (d) document.body.removeChild(d);
d = document.createElement("iframe");
d.src = "savepages.php";
document.body.appendChild(d);
}
</script>
Found out the better way to handle this. There is this simple code that explains how to call a javascript function from a form event and from that javascript function load a PHP file. The code found at http://daniel.lorch.cc/docs/ajax_simple/ is also given here:
<script type="text/javascript">
var http = false;
if(navigator.appName == "Microsoft Internet Explorer") {
http = new ActiveXObject("Microsoft.XMLHTTP");
} else {
http = new XMLHttpRequest();
}
function validate(user) {
http.abort();
http.open("GET", "validate.php?name=" + user, true);
http.onreadystatechange=function() {
if(http.readyState == 4) {
document.getElementById('msg').innerHTML = http.responseText;
}
}
http.send(null);
}
</script>
<h1>Please choose your username:</h1>
<form>
<input type="text" onkeyup="validate(this.value)" />
<div id="msg"></div>
</form>
validate.php
<?php
function validate($name) {
if($name == '') {
return '';
}
if(strlen($name) < 3) {
return "<span id=\"warn\">Username too short</span>\n";
}
switch($name) {
case 'bob':
case 'jim':
case 'joe':
case 'carol':
return "<span id=\"warn\">Username already taken</span>\n";
}
return "<span id=\"notice\">Username ok!</span>\n";
}
echo validate(trim($_REQUEST['name']));
?>