The Vaadin Framework guide has a page describing how to use Column Renderers in a Vaadin Grid. And this page describes implementing renderers, but all too briefly.
I want to implement a InstantRenderer to complement the partial set of java.time renderers added in Vaadin 8.1. Renderers were added for LocalDate & LocalDateTime but not for Instant, OffsetDateTime, and ZonedDateTime. For my Instant renderer I am currently simply applying the current default time zone (ZoneId) to get a ZonedDateTime on which I call the toString method. More could be done, but this is just to get started.
So my code should be very similar to the provided LocalDateTimeRenderer. I am trying to follow that code as an guide.
In searching the Vaadin source code and reading the doc, it seems I need three pieces of source code:
InstantRenderer ( similar to LocalDateTimeRenderer )
InstantRendererConnector ( similar to LocalDateTimeRendererConnector )
InstantRendererState ( similar to LocalDateTimeRendererState )
I have done this, and it all compiles. But my table fails to render, all I get is a white empty box on the page. No errors appear on the console or logs. If I remove my use of my InstantRenderer, and fall back to letting my Instant objects be rendered by the default of their own toString methods, all is well and the table appears as expected. So I know my custom renderer is at fault.
I am a newbie when it comes to "server-side" vs "client-side" Vaadin.
➠ Is there some kind of packaging I need to perform? Currently I have my three classes in my Vaadin project alongside the MyUI source file.
➠ Am I missing some other piece?
I instantiate my renderer by calling the no-arg constructor:
this.entriesGrid
.addColumn( Entry::getStart )
.setCaption( "Start" )
.setRenderer( new InstantRenderer( ) )
;
Here are my three files listed above, taken almost entirely from the Vaadin source code.
InstantRenderer
/*
* By Basil Bourque. Taken almost entirely from source code published by Vaadin Ltd.
*
* --------
*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.basil.timepiece;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;
import elemental.json.JsonValue;
/**
* A renderer for presenting {#code Instant} objects.
*
* #author Vaadin Ltd
* #since 8.1
*/
public class InstantRenderer
extends com.vaadin.ui.renderers.AbstractRenderer< Object, Instant >
{
private DateTimeFormatter formatter;
private boolean getLocaleFromGrid;
private ZoneId zoneId = ZoneId.systemDefault(); // Basil Bourque.
/**
* Creates a new InstantRenderer.
* <p>
* The renderer is configured to render with the grid's locale it is
* attached to, with the format style being {#code FormatStyle.LONG} for the
* date and {#code FormatStyle.SHORT} for time, with an empty string as its
* null representation.
*
* #see <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/time/format/FormatStyle.html#LONG">
* FormatStyle.LONG</a>
* #see <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/time/format/FormatStyle.html#SHORT">
* FormatStyle.SHORT</a>
*/
public InstantRenderer ()
{
this( DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG , FormatStyle.SHORT ) , "" );
getLocaleFromGrid = true;
}
/**
* Creates a new InstantRenderer.
* <p>
* The renderer is configured to render with the given formatter, with the
* empty string as its null representation.
*
* #param formatter the formatter to use, not {#code null}
* #throws IllegalArgumentException if formatter is null
*/
public InstantRenderer ( DateTimeFormatter formatter )
{
this( formatter , "" );
}
/**
* Creates a new InstantRenderer.
* <p>
* The renderer is configured to render with the given formatter.
*
* #param formatter the formatter to use, not {#code null}
* #param nullRepresentation the textual representation of the {#code null} value
* #throws IllegalArgumentException if formatter is null
*/
public InstantRenderer ( DateTimeFormatter formatter , String nullRepresentation )
{
super( Instant.class , nullRepresentation );
if ( formatter == null )
{
throw new IllegalArgumentException( "formatter may not be null" );
}
this.formatter = formatter;
}
/**
* Creates a new InstantRenderer.
* <p>
* The renderer is configured to render with the given string format, as
* displayed in the grid's locale it is attached to, with an empty string as
* its null representation.
*
* #param formatPattern the format pattern to format the date with, not {#code null}
* #throws IllegalArgumentException if format pattern is null
* #see <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns">
* Format Pattern Syntax</a>
*/
public InstantRenderer ( String formatPattern )
{
this( formatPattern , Locale.getDefault() );
getLocaleFromGrid = true;
}
/**
* Creates a new InstantRenderer.
* <p>
* The renderer is configured to render with the given string format, as
* displayed in the given locale, with an empty string as its null
* representation.
*
* #param formatPattern the format pattern to format the date with, not {#code null}
* #param locale the locale to use, not {#code null}
* #throws IllegalArgumentException if format pattern is null
* #throws IllegalArgumentException if locale is null
* #see <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns">
* Format Pattern Syntax</a>
*/
public InstantRenderer ( String formatPattern , Locale locale )
{
this( formatPattern , locale , "" );
}
/**
* Creates a new InstantRenderer.
* <p>
* The renderer is configured to render with the given string format, as
* displayed in the given locale.
*
* #param formatPattern the format pattern to format the date with, not {#code null}
* #param locale the locale to use, not {#code null}
* #param nullRepresentation the textual representation of the {#code null} value
* #throws IllegalArgumentException if format pattern is null
* #throws IllegalArgumentException if locale is null
* #see <a href=
* "https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns">
* Format Pattern Syntax</a>
*/
public InstantRenderer ( String formatPattern , Locale locale , String nullRepresentation )
{
super( Instant.class , nullRepresentation );
if ( formatPattern == null )
{
throw new IllegalArgumentException( "format pattern may not be null" );
}
if ( locale == null )
{
throw new IllegalArgumentException( "locale may not be null" );
}
formatter = DateTimeFormatter.ofPattern( formatPattern , locale );
}
#Override
public JsonValue encode ( Instant value )
{
String dateString;
if ( value == null )
{
dateString = this.getNullRepresentation();
} else if ( this.getLocaleFromGrid )
{
if ( null == this.getParentGrid() )
{
throw new IllegalStateException(
"Could not find a locale to format with: "
+ "this renderer should either be attached to a grid "
+ "or constructed with locale information" );
}
ZonedDateTime zdt = value.atZone( this.zoneId ); // Basil Bourque.
Locale locale = this.getParentGrid().getLocale();
dateString = zdt.format( formatter.withLocale( locale ) );
} else
{
ZonedDateTime zdt = value.atZone( this.zoneId ); // Basil Bourque.
dateString = zdt.format( formatter );
}
return encode( dateString , String.class );
}
#Override
protected InstantRendererState getState ()
{
InstantRendererState s = ( InstantRendererState ) super.getState();
return s;
}
#Override
protected InstantRendererState getState ( boolean markAsDirty )
{
InstantRendererState s = ( InstantRendererState ) super.getState( markAsDirty );
return s;
}
}
InstantRendererConnector
/*
* By Basil Bourque. Taken almost entirely from source code published by Vaadin Ltd.
*
* --------
*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.basil.timepiece;
import com.vaadin.shared.ui.Connect;
/**
* A connector for InstantRenderer.
* <p>
* The server-side Renderer operates on {#code Instant}s, but the data is
* serialized as a string, and displayed as-is on the client side. This is to be
* able to support the server's locale.
*
* #author Vaadin Ltd
* #since 8.1
*/
#Connect( InstantRenderer.class )
public class InstantRendererConnector extends com.vaadin.client.connectors.grid.TextRendererConnector
{
#Override
public InstantRendererState getState ()
{
return ( InstantRendererState ) super.getState();
}
}
InstantRendererState
/*
* By Basil Bourque. Taken almost entirely from source code published by Vaadin Ltd.
*
* --------
*
* Copyright 2000-2016 Vaadin Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.basil.timepiece;
/**
* Shared state of InstantRenderer.
*
* #author Vaadin Ltd
* #since 8.1
*/
public class InstantRendererState extends com.vaadin.shared.ui.grid.renderers.TextRendererState
{
// This code intentionally left blank.
}
Source on BitBucket
I have posted my complete Maven-driven project on BitBucket, all the necessary files for column renderers for Instant, OffsetDateTime, and ZonedDateTime.
Feature Request
I posted Issue # 10208 Implement column renderers for Vaadin Grid for other java.time types (Instant, OffsetDateTime, ZonedDateTime) to complement the LocalDate & LocalDateTime renderers in Vaadin 8.1. on the Vaadin Framework GitHub page.
Special packaging required
Yes, special packaging is required. You cannot simply toss the Vaadin Grid column renderer implementation classes into a regular Vaadin app.
Two of the three classes needed for a column renderer implementation involve client-side development, rather than the usual server-side development we do commonly in Vaadin app work.
Fortunately, this is easier than it might sound. To just do a simple column renderer, Vaadin fortunately provides some super-classes that do most of the heavy-lifting. So we need not learn about all the gory details of the GWT and JavaScript magic that goes on under the covers in Vaadin.
The path to success involves:
Creating a separate project using a Vaadin-provided template to build your own Vaadin Add-On.
Populating that project with source code taken from the Vaadin Framework GitHub project.
vaadin-archetype-widget
Start a new project using a multi-module Maven archetype provided by the Vaadin team: vaadin-archetype-widget seen in this list.
addon module
Once you have created a project from that archetype in your IDE, add your three column renderer classes as shown in this screen shot for an Instant renderer.
Renderer class goes in the 'addon' module’s main package.
RendererConnector & RendererState class files go in the 'addon' module’s nested client package.
Of course, in real work you would delete the example MyComponent… files created by the archetype.
demo module
Once built you can try your column renderer in the 'demo' module’s Vaadin app by importing the package of the 'addon' module. In this case:
import org.basilbourque.timecolrenderers.InstantRenderer;
GitHub source
My successful implementation of a Instant column renderer was take entirely from three LocalDateTimeRenderer related classes provided with Vaadin 8.1.3 source code. You can find the current version of these classes by typing LocalDateTimeRenderer in the GitHub find file feature.
shared/src/main/java/com/vaadin/shared/ui/grid/renderers/LocalDateTimeRendererState.java
server/src/main/java/com/vaadin/ui/renderers/LocalDateTimeRenderer.java
client/src/main/java/com/vaadin/client/connectors/grid/LocalDateTimeRendererConnector.java
I have added some custom code in a block using PHP code format to show that block on a specific page. I have checked all the things working fine on Devel PHP page but contents are not showing on page. The code below fetches the field value of a destination node.
$refer = $_SERVER[HTTP_REFERER];
$parsed = parse_url($refer);
$alias = array_pop($parsed);
$dst = \Drupal::service('path.alias_manager')->getPathByAlias($alias , $langcode);
$nid = array_pop(explode('/', $dst));
$dest_node = node_load($nid);
$body = $dest_node->get('body')->getValue();
print $body; //have tried other printing methods also but invain
Hope this clarifies the question.
Thanks
Are you sure that it works in Devel? I've just tried to execute your code, and this line:
$body = $dest_node->get('body')->getValue();
returns Array.
Try to use this one instead:
$body = $dest_node->body->value;
First of all, your first block of code (getting current node) can be replaced with just one line:
$node = \Drupal::service('current_route_match')->getParameter('node');
And the whole block can be changed in the following way:
if ($node = \Drupal::service('current_route_match')->getParameter('node')) {
print $node->body->value;
}
P.S. And it's definitely a bad idea to use PHP text filter. You may easily write your own custom module providing required block. The simplest block plugin requires several lines of code:
/**
* #file
* Contains \Drupal\my_module\Plugin\Block\MyBlock.
*/
namespace Drupal\my_module\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* Provides my super block.
*
* #Block(
* id = "my_module_block",
* admin_label = #Translation("My Block"),
* category = #Translation("My Module"),
* )
*/
class MyBlock extends BlockBase{
/**
* Builds and returns the renderable array for this block plugin.
*
* #return array
* A renderable array representing the content of the block.
*
* #see \Drupal\block\BlockViewBuilder
*/
public function build() {
if ($node = \Drupal::service('current_route_match')->getParameter('node')) {
return [ '#markup' => $node->body->value ];
}
}
}
This file MyBlock.php must be placed in /src/Plugin/Block/ directory inside your custom module named my_module.
I used drupal coder module to check my code and always get missing file doc as an error.
I used the following file doc comment but still showing error. Can you please guide me what am i doing wrong.
Edit:
<?php
/**
* #file
* Description
*/
/**
* Implements hook_menu().
*
* Description
*
* #return array An array of menu items
*/
function hook_menu() {
//My code
}
Typical first 15 lines of a file:
<?php
/**
* #file
* Description of what this module (or file) is doing.
*/
/**
* Implements hook_help().
*/
function yourmodule_help($path, $arg) {
// or any other hook...
}
Don't forget to also comment the first function of you file with /** or else coder will believe that your #file comment is your first function's comment.
Don't ask me how but I just did a huge mistake, and I need to regenerate the version.php file in wordpress.
Do you know if there is a way do to that, or another way to get the current wp version without this file ?
Thanks a lot.
Download a new version of Wordpress
and take the original version.php file
(is this)
<?php
/**
* The WordPress version string
*
* #global string $wp_version
*/
$wp_version = '3.8.1';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
*
* #global int $wp_db_version
*/
$wp_db_version = 26691;
/**
* Holds the TinyMCE version
*
* #global string $tinymce_version
*/
$tinymce_version = '359-20131026';
/**
* Holds the required PHP version
*
* #global string $required_php_version
*/
$required_php_version = '5.2.4';
/**
* Holds the required MySQL version
*
* #global string $required_mysql_version
*/
$required_mysql_version = '5.0';
I have just started using Symfony and I am having a routing problem. Here is the routing fromt the controller:
/**
* #Route("/social/{name}/", name="_speed1")
* #Route("/social/drivers/")
* #Route("/social/drivers/{name}/", name="_driver")
* #Route("/social/", name="_speed")
* #Template()
*/
public function unlimitedAction()
{
If I go to speed/social/ or speed/social/bob or speed/social/drivers/ or speed/social/drivers/bob all of those pages render with no problem. However I need the name being passed in so I changed
public function unlimitedAction()
{
to
public function unlimitedAction($name)
{
If I go to speed/social/drivers/ or speed/social/drivers/bob it returns fine. However, if I go to speed/social/ then I get the following error:
Controller "MyBundle\Controller\DefaultController::unlimitedAction()"
requires that you provide a value for the "$name" argument (because there is
no default value or because there is a non optional argument after this one).
I can't understand why it works for one route but not the other.
So my question is, how can I acheive my routing so that I can go to:
speed/social/
speed/social/drivers/
speed/social/drivers/bob
And be able to pass the variable to the action without error.
Thanks!
To answer your question: you have to provide a default value for name parameter, for each route without the {name} parameter in the url. I can't test it right now and I can't remember the syntax when using annotations, but should be something like this:
/**
* #Route("/social/{name}/", name="_speed1", defaults={"name"=null})
* #Route("/social/drivers/{name}/", name="_driver", defaults={"name"=null})
* #Template()
*/
public function unlimitedAction($name)
{
}
This way you should be able to call /social/ and /social/foo as well as /social/drivers/ and /social/drivers/foo.
But, really, this is not the right way to go. Just define more actions, each binded to a single route:
/**
* #Route("/social", name="social_index")
* #Template()
*/
public function socialIndexAction() { } // /social
/**
* #Route("/social/{name}", name="social_show")
* #Template()
*/
public function socialShowAction($name) { } // /social/foo
As a general rule, each method (each action) should be focused to do just one thing and should be as short as possible. Use services and make your controllers do what they are supposed to do: understand user input, call services and show views.