Display image stored in BLOB database in symfony - symfony

I load my image (blob data ) in my GETer Entity
When I just return ($this->foto) in my GETer I see :Resource id #284 on the screen
When I change my GETer like this : return stream_get_contents($this->foto);
I see these : ���JFIF��� ( ,,,,,,,, ( and more )
In my Controller a call the index.html.twig to show all my entities
/**
* Lists all Producten entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('CustomCMSBundle:Producten')->findAll();
return $this->render('CustomCMSBundle:Producten:index.html.twig', array(
'entities' => $entities,
));
}
Now in my views ( index.html.twig ) I like to show the picture
{% for entity in entities %}
<tr>
<td>
<img src="{{ entity.foto}}" alt="" width="80" height="80" />
</td>
<td>
{{ entity.foto }}
</td>
<td>
<ul>
<li>
show
</li>
<li>
edit
</li>
</ul>
</td>
</tr>
{% endfor %}
But I don't see the picture ?
Can anyone help me?

You are using <img src="(raw image)"> instead of <img src="(image's url)">
A quick solution is to encode your image in base64 and embed it.
Controller
$images = array();
foreach ($entities as $key => $entity) {
$images[$key] = base64_encode(stream_get_contents($entity->getFoto()));
}
// ...
return $this->render('CustomCMSBundle:Producten:index.html.twig', array(
'entities' => $entities,
'images' => $images,
));
View
{% for key, entity in entities %}
{# ... #}
<img alt="Embedded Image" src="data:image/png;base64,{{ images[key] }}" />
{# ... #}
{% endfor %}

in your entity write your image getter like this:
public function getFoto()
{
return imagecreatefromstring($this->foto);
}
and use it instead of the object "foto" property.
php doc for the function: http://php.net/manual/de/function.imagecreatefromstring.php

A more direct way, without extra work in the controller:
In the Entity Class
/**
* #ORM\Column(name="photo", type="blob", nullable=true)
*/
private $photo;
private $rawPhoto;
public function displayPhoto()
{
if(null === $this->rawPhoto) {
$this->rawPhoto = "data:image/png;base64," . base64_encode(stream_get_contents($this->getPhoto()));
}
return $this->rawPhoto;
}
In the view
<img src="{{ entity.displayPhoto }}">
EDIT
Thanks to #b.enoit.be answer to my question here, I could improve this code so the image can be displayed more than once.

As it is said before you must use base64 method, but for a better performance and usability, the correct option is creating a custom twig filter (Twig extension) as described here .
<?php
namespace Your\Namespace;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
class TwigExtensions extends AbstractExtension
{
public function getFilters()
{
return [
new TwigFilter('base64', [$this, 'twig_base64_filter']),
];
}
function twig_base64_filter($source)
{ if($source!=null) {
return base64_encode(stream_get_contents($source));
}
return '';
}
}
In your template:
<img src="data:image/png;base64,{{ entity.photo | base64 }}">

Related

What is the better solution to get the Entity I want in a biderectional OneToMany relation?

I have one entity Article and an other entity Image with a bidrectional relation OneToMany and ManyToOne :
class Article
{
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Image", mappedBy="article")
*/
private $images;
}
class Image
{
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Article", inversedBy="images")
* #ORM\JoinColumn(nullable=true)
*/
private $article;
}
In my controller I use #paramconverter to get the article I want :
/**
* #Route("/blog/{slug}", name="article")
* #ParamConverter("article", class="AppBundle:Article")
*/
public function articleAction(Article $article)
{
return $this->render('default/article.html.twig', array(
'article' => $article,
));
}
Now my problem is that I want to identify the ONLY image with the attributes "main = true" in all the "article.images" I have.
What is the best solution?
In my wiew I can do somehting like this but it's not the best I think :
{% for image in article.images %}
{% if image.main %}
<img src="{{ asset( image.src ) }}" alt="{{ image.alt }}" title="{{ image.title }}">
{% endif %}
{% endfor %}
I'd like to use something like :
{{ article.mainImg }}
How can I achieve this please? And is this the best solution?
Doctrine provides a collection filter mechanism you could use to get the "main image":
public function articleAction(Article $article)
{
$criteria = Criteria::create()
->where(Criteria::expr()->eq("main", true))
->setMaxResults(1);
$mainImg = $article->getImages()->matching($criteria)->first();
return $this->render('default/article.html.twig', array(
'article' => $article,
'mainImg' => $mainImg
));
}
More information on filtering doctrine collections: Filtering collections
I did not test the code myself, but it should convey the idea of how it can be done.

Passing multiple arguments through twig path

I have this twig code:
<div style="padding-left: 5em" class="comment">
<p>{{ comment.author.name }} - {{ comment.created|date('j. n. Y H:i') }}</p>
<p>{{ comment.text }}</p>
<p>Odpovědět na komentář</p>
{% for child in comment.children %}
{% include 'BlogApplicationBundle:Post:_comment.html.twig' with {'comment' : child}%}
{% endfor %}
</div>
and this is function that processes the output from link in twig code:
/**
* #Route("/post/{id}/newcommentresponse", name="comment_response_new")
* #Template("BlogApplicationBundle:Post:form.html.twig")
*/
public function commentResponceAction($id,$idc)
{
$comment = new Comment();
$form = $this->createForm(new CommentType(), $comment);
return array(
'form' => $form->createView()
);
}
when i try to run code i get this error :
Controller "Cvut\Fit\BiWt1\Blog\ApplicationBundle\Controller\CommentController::commentResponceAction()"
requires that you provide a value for the "$idc" argument (because
there is no default value or because there is a non optional argument
after this one).
So it seems that second argument passsed through link is ignored and i have no idea what am i doing wrong.
You are missing the $idc definition in your #Route annotation. It should look something like this:
#Route("/post/{id}/newcommentresponse/{idc}", name="comment_response_new")
or this:
#Route("/post/{id}/{idc}/newcommentresponse", name="comment_response_new")
You can also leave it out of the route and function declaration and grab it directly from the Controller:
/**
* #Route("/post/{id}/newcommentresponse", name="comment_response_new")
* #Template("BlogApplicationBundle:Post:form.html.twig")
*/
public function commentResponceAction($id)
{
$idc = $request->query->get('idc');

Sonata admin tabs in page

I use Sonata admin Generator.
I'd like to create multiple lists from a symfony class.
For example I have a list of invoices and I would like to create a tab with paid bills, an other tab with pending bills and a last tab with invoices disabled.
This status is in the class.
I saw this page(admin/admin) in the Sonata demo who use context but I wouldn't like install mediabundle if it's possible.
It is possible without the mediabundle.
I had the same use-case as you with 'project-statuses'. These statuses are in my database.
A few steps are necessary:
Override the CRUDController. Maybe this step isn't needed, but I couldn't figure out how to without. I want to display the different statuses as tabs, so I inject a collection in the list-template.
Make your own CRUDController:
namespace Your\OwnBundle\Controller;
use Sonata\AdminBundle\Controller\CRUDController as Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
class ProjectCrudController extends Controller
{
/**
* {#inheritdoc}
*
* #param Request $request
*/
public function render($view, array $parameters = array(), Response $response = null, Request $request = null)
{
$projectStatusRepo = $this->getDoctrine()->getRepository('EvinceObjectsBundle:ProjectStatus');
// here inject the params you'll need
// you can do it only when $parameters['action'] == 'list' if you want
$parameters['projectStatuses'] = $projectStatusRepo->findAll();
$parameters['activeProjectStatus'] = $request->get('status', 1);
return parent::render($view, $parameters, $response);
}
}
Inject your own CRUDController in the services.yml (or xml)
sonata.admin.project:
class: Your\OwnBundle\Admin\ProjectAdmin
tags:
- { name: sonata.admin, manager_type: orm, group: "project", label: "Project" }
arguments:
- ~
- Your\OwnBundle\Entity\Project
- YourOwnBundle:ProjectCrud
calls:
- [ setLabelTranslatorStrategy, ["#sonata.admin.label.strategy.underscore"]]
- [ setTemplate, [list, YourOwnBundle:ProjectAdmin:list.html.twig]]
Notice the setTemplate-call, so lets create your template
Create your own list-template
{% extends 'SonataAdminBundle:CRUD:base_list.html.twig' %}
{% block preview %}
<ul class="nav nav-pills">
<li><a><strong>{{ "label.select_projectstatus"|trans({}, 'SonataProjectBundle') }}</strong></a></li>
{% for projectStatus in projectStatuses %}
{% set active = false %}
{% if projectStatus.id == activeProjectStatus %}
{% set active = true %}
{% endif %}
<li class="{% if active %}active{% endif %}" >{{ projectStatus.status }}</li>
{% endfor %}
</ul>
{% endblock %}
Override the Admin::getFilterParameters function in your own admin class. Here you want to set the filter based on your requestparam:
/**
* {#inheritdoc}
*/
public function getFilterParameters()
{
$parameters = parent::getFilterParameters();
return array_merge(array(
'status' => array(
'type' => '',
'value' => $this->getRequest()->get('status', 1),
)
), $parameters);
}

echoing variable gets "Resource id"

Using symfony2 I load some entities and then try to iterate over them in a twig template.
However, instead of the variable content I am getting the following:
Resource id #23
My twig template looks like this:
<ol>
{% for post in posts %}
<li>
<div>
{{ post.content }}
</div>
</li>
{% endfor %}
</ol>
My controller code is:
$repository = $this->getDoctrine()
->getRepository('AppPostBundle:Post');
$reviews = $repository->findBy(
array('title' => 'my title'))
;
Maybe is too late for this answer (definitely it is LOL) but I recently had the same issue and the problem is that blob datatypes are treated as a buffer, so you have to read the info using buffer functions.
In your entity Post code you may add this method:
public function readContent(){
$content = '';
while(!feof($this->getContent())){
$content.= fread($this->getContent(), 1024);
}
rewind($this->getContent());
return $content;
}
Then in your views you may call the readcontent method instead of content:
<ol>
{% for post in posts %}
<li>
<div>
{{ post.readcontent }}
</div>
</li>
{% endfor %}
</ol>
Is better late than never :)
My entity name is : 'Test'
Blob type field is : 'Details'
in '/src/Vendorname/Bundlename/Entity/entityname.php'
**
* Get details
*
* #return string
*/
public function getDetails()
{
return $this->details;
}
/**
* Reading the blob type of content.
* #return data
*/
public function readDetails(){
$details = '';
while(!feof($this->getDetails())){
$details.= fread($this->getDetails(), 1024);
}
rewind($this->getDetails());
return $details;
}
and in '*.html.twig' file
{% for match in matches %}
{{match.readdetails}}
{%endfor%}

How to load a controller function and render it in a twig tag using Symfony2?

I am using Symfony2 and Twig. I have a function (below) in my controller that returns a specific text. Is it possible to call that function directly from my template and change the {{text}} in my template to whatever the function returns, possibly via Ajax?
Here's my function:
public function generateCode($url) {
$url = $_SERVER['SERVER_NAME'] . '/embed/' . $url;
$return = '<iframe>'.$url.'</iframe>';
return $return;
}
Another controller function calls the function above and renders my template:
public function getCodeAction($url) {
$text = $this->generateCode($url);
return $this->render('MyMyBundle:User:code.html.twig', array('text' => $text));
}
In my template I am using:
{{ text }}
to display the value.
In Symfony 2.2, this was changed.
The render tag signature and arguments changed.
Before:
{% render 'BlogBundle:Post:list' with { 'limit': 2 }, { 'alt': BlogBundle:Post:error' } %}
After:
{% render controller('BlogBundle:Post:list', { 'limit': 2 }), { 'alt': 'BlogBundle:Post:error' } %}
or
{{ render(controller('BlogBundle:Post:list', { 'limit': 2 }), { 'alt': 'BlogBundle:Post:error'}) }}
Note: The function is the preferred way.
See https://github.com/symfony/symfony/blob/2.2/UPGRADE-2.2.md
You can use ajax if you have dynamic data, but as far as I can see from your brief info, you can always execute that controller function directly from your view:
{% render "MyMyBundle:User:generateCode" with { 'url': 'your url here' } %}
More Information on this available at:
http://symfony.com/doc/2.0/quick_tour/the_view.html, under Embedding other Controllers
For the record, in new versions you need to use the absolute URL:
{{ render url('my_route_id', {'param': value}) }}
{{ render(controller("AcmeDemoBundle:Demo:topArticles", {'num': 10})) }}
In Silex I solved it like this:
{{ render(url('route_name', {'param': value})) }}
If you do not have the route name, URL can be used:
{{ render(app.request.baseUrl ~ '/some-path/' ~ value) }}
If using URL we should always concat the baseUrl.
Symfony 2.6+
in twig:
{{ render(controller('AppBundle:PropertySearch:featuredProperties', {'limit': 15})) }}
controller:
/**
* featuredPropertiesAction
*
* #param Request $request
* #param int $limit
*
* #return Response
*/
public function featuredPropertiesAction(Request $request, $limit)
{
$search = $this->resultsHelper->featuredSearch($limit);
return $this->render('HASearchBundle::featured_properties.html.twig', [
'search' => $search,
]);
}

Resources