Using raw Cypher to query Neo4j in Symfony - symfony

I am trying to go throught this tutorial: http://www.sitepoint.com/adding-social-network-features-php-app-neo4j/ But using the Symfony Framework instead of Silex.
I have been able to set up Neo4j to run with Symfony and am able to right user data to the graph. Now I would like to display all user email addresses in a list. I have taken this script:
public function home(Application $application, Request $request)
{
$neo = $application['neo'];
$q = 'MATCH (user:User) RETURN user';
$result = $neo->sendCypherQuery($q)->getResult();
$users = $result->get('user');
return $application['twig']->render('index.html.twig', array(
'users' => $users
));
}
And adapted it to read:
public function showUsersAction()
{
$em = $this->container->get('neo4j.manager');
$query = 'MATCH (n:`User`) RETURN n';
$users = $em->cypherQuery($query);
//print_r($users);
return $this->render('UserBundle:Account:showUsers.html.twig', array('users' =>$users));
}
And The twig looks as follows:
{% extends '::base.html.twig' %}
{% block content %}
<h1>get all users:</h1>
<ul>
{% for user in users %}
<li>{{ user.property('email') }}</li>
{% endfor %}
</ul>
{% endblock %}
But something in the twig is wrong, im getting the error:
Method "property" for object "Everyman\Neo4j\Query\Row" does not exist in UserBundle:Account:showUsers.html.twig at line 6

The problem was found in the syntax of the twig file. After consulting this page: https://github.com/jadell/neo4jphp/wiki/Cypher-and-gremlin-queries it became clear, that I had to include user['n'] in my twig template. The twig template now looks as such:
{% extends '::base.html.twig' %}
{% block content %}
<h1>get all users:</h1>
<ul>
{% for user in users %}
<li>{{ user['n'].getProperty('email') }}</li>
{% endfor %}
</ul>
{% endblock %}

I'm the author of the article you mentioned. The thing is that you use a different neo4j library than the one used in the article, hence neoclient, so the methods used in the article are different than the methods provided with neo4jphp.
As NeoClient uses heavily the Symfony components, integrating it in Symfony is really easy, you just need to override the DI. Example here : https://github.com/graphaware/GithubNeo4j/tree/master/src/GraphAware/Neo4jBundle
You'll then be able to use the methods illustrated in the 3 articles I wrote on Sitepoint.
So your problem with the twig template is that he doesn't find the getProperty method of the node object class, which is normal as neo4jphp returns Row object classes.
If you switch back to neoclient, as in the article, in the Twig template you can just write :
{% for user in users %}
<li>{{ user.getProperty('email') }}</li>
{% endfor %}

Related

Symfony Twig exception

