knpMenuBundle issue - php

I just tried knpLabs MenuBundle
I am not receiving the flag for the current item, I follower the turorial from https://github.com/KnpLabs/KnpMenuBundle/blob/master/Resources/doc/index.md
Here is my code
use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAware;
class Builder extends ContainerAware
{
public function mainMenu(FactoryInterface $factory, array $options)
{
$menu = $factory->createItem('root');
$menu->addChild('Innehåll', array('route' => 'Content'));
$menu->addChild('Skärmlayouter', array('route' => 'Layout'));
$menu->addChild('Media', array('route' => 'Media'));
$menu->addChild('Områden & fastigheter', array('route' => 'Container'));
$menu->addChild('Användare & behörigheter', array('route' => 'UserManagement'));
return $menu;
}
}
And here is what it produces:
<ul>
<li class="first">
Innehåll
</li>
<li>
Skärmlayouter
</li>
<li>
Media
</li>
<li>
Områden & fastigheter
</li>
<li class="last">
Användare & behörigheter
</li>
</ul>
It claims to include the active link flag (by class "current") automatically, that's why I wanted to try this bundle, so I wouldn't have to meddle around coding that part.
Either I am missing a key point, or this documentation that I am following is missing a key part?

You should use setCurrentUri method. Such as:
$menu = $factory->createItem('root');
$menu->setCurrentUri($this->container->get('request')->getRequestUri());

Related

Laravel: extending view from module

