Spring Data Solr + HATEOAS - spring-hateoas

playing with spring data solr here... I am able to return a page of results in HATEOAS format which is fine i.e.
#RequestMapping("/findAllPaged")
HttpEntity<PagedResources<Module>> findAllPaged(Pageable pageable, PagedResourcesAssembler assembler) {
Page<Module> page = moduleRepository.findAll(pageable)
return new ResponseEntity<>(assembler.toResource(page), HttpStatus.OK);
}
but how can I have a method return one entity in the correct HATEOAS format
I currently do the following which gives me basic json serialization, but unsure how to get HATEOAS:
#RequestMapping("/module/{id}")
Module module(#PathVariable String id) {
moduleRepository.findOne(id)
}
also how would I return a List in HATEOAS form?
#RequestMapping("/findAll")
List<Module> findAll() {
moduleRepository.findAll().content
}

Actually I found that if I annotate my repository like so with RepositoryRestResource, then I automatically get rest hateaos services exposed for me
#RepositoryRestResource
interface ModuleRepository extends SolrCrudRepository<Module, String>{
/**
* Does exact (equals) query
* #param name
* #param description
* #param pageable
* #return
*/
Page<Module> findByNameOrDescription(#Param(value = "name")#Boost(2.0F) String name, #Param(value = "description") String description, Pageable pageable);
/**
* Does like query and ignores case
* #param name
* #param description
* #param pageable
* #return
*/
Page<Module> findByNameContainingOrDescriptionContainingAllIgnoreCase(#Param(value = "name")String name, #Param(value = "description") String description, Pageable pageable);
/**
* Custom query example
* #param name
* #param pageable
* #return
*/
#Query(value = "name:*?0*")
Page<Module> myCustomQuery(#Param(value = "name")String name,Pageable pageable);
#Query(value = "name:*?0* OR description:*?0* ")
Page<Module> myOtherCustomQuery(#Param(value = "name")String name,Pageable pageable);
Page<Module> findByNameContainingIgnoreCase(#Param(value = "name")String name, Pageable pageable);
}
e.g.
http://localhost:8080/modules/ all docs
http://localhost:8080/modules/1 one doc
http://localhost:8080/modules?page=0&size=4&sort=name,desc paged results
http://localhost:8080/modules/search/findByNameOrDescription?name=name1&description=description2&page=0&size=10
http://localhost:8080/modules/search/findByNameContainingOrDescriptionContainingAllIgnoreCase?name=mAt&description=sCi&page=0&size=10

Related

Unable to get jsonDecode in magento 2

Magento 1.x has its own JSON decode functions:
Mage::helper('core')->jsonDecode($array);
So how to use JSON Decode in Magento 2.
In the current version of Magento2 (2.2.3) the \Magento\Framework\Json\Helper\Data class is deprecated and may no longer be used in future versions. Therefore it is highly recommended to use the \Magento\Framework\Serialize\Serializer\Json class instead to decode a json string or encode an array to a json string.
/**
*
* #var \Magento\Framework\Serialize\Serializer\Json
*/
protected $_jsonSerializer;
public function __construct(
...
\Magento\Framework\Serialize\Serializer\Json $jsonSerializer,
...
) {
...
$this->_jsonSerializer = $jsonSerializer;
...
}
public function decodeJsonString($jsonString)
{
return $this->_jsonSerializer->unserialize($jsonString);
}
public function encodeArray($array)
{
return $this->_jsonSerializer->serialize($array);
}
Try below code with magento 2 for json decode
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$jsonManager = $objectManager->get('\Magento\Framework\Json\Decoder');
return $jsonManager->decode($data);
According to This Answer
Method 1:
echo $this->helper(\Magento\Framework\Json\Helper\Data::class)->jsonDecode($array);
Or
$jsonHelper = $this->helper('Magento\Framework\Json\Helper\Data');
echo $jsonHelper->jsonDecode($array);
Method 2:
/**
* Constructor.
*
* #param \Magento\Framework\Json\Helper\Data $jsonHelper
*/
public function __construct(\Magento\Framework\Json\Helper\Data $jsonHelper)
{
$this->jsonHelper = $jsonHelper;
}
/**
* #param array $dataToDecode
* #return string
*/
public function decodeSomething(array $dataToDecode)
{
$decodedData= $this->jsonHelper->jsonDecode($dataToDecode);
return $decodedData;
}

CakePHP and DefaultPasswordHasher syntax error

I have no clue why but for the line
use Cake\Auth\DefaultPasswordHasher;
I'm getting an error
Error: syntax error, unexpected '?'
and full code of user.php
namespace App\Model\Entity;
use Cake\ORM\Entity;
use Cake\Auth\DefaultPasswordHasher;
/**
* User Entity
*
* #property int $id
* #property string $email
* #property string $password
* #property \Cake\I18n\Time $created
* #property \Cake\I18n\Time $modified
*
* #property \App\Model\Entity\Bookmark[] $bookmarks
*/
class User extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* Note that when '*' is set to true, this allows all unspecified fields to
* be mass assigned. For security purposes, it is advised to set '*' to false
* (or remove it), and explicitly make individual fields accessible as needed.
*
* #var array
*/
protected $_accessible = [
'*' => true,
'id' => false
];
/**
* Fields that are excluded from JSON versions of the entity.
*
* #var array
*/
protected $_hidden = [
'password'
];
protected function _setPassword($value){
$hasher = new DefaultPasswordHasher();
return $hasher->hash($value);
}
}
Any thoughts? I'm using latest CakePHP
Please try with this one. Please update your CakePHP project with composer, it will update all dependency if you miss something.
namespace App\Model\Entity;
use Cake\Auth\DefaultPasswordHasher;
use Cake\ORM\Entity;
class User extends Entity
{
// Make all fields mass assignable except for primary key field "id".
protected $_accessible = [
'*' => true,
'id' => false
];
// ...
protected function _setPassword($password)
{
return (new DefaultPasswordHasher)->hash($password);
}
// ...
}
Also please read this doc here. Hope it should be help you to solve this issue.
use Cake\ORM\Entity;
use Cake\Auth\DefaultPasswordHasher;
/**
* User Entity
*
* #property int $id
* #property string $email
* #property string $password
* #property string $role
* #property \Cake\I18n\Time $created
* #property \Cake\I18n\Time $modified
*/
class User extends Entity
{
/**
* Fields that can be mass assigned using newEntity() or patchEntity().
*
* Note that when '*' is set to true, this allows all unspecified fields to
* be mass assigned. For security purposes, it is advised to set '*' to false
* (or remove it), and explicitly make individual fields accessible as needed.
*
* #var array
*/
protected $_accessible = [
'*' => true,
'id' => false
];
/**
* Fields that are excluded from JSON versions of the entity.
*
* #var array
*/
protected $_hidden = [
'password'
];
protected function _setPassword($password) {
return (new DefaultPasswordHasher)->hash($password);
}
}

How to declare a EventSubscriber in config.yml using bazinga_geocoder.geocoder service?

I am planning to make a reverse geocoding based on the BazingaGeocoderBundle. A simple way to do that is write this simple code in the controller:
$result = $this->container
->get('bazinga_geocoder.geocoder')
->using('google_maps')
->reverse(48.79084170157100,2.42479377175290);
return $this->render("MinnAdsBundle:Motors:test.html.twig",
array('result'=>var_dump($result)));
Until here, things are going well.
My objective is to make the code nicer & resuable. So, I used this article to write my own GeocoderEventSubscriber as describer below:
<?php
namespace Minn\AdsBundle\Doctrine\Event;
use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Event\LifecycleEventArgs;
//use Geocoder\Provider\ProviderInterface;
use Bazinga\Bundle\GeocoderBundle\Geocoder\LoggableGeocoder;
/**
* Subscribes to Doctrine prePersist and preUpdate to update an
* the address components of a MotorsAds entity
*
* #author majallouli
*/
class MotorsAdsGeocoderEventSubscriber implements EventSubscriber {
protected $geocoder;
public function __construct(LoggableGeocoder $geocoder){
$this->geocoder = $geocoder;
}
/**
* Specifies the list of events to listen
*
* #return array
*/
public function getSubscribedEvents(){
return array(
'prePersist',
'preUpdate',
);
}
/**
* Sets a new MotorsAds's address components if not present
*
* #param LifecycleEventArgs $eventArgs
*/
public function prePersist(LifecycleEventArgs $eventArgs){
$motorsAds = $eventArgs->getEntity();
if($motorsAds instanceof \Minn\AdsBundle\Entity\MotorsAds){
if( !$motorsAds->getCountry()){
$em = $eventArgs->getEntityManager();
$this->geocodeMotorsAds($motorsAds,$em);
}
}
}
/**
* Sets an updating MotorsAds's address components if not present
* or any part of address updated
*
* #param PreUpdateEventArgs $eventArgs
*/
public function preUpdate(PreUpdateEventArgs $eventArgs){
$motorsAds = $eventArgs->getEntity();
if($motorsAds instanceof \Minn\AdsBundle\Entity\MotorsAds){
if( !$motorsAds->getCountry() ){
$em = $eventArgs->getEntityManager();
$this->geocodeMotorsAds($motorsAds,$em);
$uow = $em->getUnitOfWork();
$meta = $em->getClassMetadata(get_class($motorsAds));
$uow->recomputeSingleEntityChangeSet($meta, $motorsAds);
}
}
}
/**
* Geocode and set the MotorsAds's address components
*
* #param type $motorsAds
*/
private function geocodeMotorsAds($motorsAds,$em){
$result = $this->geocode
->using('google_maps')
->reverse($motorsAds->getLat(),$motorsAds->getLng());
$motorsAds->setCountry(
$em->getRepository("MinnAdsBundle:Country")->findCountryCode($result['countryCode']));
}
}
After that, I declared my EventSubscriber as a service:
services:
# ...
geocoder_motorsads.listener:
class: Minn\AdsBundle\Doctrine\Event\MotorsAdsGeocoderEventSubscriber
arguments: [#bazinga_geocoder.geocoder] # almost sure that the error is here!!
tags:
- { name: doctrine.event_subscriber }
Actually, I get this error:
ContextErrorException: Notice: Undefined property: Minn\AdsBundle\Doctrine\Event\MotorsAdsGeocoderEventSubscriber::$geocode in /home/amine/NetBeansProjects/tuto/src/Minn/AdsBundle/Doctrine/Event/MotorsAdsGeocoderEventSubscriber.php line 78
I am almost sure that error is in the declaration of arguments of the EventSubscriber. Is it #bazinga_geocoder.geocoder?
Thank you for your help!
Your property is $this->geocoder but you're calling $this->geocode, you're spelling it wrong.

Handling checked exceptions for eclipse plugin

I am working on an Eclipse plugin and am faced with checked exceptions thrown from the API that I am using in my plugin. What is the practice around handling such exceptions in the context of a plugin? I could not find an appropriate Exception subclass from the Plugin development API.
Thanks in advance.
I use logging classes that I found in a book titled "Eclipse Plug-ins", by Eric Clayberg and Dan Rubel.
Here's the main logging class.
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.core.runtime.Status;
public class EclipseLogging {
public static void logInfo(Plugin plugin, String pluginID, String message,
boolean display) {
log(plugin, pluginID, IStatus.INFO, IStatus.OK, message, null, display);
}
public static void logInfo(Plugin plugin, String pluginID,
Throwable exception) {
log(plugin, createStatus(pluginID, IStatus.ERROR, IStatus.OK,
"Unexpected Exception", exception));
}
public static void logInfo(Plugin plugin, String pluginID, String message,
Throwable exception) {
log(plugin, createStatus(pluginID, IStatus.ERROR, IStatus.OK, message,
exception));
}
public static void logError(Plugin plugin, String pluginID,
Throwable exception) {
logError(plugin, pluginID, "Unexpected Exception", exception);
}
public static void logError(Plugin plugin, String pluginID, String message,
Throwable exception) {
log(plugin, pluginID, IStatus.ERROR, IStatus.OK, message, exception,
true);
}
public static void log(Plugin plugin, String pluginID, int severity,
int code, String message, Throwable exception, boolean display) {
if (display) {
ExceptionAction action = new ExceptionAction(plugin, message,
exception);
action.run();
}
log(plugin, createStatus(pluginID, severity, code, message, exception));
}
public static IStatus createStatus(String pluginID, int severity, int code,
String message, Throwable exception) {
return new Status(severity, pluginID, code, message, exception);
}
public static void log(Plugin plugin, IStatus status) {
plugin.getLog().log(status);
}
}
And here's the exception action class.
import org.eclipse.core.runtime.Plugin;
import org.eclipse.jface.action.Action;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
public class ExceptionAction extends Action {
private Plugin plugin;
private String message;
private Throwable exception;
public ExceptionAction(Plugin plugin, String message, Throwable exception) {
this.plugin = plugin;
this.message = message;
this.exception = exception;
}
public void run() {
IWorkbench workbench = PlatformUI.getWorkbench();
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
if (window != null) {
Shell parentShell = window.getShell();
parentShell.forceActive();
try {
ExceptionDetailsDialog dialog = new ExceptionDetailsDialog(
parentShell, null, null, message, exception, plugin);
dialog.open();
} catch (SWTException e) {
}
}
}
}
And finally, the classes to display the exception.
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
/**
* An abstract dialog with a details section that can be shown or hidden by the
* user. Subclasses are responsible for providing the content of the details
* section.
*/
public abstract class AbstractDetailsDialog extends Dialog {
private final String title;
private final String message;
private final Image image;
private Button detailsButton;
private Control detailsArea;
private Point cachedWindowSize;
/**
* Construct a new instance with the specified elements. Note that the
* window will have no visual representation (no widgets) until it is told
* to open. By default, <code>open</code> blocks for dialogs.
*
* #param parentShell
* the parent shell, or <code>null</code> to create a top-level
* shell
* #param title
* the title for the dialog or <code>null</code> for none
* #param image
* the image to be displayed
* #param message
* the message to be displayed
*/
public AbstractDetailsDialog(Shell parentShell, String title, Image image,
String message) {
this(new SameShellProvider(parentShell), title, image, message);
}
/**
* Construct a new instance with the specified elements. Note that the
* window will have no visual representation (no widgets) until it is told
* to open. By default, <code>open</code> blocks for dialogs.
*
* #param parentShell
* the parent shell provider (not <code>null</code>)
* #param title
* the title for the dialog or <code>null</code> for none
* #param image
* the image to be displayed
* #param message
* the message to be displayed
*/
public AbstractDetailsDialog(IShellProvider parentShell, String title,
Image image, String message) {
super(parentShell);
this.title = title;
this.image = image;
this.message = message;
setShellStyle(SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL);
}
/**
* Configures the given shell in preparation for opening this window in it.
* In our case, we set the title if one was provided.
*/
protected void configureShell(Shell shell) {
super.configureShell(shell);
if (title != null)
shell.setText(title);
}
/**
* Creates and returns the contents of the upper part of this dialog (above
* the button bar). This includes an image, if specified, and a message.
*
* #param parent
* the parent composite to contain the dialog area
* #return the dialog area control
*/
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
if (image != null) {
((GridLayout) composite.getLayout()).numColumns = 2;
Label label = new Label(composite, 0);
image.setBackground(label.getBackground());
label.setImage(image);
label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_CENTER
| GridData.VERTICAL_ALIGN_BEGINNING));
}
Label label = new Label(composite, SWT.WRAP);
if (message != null)
label.setText(message);
GridData data = new GridData(GridData.FILL_HORIZONTAL
| GridData.VERTICAL_ALIGN_CENTER);
data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
label.setLayoutData(data);
label.setFont(parent.getFont());
return composite;
}
/**
* Adds OK and Details buttons to this dialog's button bar.
*
* #param parent
* the button bar composite
*/
protected void createButtonsForButtonBar(Composite parent) {
createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
false);
detailsButton = createButton(parent, IDialogConstants.DETAILS_ID,
IDialogConstants.SHOW_DETAILS_LABEL, false);
}
/**
* The buttonPressed() method is called when either the OK or Details
* buttons is pressed. We override this method to alternately show or hide
* the details area if the Details button is pressed.
*/
protected void buttonPressed(int id) {
if (id == IDialogConstants.DETAILS_ID)
toggleDetailsArea();
else
super.buttonPressed(id);
}
/**
* Toggles the unfolding of the details area. This is triggered by the user
* pressing the Details button.
*/
protected void toggleDetailsArea() {
Point oldWindowSize = getShell().getSize();
Point newWindowSize = cachedWindowSize;
cachedWindowSize = oldWindowSize;
// Show the details area.
if (detailsArea == null) {
detailsArea = createDetailsArea((Composite) getContents());
detailsButton.setText(IDialogConstants.HIDE_DETAILS_LABEL);
}
// Hide the details area.
else {
detailsArea.dispose();
detailsArea = null;
detailsButton.setText(IDialogConstants.SHOW_DETAILS_LABEL);
}
/*
* Must be sure to call getContents().computeSize(SWT.DEFAULT,
* SWT.DEFAULT) before calling getShell().setSize(newWindowSize) since
* controls have been added or removed.
*/
// Compute the new window size.
Point oldSize = getContents().getSize();
Point newSize = getContents().computeSize(SWT.DEFAULT, SWT.DEFAULT);
if (newWindowSize == null)
newWindowSize = new Point(oldWindowSize.x, oldWindowSize.y
+ (newSize.y - oldSize.y));
// Crop new window size to screen.
Point windowLoc = getShell().getLocation();
Rectangle screenArea = getContents().getDisplay().getClientArea();
final int pos = screenArea.height - (windowLoc.y - screenArea.y);
if (newWindowSize.y > pos)
newWindowSize.y = pos;
getShell().setSize(newWindowSize);
((Composite) getContents()).layout();
}
/**
* subclasses must implement createDetailsArea to provide content for the
* area of the dialog made visible when the Details button is clicked.
*
* #param parent
* the details area parent
* #return the details area
*/
protected abstract Control createDetailsArea(Composite parent);
}
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
import java.util.Dictionary;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Plugin;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.jface.window.SameShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
/**
* A dialog to display one or more errors to the user, as contained in an
* <code>IStatus</code> object along with the plug-in identifier, name, version
* and provider. If an error contains additional detailed information then a
* Details button is automatically supplied, which shows or hides an error
* details viewer when pressed by the user.
*
* #see org.eclipse.core.runtime.IStatus
*/
public class ExceptionDetailsDialog extends AbstractDetailsDialog {
/**
* The details to be shown ({#link Exception}, {#link IStatus}, or
* <code>null</code> if no details).
*/
private final Object details;
/**
* The plugin triggering this details dialog and whose information is to be
* shown in the details area or <code>null</code> if no plugin details
* should be shown.
*/
private final Plugin plugin;
/**
* Construct a new instance with the specified elements. Note that the
* window will have no visual representation (no widgets) until it is told
* to open. By default, <code>open</code> blocks for dialogs.
*
* #param parentShell
* the parent shell, or <code>null</code> to create a top-level
* shell
* #param title
* the title for the dialog or <code>null</code> for none
* #param image
* the image to be displayed
* #param message
* the message to be displayed
* #param details
* an object whose content is to be displayed in the details
* area, or <code>null</code> for none
* #param plugin
* The plugin triggering this deatils dialog and whose
* information is to be shown in the details area or
* <code>null</code> if no plugin details should be shown.
*/
public ExceptionDetailsDialog(Shell parentShell, String title, Image image,
String message, Object details, Plugin plugin) {
this(new SameShellProvider(parentShell), title, image, message,
details, plugin);
}
/**
* Construct a new instance with the specified elements. Note that the
* window will have no visual representation (no widgets) until it is told
* to open. By default, <code>open</code> blocks for dialogs.
*
* #param parentShell
* the parent shell provider (not <code>null</code>)
* #param title
* the title for the dialog or <code>null</code> for none
* #param image
* the image to be displayed
* #param message
* the message to be displayed
* #param details
* an object whose content is to be displayed in the details
* area, or <code>null</code> for none
* #param plugin
* The plugin triggering this deatils dialog and whose
* information is to be shown in the details area or
* <code>null</code> if no plugin details should be shown.
*/
public ExceptionDetailsDialog(IShellProvider parentShell, String title,
Image image, String message, Object details, Plugin plugin) {
super(parentShell, getTitle(title, details), getImage(image, details),
getMessage(message, details));
this.details = details;
this.plugin = plugin;
}
/**
* Build content for the area of the dialog made visible when the Details
* button is clicked.
*
* #param parent
* the details area parent
* #return the details area
*/
protected Control createDetailsArea(Composite parent) {
// Create the details area.
Composite panel = new Composite(parent, SWT.NONE);
panel.setLayoutData(new GridData(GridData.FILL_BOTH));
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
panel.setLayout(layout);
// Create the details content.
createProductInfoArea(panel);
createDetailsViewer(panel);
return panel;
}
/**
* Create fields displaying the plugin information such as name, identifer,
* version and vendor. Do nothing if the plugin is not specified.
*
* #param parent
* the details area in which the fields are created
* #return the product info composite or <code>null</code> if no plugin
* specified.
*/
protected Composite createProductInfoArea(Composite parent) {
// If no plugin specified, then nothing to display here
if (plugin == null)
return null;
Composite composite = new Composite(parent, SWT.NULL);
composite.setLayoutData(new GridData());
GridLayout layout = new GridLayout();
layout.numColumns = 2;
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
composite.setLayout(layout);
Dictionary<?, ?> bundleHeaders = plugin.getBundle().getHeaders();
String pluginId = plugin.getBundle().getSymbolicName();
String pluginVendor = (String) bundleHeaders.get("Bundle-Vendor");
String pluginName = (String) bundleHeaders.get("Bundle-Name");
String pluginVersion = (String) bundleHeaders.get("Bundle-Version");
new Label(composite, SWT.NONE).setText("Provider:");
new Label(composite, SWT.NONE).setText(pluginVendor);
new Label(composite, SWT.NONE).setText("Plug-in Name:");
new Label(composite, SWT.NONE).setText(pluginName);
new Label(composite, SWT.NONE).setText("Plug-in ID:");
new Label(composite, SWT.NONE).setText(pluginId);
new Label(composite, SWT.NONE).setText("Version:");
new Label(composite, SWT.NONE).setText(pluginVersion);
return composite;
}
/**
* Create the details field based upon the details object. Do nothing if the
* details object is not specified.
*
* #param parent
* the details area in which the fields are created
* #return the details field
*/
protected Control createDetailsViewer(Composite parent) {
if (details == null)
return null;
Text text = new Text(parent, SWT.MULTI | SWT.READ_ONLY | SWT.BORDER
| SWT.H_SCROLL | SWT.V_SCROLL);
text.setLayoutData(new GridData(GridData.FILL_BOTH));
// Create the content.
StringWriter writer = new StringWriter(1000);
if (details instanceof Throwable)
appendException(new PrintWriter(writer), (Throwable) details);
else if (details instanceof IStatus)
appendStatus(new PrintWriter(writer), (IStatus) details, 0);
text.setText(writer.toString());
return text;
}
// /////////////////////////////////////////////////////////////////
//
// Utility methods for building content
//
// /////////////////////////////////////////////////////////////////
/**
* Answer the title based on the provided title and details object.
*/
public static String getTitle(String title, Object details) {
if (title != null)
return title;
if (details instanceof Throwable) {
Throwable e = (Throwable) details;
while (e instanceof InvocationTargetException)
e = ((InvocationTargetException) e).getTargetException();
String name = e.getClass().getName();
return name.substring(name.lastIndexOf('.') + 1);
}
return "Exception";
}
/**
* Answer the image based on the provided image and details object.
*/
public static Image getImage(Image image, Object details) {
if (image != null)
return image;
Display display = Display.getCurrent();
if (details instanceof IStatus) {
switch (((IStatus) details).getSeverity()) {
case IStatus.ERROR:
return display.getSystemImage(SWT.ICON_ERROR);
case IStatus.WARNING:
return display.getSystemImage(SWT.ICON_WARNING);
case IStatus.INFO:
return display.getSystemImage(SWT.ICON_INFORMATION);
case IStatus.OK:
return null;
}
}
return display.getSystemImage(SWT.ICON_ERROR);
}
/**
* Answer the message based on the provided message and details object.
*/
public static String getMessage(String message, Object details) {
if (details instanceof Throwable) {
Throwable e = (Throwable) details;
while (e instanceof InvocationTargetException)
e = ((InvocationTargetException) e).getTargetException();
if (message == null)
return e.toString();
return MessageFormat.format(message, new Object[] { e.toString() });
}
if (details instanceof IStatus) {
String statusMessage = ((IStatus) details).getMessage();
if (message == null)
return statusMessage;
return MessageFormat
.format(message, new Object[] { statusMessage });
}
if (message != null)
return message;
return "An Exception occurred.";
}
public static void appendException(PrintWriter writer, Throwable ex) {
if (ex instanceof CoreException) {
appendStatus(writer, ((CoreException) ex).getStatus(), 0);
writer.println();
}
appendStackTrace(writer, ex);
if (ex instanceof InvocationTargetException)
appendException(writer, ((InvocationTargetException) ex)
.getTargetException());
}
public static void appendStatus(PrintWriter writer, IStatus status,
int nesting) {
for (int i = 0; i < nesting; i++)
writer.print(" ");
writer.println(status.getMessage());
IStatus[] children = status.getChildren();
for (int i = 0; i < children.length; i++)
appendStatus(writer, children[i], nesting + 1);
}
public static void appendStackTrace(PrintWriter writer, Throwable ex) {
ex.printStackTrace(writer);
}
}

Zend Framework 1.9.2+ Zend_Rest_Route Examples

With the introduction of Zend_Rest_Route in Zend Framework 1.9 (and its update in 1.9.2) we now have a standardized RESTful solution for routing requests. As of August 2009 there are no examples of its usage, only the basic documentation found in the reference guide.
While it is perhaps far more simple than I assume, I was hoping those more competent than I might provide some examples illustrating the use of the Zend_Rest_Controller in a scenario where:
Some controllers (such as indexController.php) operate normally
Others operate as rest-based services (returning json)
It appears the JSON Action Helper now fully automates and optimizes the json response to a request, making its use along with Zend_Rest_Route an ideal combination.
Appears it was rather simple. I've put together a Restful Controller template using the Zend_Rest_Controller Abstract. Simply replace the no_results return values with a native php object containing the data you want returned. Comments welcome.
<?php
/**
* Restful Controller
*
* #copyright Copyright (c) 2009 ? (http://www.?.com)
*/
class RestfulController extends Zend_Rest_Controller
{
public function init()
{
$config = Zend_Registry::get('config');
$this->db = Zend_Db::factory($config->resources->db);
$this->no_results = array('status' => 'NO_RESULTS');
}
/**
* List
*
* The index action handles index/list requests; it responds with a
* list of the requested resources.
*
* #return json
*/
public function indexAction()
{
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
// 1.9.2 fix
public function listAction() { return $this->_forward('index'); }
/**
* View
*
* The get action handles GET requests and receives an 'id' parameter; it
* responds with the server resource state of the resource identified
* by the 'id' value.
*
* #param integer $id
* #return json
*/
public function getAction()
{
$id = $this->_getParam('id', 0);
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
/**
* Create
*
* The post action handles POST requests; it accepts and digests a
* POSTed resource representation and persists the resource state.
*
* #param integer $id
* #return json
*/
public function postAction()
{
$id = $this->_getParam('id', 0);
$my = $this->_getAllParams();
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
/**
* Update
*
* The put action handles PUT requests and receives an 'id' parameter; it
* updates the server resource state of the resource identified by
* the 'id' value.
*
* #param integer $id
* #return json
*/
public function putAction()
{
$id = $this->_getParam('id', 0);
$my = $this->_getAllParams();
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
/**
* Delete
*
* The delete action handles DELETE requests and receives an 'id'
* parameter; it updates the server resource state of the resource
* identified by the 'id' value.
*
* #param integer $id
* #return json
*/
public function deleteAction()
{
$id = $this->_getParam('id', 0);
// do some processing...
// Send the JSON response:
$this->_helper->json($this->no_results);
}
}
great post, but I would have thought the Zend_Rest_Controller would route the request to the right action with respect to the HTTP method used. It'd be neat if a POST request to http://<app URL>/Restful would automatically _forward to postAction for example.
I'll go ahead and provide another strategy below, but maybe I'm missing the point behind Zend_Rest_Controller ... please comment.
My strategy:
class RestfulController extends Zend_Rest_Controller
{
public function init()
{
$this->_helper->viewRenderer->setNoRender();
$this->_helper->layout->disableLayout();
}
public function indexAction()
{
if($this->getRequest()->getMethod() === 'POST')
{return $this->_forward('post');}
if($this->getRequest()->getMethod() === 'GET')
{return $this->_forward('get');}
if($this->getRequest()->getMethod() === 'PUT')
{return $this->_forward('put');}
if($this->getRequest()->getMethod() === 'DELETE')
{return $this->_forward('delete');}
$this->_helper->json($listMyCustomObjects);
}
// 1.9.2 fix
public function listAction() { return $this->_forward('index'); }
[the rest of the code with action functions]