I am trying to use a HTML table bundle:
https://github.com/ekyna/TableBundle
Here is the calling code:
$table = $this->get('table.factory')->createBuilder(
new InventoryType(),
['name' => 'project_inventory_list']
)->getTable($request);
$content = ['content_area' => $table->createView()];
return $this->render('MyProjectBundle:Default:index.html.twig', $content);
I am getting an exception:
An exception has been thrown during the rendering of a template
("Catchable Fatal Error: Object of class
Ekyna\Component\Table\TableView could not be converted to string") in
MyProjectBundle:Default:index.html.twig at line 6.
Stepped through code not sure whats going on - hoping it's a trivial issue???
| EDIT
{% extends 'mYThemeBundle:layout:base-layout.html.twig' %}
{% block title %}HEADER{% endblock %}
{% block page_content %}
{{ content_area }}
{% endblock %}
In your TWIG template, you have to do the following:
{% extends 'mYThemeBundle:layout:base-layout.html.twig' %}
{% block title %}HEADER{% endblock %}
{% block page_content %}
{{ ekyna_table_render(content_area ) }}
{% endblock %}
You need to use the TWIG function ekyna_table_render to render the table view.
After installing EkynaBundle (documentation was not up to date) I also needed to adjust the template as demonstrated above in addition to:
Install and enable WhiteOctoberPagerfantaBundle
Install and enable BraincraftedBootstrapBundle
Install twig extensions
Install and enable LiipImagineBundle
Thanks for all the help.

Permanently extend symfony twig template

In my symfony2 application I created a dashboard which currently consists of many navigation elements.
Now I am trying to split those elements into several bundles.
This is the code I have:
{# app/Resources/views/base.html.twig #}
{# ... #}
{% block body %} {% endblock %}
{# ... #}
Then in the ProfileBundle:
{# src/MyApp/ProfileBundle/Resources/views/Dashboard/index.html.twig #}
{% block body %}
<p>Heading</p>
<ul>
{% block dashboardNavi %} {% endblock %}
</ul>
{% block %}
edit: The controller:
class DashboardController extends Controller
{
public function indexAction()
{
return $this->render('MyAppProfileBundle:Dashboard:index.html.twig', array());
}
}
The routing:
pricecalc_profile_dashboad_security:
pattern: /dashboard
defaults: {_controller: MyAppProfileBundle:Dashboard:index }
That template is rendered correctly, when my route "/dashboard" is loaded.
What I now'd like to do, is extend that dashboardNavi-Block in multiple Bundles without changing the route from my ProfileBundle.
Each of those Bundles brings it`s own routes and controllers for custom actions, but all bundles should extend that one block to add links for their custom actions to the dashboard screen.
What I have so far is:
{# src/MyApp/ProfileNewsletterBundle/Resources/views/Dashboard/indexNewsletter.html.twig #}
{% extends 'MyAppProfileBundle:Dashboard:index.html.twig' %}
{% block dashboardNavi %}
{{ parent() }}
<li>Test</li>
{% endblock %}
but that template is never rendered.
edit 2:
Maybe my understanding of how symfony is working in terms of template inheritance is kind of wrong. I'll specify what I am trying to do.
I got one Bundle (DashboardBundle) which consists of an own route, controller, view etc. The view contains two blocks - like navigation and dashboard.
Now, I would like to have those two blocks extended by some other Bundles - just adding new navigation items and shortcuts on that dashboard and navigation block.
I would like to do those enhancements without modifying my Dashboard-Bundle - if that is possible at all.
When finished, I will have 16 Bundles, each providing own functionality in own Controllers - and they should just be linked on that dashboard.
Is it possible to have the dashboard-view extended that way without modifying the view itself?
I finally managed to fix that after having understood how symfony works in extending controllers and views.
I added a new Controller:
{# src/MyApp/ProfileNewsletterBundle/Controllers/DashboardController.php #}
class DashboardController extends Controller {
public function indexAction()
{
return $this->render('ProfileNewsletterBundle:Dashboard:index.html.twig', array());
}
}
modified the bundle ProfileNewsletterBundle to let the method getParent return ProfileBundle,
and modified the view:
{% extends 'ProfileBundle:Dashboard:index.html.twig' %}
{% block dashboardNavi %}
<li>Test</li>
{% endblock %}
That seems to work fine so far.
Thank you all for spending your time on that.

Sonata Admin - Disable list view

I'm facing a problem with Sonata Admin. Is there a way to disable the "list view" ? I would like to fetch the first entity in the database and to go on it when clicking on the link in the sidebar. But not for all entry.
Is there a clean way to do it ? (I have the idea to check the entity in a custom controller, and to redirect to list view or edit view depending on the entity, but that's not really clean)
If you want to do a custom query for your list view, you could override the createQuery method in your Admin class like this :
class EntityAdmin
{
public function createQuery($context = 'list')
{
$query = parent::createQuery($context);
$query->andWhere(
$query->expr()->eq($query->getRootAlias() . '.id', ':id')
);
$query->setParameter('id', 1);
return $query;
}
}
You will have only your first entity in your list view.
UPDATE
You could override the standard_layout.html.twig to change the link in your sidebar :
First you need to set where your template is located:
app/config/config.yml
sonata_admin:
templates:
layout: ApplicationSonataAdminBundle::standard_layout.html.twig
Change the behaviour of the sidebar, for Sonata Admin 2.3 this is how you do it :
src/Application/Sonata/AdminBundle/Resources/Views/standard_layout.html.twig l.224
<ul class="treeview-menu{% if active %} active{% endif %}">
{% for admin in group.items %}
{% if admin.code == 'sonata.admin.entity' and
admin.hasroute('edit') and
admin.isGranted('EDIT') %}
<li{% if app.request.get('_sonata_admin') == admin.code %} class="active"{% endif %}><i class="fa fa-angle-double-right"></i> {{ admin.label|trans({}, admin.translationdomain) }}</li>
{% else %}
{% if admin.hasroute('list') and admin.isGranted('LIST') %}
<li{% if app.request.get('_sonata_admin') == admin.code %} class="active"{% endif %}><i class="fa fa-angle-double-right"></i> {{ admin.label|trans({}, admin.translationdomain) }}</li>
{% endif %}
{% endif %}
{% endfor %}
</ul>
You must change 'sonata.admin.entity' by the identifier of your admin service.
Also if you want to remove access to the list you should add in your Admin class
use Sonata\AdminBundle\Route\RouteCollection;
class EntityAdmin
{
protected function configureRoutes(RouteCollection $collection)
{
$collection->remove('list');
}
}

Activity Log in dashboard sonata admin

I'm trying to implement activity log in the dashboard i.e. a notification in each row that says which entities have a change since the last login of a user.
To do it I'm thinking about overwrite the class AdminListBlockService and the template block_admin_list.html.twig
but i don't have yet clear how do it.
someone know a better way to do it? if that is the better way, how can I achieve it?
thanks a lot!
ok
I found a better way... i have overwritten only the block_admin_list.html.twig so:
//config.yml
sonata_admin:
templates:
list_block: AdminBundle:Block:block_admin_list.html.twig
note the diference "SonataAdminBundle" and "AdminBundle"
next step add in the template:
{% if admin.activityLog() is defined and admin.isGranted('LIST') %}
<a class="btn btn-link" href="{{ admin.generateUrl('list')>admin.activityLog</a>
{% endif %}
and finally create the logic for each Entity where i want the notification
//in the exempleAdmin
public function activityLog(){
// custom code $activity= ....
return $activity;
}
if someone know a better way to do it, please let me know, thanks
Well what you can do is override the template like this:
In your admin class:
// Configure our custom roles for this entity
public function configure() {
parent::configure();
$this->setTemplate('list', 'MyAdminBundle:CRUD:list-myentity.html.twig');
}
Then in your template you can do something like:
{# The default template which provides batch and action cells, with the valid colspan computation #}
{% extends 'SonataAdminBundle:CRUD:list.html.twig' %}
{% block table_body %}
<tbody>
{% for object in admin.datagrid.results %}
<style>
table tr.green-color td {background-color: #2BFF5D !important; }
</style>
<tr {% if changed %} class="green-color" {% endif %}>
{% include admin.getTemplate('inner_list_row') %}
</tr>
{% endfor %}
</tbody>
{% endblock %}

SonataAdmin: replace ID in breadcrumbs

How can I replace Object's ID in SonataAdmin breadcrumbs by some other text?
If I set __toString() in my document, it works only for editing. When I attempt to create new record, there is something like MyDocument:0000000000e09f5c000000006a48ef49 in the last breadcumb.
I'm searching for a method which allows me to set some text as the last breadcump if Document::toString() returns null.
This behaviour is implemented directly in the entity:
public function __toString()
{
return $this->getFoo() ? : '-';
}
Bundles are using variants of this, including return (string)$this->getFoo(); or $this->getFoo() ? : 'n/a'; etc.
Related question: toString method for SonataAdminBundle Listing in Symfony2
BTW something cool to know, you can completely customize the breadcrumb via a Twig template:
{% block sonata_breadcrumb %}
{% set _breadcrumb %}
<li>Home</li>
<li>Library</li>
<li class="active">Data</li>
{% endset %}
{{ parent() }}
{% endblock %}

Resources