I have a module in my Laravel app (it could also be a composer package).
This module has a view composer which sets an array to all views containing the routes which should be included in the main navigation of the app.
The composer looks like this:
class ContactNavigationComposer
{
/**
* Bind data to the view.
*
* #param \Illuminate\View\View $view
* #return void
*/
public function compose(View $view)
{
$view->with('contactNavigation', config('contact.navigation'));
}
}
Then in the mainNav of the app this variable $contactNavigation becomes iterated to generate the entries:
<ul>
# ...
<li>
<a
class="{{ (request()->is('navigations/areas')) ? 'active' : '' }}"
href="{{ route('areas.index') }}">
Navigation Areas
</a>
</li>
<li>
<a
class="{{ (request()->is('languages')) ? 'active' : '' }}"
href="{{ route('languages.index') }}">
Languages
</a>
</li>
#foreach($contactNavigation as $text => $url)
<li>
<a
class="{{ (request()->is($url)) ? 'active' : '' }}"
href="{{ $url }}">
{{ $text }}
</a>
</li>
#endforeach
</ul>
This works perfectly fine but I was wondering if I can have this behavior in a more dynamic way and let composers of different modules using the same array e.g. $modules which contains navigation entries (and other stuff) of different modules.
This way I wouldn't have to add module extensions to the applications views later on.
So my suggested solution would be smth. like that:
class ContactNavigationComposer
{
/**
* Bind data to the view.
*
* #param \Illuminate\View\View $view
* #return void
*/
public function compose(View $view)
{
$view->with('modules.navigation.contact', config('contact.navigation'));
}
}
<ul>
# ...
#if (isset($modules['navigation']))
#foreach($modules['navigation'] as $moduleNavigation)
#foreach($moduleNavigation as $text => $url)
<li>
<a
class="{{ (request()->is($url)) ? 'active' : '' }}"
href="{{ $url }}">
{{ $text }}
</a>
</li>
#endforeach
#endforeach
#endif
</ul>
Of course with the dot-notation, this modules.navigation.contact-key is never translated into a view variable especially not as an array.
Is there any way to achieve something like that?
For those who came across this issue as well:
I changed my compose method to this
// ViewComposer
class ContactNavigationComposer extends BaseComposer
{
public function compose(View $view)
{
$moduleDataBag = $this->getModuleDataBag($view);
$moduleData = $moduleDataBag->mergeRecursive([
'contact' => [
'navigation' => config('contact.navigation.entries')
]
]);
$view->with('modules', $moduleData);
}
}
The getModuleDataBag-method comes from the BaseComposer-class from which each ViewComposer inherits from.
class BaseComposer
{
protected function getModuleDataBag(View $view)
{
if (!array_key_exists(config('contact.view.dataKey'), $view->gatherData())) {
ViewFacade::share(config('contact.view.dataKey'), collect([]));
}
return $view->gatherData()[config('contact.view.dataKey')];
}
}
The key in which all the configuration is stored is defined in the (publishable) config. This way this setup is flexible for modifications by the surrounding application.
(The package is called contact, that's why the view data key is in the contact-config.)
If the expected key is not found, the BaseComposer sets it to all views using the ::share-method on the View-facade as an empty collection.
Each ViewComposer always call the getModuleDataBag-method first to receive the current data probably already set by other ViewComposers.
As this $moduleDataBag is a collection, all additional values can be merged into as long as they are arrays. This is done recursively so that each existing key and value is preserved.
Hope that can help someone later on.

About the using of elasticsearch-php

This is the documentation,
https://www.elastic.co/guide/en/elasticsearch/client/php-api/current/_quickstart.html
The questions are in screenshot below:
Edit:
For example,I want to get the search result in this example below,how to write the controller?
view:
<html>
<head>
<meta charset="utf-8">
<link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.2/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/tether/1.3.2/css/tether.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<nav class="navbar navbar-light bg-faded">
<a class="navbar-brand" href="#">Navbar</a>
<ul class="nav navbar-nav">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Features</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
</ul>
<form class="form-inline pull-xs-right">
<input class="form-control" type="text" placeholder="Search">
<button class="btn btn-success-outline" type="submit">Search</button>
</form>
</nav>
</div>
<script src="https://cdn.bootcss.com/jquery/2.2.3/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/tether/1.3.2/js/tether.min.js"></script>
<script src="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.2/js/bootstrap.min.js"></script>
</body>
</html>
route:
<?php
Route::group(['middleware' => 'web'], function () {
Route::resource('/search', 'SearchController');
});
Controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
class SearchController extends Controller
{
public function index()
{
//
}
public function create()
{
//
}
public function store(Request $request)
{
//
}
public function show($id)
{
//
}
public function edit($id)
{
//
}
public function update(Request $request, $id)
{
//
}
public function destroy($id)
{
//
}
}
Model:Article.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
protected $fillable = [
'title', 'content'
];
}
Seems to me like they only provided the instructions on how to install composer but you still need to actually require the package with composer by using:
composer require elasticsearch/elasticsearch
If you run composer install it should be autoloaded for you so that you can call it from anywhere. From that point on you can just instantiate the Elasticsearch clientbuilder where you need it.
The "code on the left" is a return response you are getting it is the elasticsearch json converted to a php array.
To actually get up and running you need:
$client = Elasticsearch\ClientBuilder::create()->build();
$params = [
'index' => 'my_index',
'type' => 'my_type',
'id' => 'my_id',
'body' => ['testField' => 'abc']
];
$response = $client->index($params);
print_r($response);
The above should be pretty much what you need, you need to change the params to whatever your settings are and the body to what your search query is.
Edit
Looked over the composer.json edit so you need actually need to composer require since it's already in the file. Simply "composer install" is enough.
This is what I whipped up quickly, I tried the index method and it works fine. In this case I still had an elasticsearch server with an index name of "node" and a type of "vacation" this needs to change depending on your personal elasticsearch server. The logical thing here would be to have a type of "user" ofcourse.
class UsersController extends Controller
{
// the main elasticsearch instance created with the constructor
protected $client;
public function __construct() {
$hosts = [
// since I am using homestead I have to refer to the ip address of my host machine on which I have installed
// elasticcsearch, otherwise the default localhost option will point to homestead localhost
'192.168.178.10:9200'
];
$this->client = \Elasticsearch\ClientBuilder::create()->setHosts($hosts)->build();
}
public function index()
{
$params = [
'index' => 'node',
'type' => 'vacation',
'body' => [
'query' => [
'match_all' => []
]
]
];
$response = $this->client->search($params);
print_r($response);
}
public function create()
{
$params = [
'index' => 'node',
'type' => 'vacation',
'id' => '1029',
'body' => [
'query' => [
'match_all' => []
]
]
];
$response = $this->client->index($params);
print_r($response);
}
}
The elasticsearch documentation has all the settings for updating, deleting, indexing and searching neatly documented so just implement those for each resource method.
There is plenty of room for improvement if you want to do it the laravel way and implement this neatly. But this should at least get you going. A better option is to make a serviceprovider for the Elasticsearch client builder and inject it into your UsersController via typehinting but I will leave that up to you.
Good luck.

Using laravel-menu, how do I get sub-items to nest?

I am using Lavary's laravel-menu package, and I am trying to build a simple 2 level menu system based on the contents of a db table. I have the middleware created to create the menu on each request:
public function handle($request, Closure $next)
{
Menu::make('NavBar', function($menu){
$menuitems = MenuItem::all();
foreach($menuitems as $menuitem)
{
if(!is_null($menuitem->parent)){
// For example, 'Conferences', a top level menu item with a null parent field
$menu->add($menuitem->title, url($menuitem->url));
}
else{
// Parent is a field in database, for example 'Traverse City 2015' would have the parent 'conferences'
$parent = $menuitem->parent;
$menu->item($parent)->add($menuitem->title, url($menuitem->url));
}
}
});
return $next($request);
}
In my view, I call:
{!! $NavBar->asUl() !!}
I would expect this to render as such:
<ul>
<li>Conferences</li>
<ul>
<li><a href="/conferences/traverse-city-2015">Traverse City 2015</li>
</ul>
</ul>
Instead, it is rendering:
<ul>
<li>Conferences</li>
<li>Traverse City 2015</li>
</ul>
Any ideas why the sub-items aren't showing up correctly?
What you are after is nested groups: https://github.com/lavary/laravel-menu#nested-groups
Menu::make('MyNavBar', function($menu){
$menu->group(array('prefix' => 'pages', 'data-info' => 'test'), function($m){
$m->add('About', 'about');
$m->group(array('prefix' => 'about', 'data-role' => 'navigation'), function($a){
$a->add('Who we are', 'who-we-are?');
$a->add('What we do?', 'what-we-do');
$a->add('Our Goals', 'our-goals');
});
});
});
This will then render as:
<ul>
<li data-info="test">
About
<ul>
<li data-info="test" data-role="navigation"></li>
<li data-info="test" data-role="navigation"></li>
<li data-info="test" data-role="navigation"></li>
</ul>
</li>
</ul>

Add Class to html Macros Laravel Blade

I am new to laravel blade and I want to have an automatic active navigation bar,
so I have this code
<li>{{ HTML::clever_link("index", 'Home' ) }}</li>
<li><a class="glow" href='breeder'>Breeder's Profile</a></li>
<li><a class="glow" href='gallery'>Gallery</a></li>
<li><a class="glow" href='contact'>Contact Us</a></li>
I used the clever link as I research to do what i want, but it remove the link class "glow" now I want to add the glow class to the li with the clever link, I tried this
<li>{{ HTML::clever_link("index", 'Home', class="glow" ) }}</li>
but it just gives me error. Thanks
You can simply add an argument to your HTML Macro: (Obviously I don't know how your macro looks like so this is just an example)
HTML::macro('clever_link', function($link, $label, $class = ''){
return ''.$label.'';
});
Usage:
{{ HTML::clever_link("index", 'Home', 'glow') }}
Or something a bit more flexible:
HTML::macro('clever_link', function($link, $label, $attributes = array()){
return '<a href="'.$link.'" '.HTML::attributes($attributes).'>'.$label.'</a>';
});
Usage:
{{ HTML::clever_link("index", 'Home', array('class' => 'glow')) }}
(The HTML::attributes() method allows you to convert an array into an HTML attributes string)
// for navigation menu highlight
HTML::macro('clever_link', function($route, $text, $icon) {
if( Request::path() == $route ) {
$active = "class = 'active'";
}
else {
$active = '';
}
return "<a href = '{url($route)}' $active> <i class = '{$icon}'></i>{$text}</a>";
});
</pre>
Usage:
Make your menu as:
{{ HTML::clever_link("/", 'Home', 'icon-home-2') }}
{{ HTML::clever_link("/aboutus", 'About Us', 'icon-dollor') }}
in your menu's link
OR use
https://github.com/pyaesone17/active-state

check route url on cakephp

Hi all i have a menu like this on a cakephp 2 website:
<ul class="nav">
<li><?php echo $this->Html->link('Home', array('controller' => 'posts', 'action' => 'index')); ?></li>
<li><?php echo $this->Html->link('Add post', array('controller' => 'posts', 'action' => 'add')); ?></li>
<li>Contact</li>
</ul>
and i have to check if i'm on a page to add class="selected" on the menu link.
How can i do this?
Thanks
In your view file you can also do:
$this->request->params
I recommend you to write your own helper that will implement a method with the same args as HtmlHelper::link and internally call and return HtmlHelper but before it will compare $this->request->params with the passed array of the first arg. If it matches you can inject the class name in the 3rd arg.
Something like this, implement it on your own:
class MyHelper extends AppHelper {
public $helpers = array('Html');
public function link($title, $url, $options) {
/**
* if ($this->View->request->params ...
* do your matching logic here
* and if it matches: $options['class'] = 'active';
*/
return $this->Html->link($title, $url, $options
}
I wrote a (CakePHP 1.2) helper a while back that does this automatically:
http://richardathome.com/blog/cakephp-smarter-links
Should be pretty straight forward to port it to 2.0

Categories