I can't seem to get my table gateway to inject into my repository(service)...
I have the following:
Module.php:
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getServiceConfig()
{
return array(
'factories' => array(
'Album\Model\Concrete\AlbumRepository' => function($sm) {
$tableGateway = $sm->get('AlbumTableGateway');
$table = new AlbumRepository($tableGateway);
return $table;
},
'AlbumTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('albums', $dbAdapter, null, $resultSetPrototype);
}
)
);
}
and here is my module.config.php:
return array(
'service_manager' => array(
'invokables' => array(
'Album\Model\Abstracts\IAlbumRepository' => 'Album\Model\Concrete\AlbumRepository'
),
),
'controllers' => array(
'factories' => array(
'Album\Controller\Album' => 'Album\Model\Factories\AlbumControllerFactory',
),
),
the error is:
Catchable fatal error: Argument 1 passed to Album\Model\Concrete\AlbumRepository::__construct() must be an instance of Zend\Db\TableGateway\TableGateway, none given, called in C:\xampp\htdocs\ZendFrameworkTest\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php on line 1035 and defined in C:\xampp\htdocs\ZendFrameworkTest\module\Album\src\Album\Model\Concrete\AlbumRepository.php on line 11
Note:
the delegate functions on the factories array are just not getting called, i'm doing somethign silly but i can't tell what.
I'm also doing dependancy injection, i'm guessing this is where it's going wrong as the factory is creating the repository object without the injection:
class AlbumControllerFactory implements FactoryInterface
{
/**
* Create service
*
* #param ServiceLocatorInterface $serviceLocator
*
* #return mixed
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
// Need to do something here?
$realServiceLocator = $serviceLocator->getServiceLocator();
$postService = $realServiceLocator->get('Album\Model\Abstracts\IAlbumRepository');
return new AlbumController($postService);
}
}
You defined your repository as invokable, that means that service manager tries to create it by instantiating directly without any params.
change it to alias
return array(
'service_manager' => array(
'aliases' => array(
'Album\Model\Abstracts\IAlbumRepository' => 'Album\Model\Concrete\AlbumRepository'
),
),
);
Related
In current state I've got two modules - main module, and admin panel module.
Main module is called "Kreator", admin -> "KreatorAdmin". All the models are located inside the Kreator module (Kreator/Model/UserTable.php etc.).
"KreatorAdmin" is almost empty, there is a configuration for it:
KreatorAdmin/config/module.config.php
<?php
return array(
'controllers' => array(
'invokables' => array(
'KreatorAdmin\Controller\Admin' => 'KreatorAdmin\Controller\AdminController',
),
),
'router' => array(
'routes' => array(
'zfcadmin' => array(
'options' => array(
'defaults' => array(
'controller' => 'KreatorAdmin\Controller\Admin',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
__DIR__ . '/../view'
),
),
);
KreatorAdmin/src/KreatorAdmin/AdminController.php
<?php
namespace KreatorAdmin\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class AdminController extends AbstractActionController
{
public function indexAction()
{
//$this->getServiceLocator()->get('Kreator\Model\UserTable');
return new ViewModel();
}
}
KreatorAdmin/Module.php
<?php
namespace KreatorAdmin;
class Module
{
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
Simply adding "use" statements in controller and navigating by namespaces results in error
Argument 1 passed to KreatorAdmin\Controller\AdminController::__construct() must be an instance of Kreator\Model\UserTable, none given,
I also tried to play a bit with service manager as described here:
ZF2 Models shared between Modules but no luck so far.
How am I supposed to access UserTable from KreatorAdmin/src/KreatorAdmin/AdminController.php ?
Cheers!
update 1
I've added getServiceConfig to Module.php
public function getServiceConfig()
{
return [
'factories' => [
// 'Kreator\Model\UserTable' => function($sm) {
// $tableGateway = $sm->get('UserTableGateway');
// $table = new UserTable($tableGateway);
// return $table;
// },
// 'UserTableGateway' => function($sm) {
// $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
// $resultSetPrototype = new ResultSet();
// $resultSetPrototype->setArrayObjectPrototype(new User());
// return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
// },
'DbAdapter' => function (ServiceManager $sm) {
$config = $sm->get('Config');
return new Adapter($config['db']);
},
'UserTable' => function (ServiceManager $sm) {
return new UserTable($sm->get('UserTableGateway'));
},
'UserTableGateway' => function (ServiceManager $sm) {
$dbAdapter = $sm->get('DbAdapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
return new TableGateway('users', $dbAdapter, null, $resultSetPrototype);
},
],
];
}
And updated controller
class AdminController extends AbstractActionController
{
protected $userTable;
public function indexAction()
{
$userTable = $this->getServiceLocator()->get('Kreator\Model\UserTable');
return new ViewModel();
}
}
First error - using commented version:
Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Zend\Db\Adapter\Adapter
Second - using uncommented part:
Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Kreator\Model\UserTable
Solution
If anyone wonder. Using above configuration there is a correct solution in jobaer answer.
Using commented version, you have to remember to add
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
somewhere in config to service_manager.
May be you messed up with ZF2 and ZF3 configuration. I am not sure but somewhere may be, you tried to create a factory of AdminController by passing an instance of UserTable to make it available inside AdminController's action methods. And later you are not passing that instance of UserTable into the AdminController's constructor while working with it further. The highlighted part from the previous line results in that error.
In ZF2 you do not need to pass that UserTable instance in the controller's constructor for its availability. Just use the following one in any controller's action methods.
$userTable = $this->getServiceLocator()->get('UserTable');
If want to know how this process is done, please, refer to this part of the tutorial.
I'm building my first Zend Framework 2 application with the skeleton tutorial. But whenever I try to call any plugin from any controller, I get the error message:
A plugin by the name "PLUGIN_NAME" was not found in the plugin manager
Zend\Mvc\Controller\PluginManager
Unfortunately I don't know which part of the code could help you to help me. I post some files which I think could be important.
config/modules.config
return [
'Zend\Router',
'Zend\Validator',
'Zend\Form',
'Album',
'Application',
'User',
];
module/User/src/Module.php
<?php
namespace User;
use User\Model\User;
use User\Model\UserTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
class Module
{
const VERSION = '1.0.0dev';
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\ClassMapAutoloader' => array(
__DIR__ . '/autoload_classmap.php',
),
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getConfig()
{
return include __DIR__ . '/../config/module.config.php';
}
public function getServiceConfig()
{
return array(
'factories' => array(
'User\Model\UserTable' => function($sm) {
$tableGateway = $sm->get('UserTableGateway');
$table = new UserTable($tableGateway);
return $table;
},
'UserTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new User());
return new TableGateway('user', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
}
module/User/config/module.config.php
<?php
namespace User;
use Zend\ServiceManager\Factory\InvokableFactory;
use Zend\Router\Http\Segment;
return [
'controllers' => [
'factories' => [
Controller\UserController::class => InvokableFactory::class,
],
'invokables' => [
'User\Controller\User' => 'User\Controller\UserController',
],
],
'router' => [
'routes' => [
'user' => [
'type' => Segment::class,
'options' => [
'route' => '/user[/:action[/:id]]',
'constraints' => [
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
],
'defaults' => [
'controller' => Controller\UserController::class,
'action' => 'index',
],
],
],
],
],
'view_manager' => [
'template_path_stack' => [
'user' => __DIR__ . '/../view',
],
],
];
I'm trying to call my plugins like this from a controller action:
$this->flashMessanger()->...
$this->identity();
$this->getServiceLocator();
Because I really needed the Service Locator, I found a workaround, which is not so nice I think, but works for me:
$sm = $this->getEvent()->getApplication()->getServiceManager();
But I guess something is wrong here.
Edit:
For a better reproduction of what I did (I installed Zend Framework again and it still gives me the same error):
Installed Zend Framework (2.4 I guess?) by this installation guide (https://framework.zend.com/manual/2.4/en/ref/installation.html). I installed it with the following command:
composer create-project -sdev --repository-url="https://packages.zendframework.com" zendframework/skeleton-application
On the installation, when I was asked if I want to install a minimum install, I chose "No". Every next question I answered with "Yes" (the installer asks to install a lot of modules, I installed them all).
The installer asked in which config I want to inject "ZendDeveloperTools". I answered 2 (config/development.config.php.dist). For all others I chose 1 (config/modules.config.php).
I tested the skeleton application by calling the url in my browser, it worked.
I downloaded the Album module from GitHub here (https://github.com/Hounddog/Album).
I copied the album module to my modules folder.
I added the entry 'Album' to my config/modules.config.php file
I browsed to the album page
I'm getting the error:
A plugin by the name "getServiceLocator" was not found in the plugin
manager Zend\Mvc\Controller\PluginManager
I assume the reason for this error is the getAlbumTable() method in the AlbumController
public function getAlbumTable()
{
if (!$this->albumTable) {
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('Album\Model\AlbumTable');
}
return $this->albumTable;
}
In the ZF2 docs for controller plugins you can read that your controller has to implement the following methods: setPluginManager, getPluginManager and plugin. You can also read:
For an extra layer of convenience, both AbstractActionController and AbstractActionController have __call() implementations that allow you to retrieve plugins via method calls:
$plugin = $this->url();
Does your controller extend AbstractActionController or AbstractActionController? If yes, it should work as mentioned in the docs (so those methods you mention in your question should work).
Since you didn't share any controller code it is hard to say whether this is the problem...
UPDATE
The error you get is not related to the configuration of your ControllerPluginManager, but you get this error because you are doing:
$sm = $this->getServiceLocator();
Since the method getServiceLocator doesn't exist the magic __call() method is executed and this leads to the error.
This is because in the latest versions of ZF2 the controller classes are no longer 'service locator aware' meaning you cannot retrieve the ServiceManager by calling $this->getServiceLocator().
Instead you will have to inject your Album\Model\AlbumTable service into the controller class inside a factory:
1) Add a constructor method to your controller class:
public function __construct(AlbumTable $albumTable){
$this->albumTable = $albumTable;
}
2) Create a factory for your controller:
<?php
namespace Album\Controller\Factory;
use Album\Controller\AlbumController;
class AlbumControllerFactory implements FactoryInterface
{
/**
* #param ServiceLocatorInterface $serviceLocator
* #return AlbumController
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$controllerPluginManager = $serviceLocator;
$serviceManager = $controllerPluginManager->get('ServiceManager');
$albumTable = $serviceManager->get('Album\Model\AlbumTable');
return new AlbumController($albumTable);
}
}
3) Register your controller factory inside your module.config.php:
'factories' => [
`Album\Controller\AlbumController` => `Album\Controller\Factory\AlbumControllerFactory`,
],
The function getAlbumTable() was used in ZF2 tutorial but in ZF3 it was replaced by member table.
Change the deleteAction() function in AlbumController.php to read:
public function deleteAction()
{
$id = (int) $this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('album');
}
$request = $this->getRequest();
if ($request->isPost()) {
$del = $request->getPost('del', 'No');
if ($del == 'Yes') {
$id = (int) $request->getPost('id');
$this->table->deleteAlbum($id);
}
// Redirect to list of albums
return $this->redirect()->toRoute('album');
}
return array(
'id' => $id,
'album' => $this->table->getAlbum($id)
);
}
Note the two lines reading $this->table->... instead of $this->getAlbumTable()->...
How can create a connection to my data/database.db
I get this connection only with one config but don't from another config in the same file module.php
In this code it's ok
public function getServiceConfig()
{
return array(
'factories' => array(
'Music\V1\Rest\Album\AlbumMapper' => function ($sm) {
$adapter = $sm->get('Zend\Db\Adapter\Adapter');
return new \Music\V1\Rest\Album\AlbumMapper($adapter);
},
),
);
}
But if I try with two connection doesn't work:
public function getServiceConfig()
{
return array(
'factories' => array(
'Music\V1\Rest\Album\AlbumMapper' => function ($sm) {
$adapter = $sm->get('Zend\Db\Adapter\Adapter');
return new \Music\V1\Rest\Album\AlbumMapper($adapter);
},
'Music\V1\Rest\Albumjson\AlbumjsonMapper' => function ($sm) {
$adapter = $sm->get('Zend\Db\Adapter\Adapter');
return new \Music\V1\Rest\Albumjson\AlbumjsonMapper($adapter);
},
),
);
}
I get the next error with zf2:
An abstract factory could not create an instance of musicv1restalbumjsoncontroller(alias: Music\\V1\\Rest\\Albumjson\\Controller).
The error has nothing to do with your database setup. It means your controller class cannot be found. Did you properly register a controller called Music\\V1\\Rest\\Albumjson\\Controller?
I have problem with creating custom translator from database in ZF2. I have a DB like this
and files:
1)Application/module.config.php
'service_manager' => array(
'abstract_factories' => array(),
'factories' => array(
'translator' => function (\Zend\ServiceManager\ServiceManager $serviceManager)
{
$pluginManager = new \Zend\I18n\Translator\LoaderPluginManager();
$pluginManager->setServiceLocator($serviceManager);
$pluginManager->setFactory('DatabaseTranslationLoaderFactory', function($serviceManager)
{
$translator = new \Zend\I18n\Translator\DatabaseTranslationLoaderFactory();
return $translator->createService($serviceManager);
});
$translator = new \Zend\I18n\Translator\Translator(array());
$translator->setFallbackLocale('en_US');
$translator->setPluginManager($pluginManager);
$translator->addRemoteTranslations('DatabaseTranslationLoaderFactory');
return $translator;
},
),
),
'translator' => array(
'locale' => 'en_US',
'translation_file_patterns' => array(
array(
'type' => 'Zend\I18n\Translator\Loader\Database',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s.mo',
),
),
),
2) Zend/I18n/Translator/Loader/Database.php
<?php
namespace Zend\I18n\Translator\Loader;
use Zend\Db\Adapter\Adapter;
use Zend\Db\Sql\Sql;
use Zend\I18n\Translator\Plural\Rule as PluralRule;
use Zend\I18n\Translator\TextDomain;
class Database implements RemoteLoaderInterface {
protected $dbAdapter;
public $dbAdapter;
public function __construct(Adapter $dbAdapter = null)
{
if ($dbAdapter === null)
{
$configArray = array('driver' => 'Pdo_Mysql',
'database' => 'dbname',
'username' => 'username',
'password' => 'pswd',
'hostname' => 'localhost',
'charset' => 'utf-8',
);
$dbAdapter = new Adapter($configArray);
}
$this->dbAdapter = $dbAdapter;
}
public function load($locale, $textDomain)
{
$sql = new Sql($this->dbAdapter);
$select = $sql->select('ic_var')->columns(array('value'))
->where(array('language' => $locale, 'name' => $textDomain));
$messages = $this->dbAdapter->query(
$sql->getSqlStringForSqlObject($select),
Adapter::QUERY_MODE_EXECUTE
);
$textDomain = new TextDomain();
foreach ($messages as $message) {
if (isset($textDomain[$message['name']])) {
if (!is_array($textDomain[$message['name']])) {
$textDomain[$message['name']] = array(
$message['plural_index'] => $textDomain[$message['name']]
);
}
$textDomain[$message['name']][$message['plural_index']] = $message['value'];
} else {
$textDomain[$message['name']] = $message['value'];
}
}
return $textDomain;
}
}
3) Zend/I18n/Translator/DatabaseTranslationLoaderFactory.php
<?php
namespace Zend\I18n\Translator;
use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
use Zend\I18n\Translator\Loader\Database;
class DatabaseTranslationLoaderFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
return new Database($serviceLocator->get('Zend\Db\Adapter\Adapter'));
}
}
4) Application/Module.php
public function onBootstrap(MvcEvent $e)
{
$translator = $e->getApplication()->getServiceManager()->get('translator');
$translator->addTranslationFile(
'DatabaseTranslationLoader',
'text-domain',
'text-domain'
);
}
But translation doesn`t work, because db adapter not find in loader:
Fatal error: Uncaught exception 'Zend\I18n\Exception\RuntimeException' with message 'Specified loader is not a file loader'
Thanks for your answers!
First of all you shouldn't define your custom classes in the Zend namespace as this is reserved a namespace for the ZF2 library and you don't want to touch (or add) files in the vendor directory.
Just put the custom classes in your own namespace outside the vendor folder. i.e. MyI18n
You can register you custom remote loader to the pluginManager in module.config.php.
return array(
'translator' => array(
'loaderpluginmanager' => array(
'factories' => array(
'database' => 'MyI18n\Translator\DatabaseTranslationLoaderFactory',
)
),
'remote_translation' => array(
array(
'type' => 'database' //This sets the database loader for the default textDomain
),
),
)
);
You don't have to overwrite the Translator factory if you want to add a custom loader, so just remove that code in your Module.php.
Als remove the configuration under translation_file_patterns as this is only needed for file loaders.
EDIT
For the above to work you need to overwrite the TranslatorServiceFactory because ZF has no support to register custom loaders on the plugin manager.
namespace MyNamespace\Translator;
use Zend\Mvc\Service\TranslatorServiceFactory as BaseTranslatorFactory;
class TranslatorServiceFactory extends BaseTranslatorFactory
{
/**
* #param ServiceLocatorInterface $serviceLocator
* #return MvcTranslator
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
$translator = parent::createService($serviceLocator);
$config = $serviceLocator->get('Config');
$pluginManagerConfig = isset($config['translator']['loaderpluginmanager']) ? $config['translator']['loaderpluginmanager'] : array();
$pluginManager = new LoaderPluginManager(new Config($pluginManagerConfig));
$pluginManager->setServiceLocator($serviceLocator);
$translator->setPluginManager($pluginManager);
return $translator;
}
}
Now register your custom factory in the service configuration:
class Module
{
public function getServiceConfig()
{
return array(
'factories' => array(
'MvcTranslator' => 'MyNamespace\Translator\TranslatorServiceFactory',
)
)
}
}
I register custom remote loader to the pluginManager in module.config.php like this
'translator' => [
'loaderpluginmanager' => [
'factories' => [
'database' => function($lpm){
$sm = $lpm->getServiceLocator();
$loader = new Zf2Translation\Loader\DatabaseTranslationLoader($sm);
return $loader;
},
],
],
'remote_translation' => [
[
'type' => 'database',
],
],
]
Next in Database Loader class
use Zend\I18n\Translator\Loader\RemoteLoaderInterface;
class DatabaseTranslationLoader implements RemoteLoaderInterface
{
protected $dbAdapter;
protected $sm;
public function __construct(ServiceManager $sm)
{
$this->sm = $sm;
$this->dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
}
}
I hope it helps.
I'm having a problem with setting up a model table from a view helper. I have used the exact same code that I use within my regular controllers: e.g.:
namespace Application\View\Helper;
use Zend\View\Helper\AbstractHelper;
use Application\Model\MenusTable;
use Zend\ServiceManager\ServiceLocatorAwareInterface;
use Zend\ServiceManager\ServiceLocatorInterface;
**snipped**
public function setServiceLocator(ServiceLocatorInterface $serviceLocator)
{
$this->serviceLocator = $serviceLocator;
return $this;
}
public function getServiceLocator()
{
return $this->serviceLocator;
}
public function getMenusTable()
{
if (!$this->menusTable) {
$sm = $this->getServiceLocator();
$this->menusTable = $sm->get('Application\Model\MenusTable');
}
return $this->menusTable;
}
public function allLinks()
{
$all = $this->getMenusTable()->fetchAll();
return $all;
}
However I am met with this error:
Catchable fatal error: Argument 1 passed to Application\Model\MenusTable::__construct() must be an instance of Zend\Db\Adapter\Adapter, none given, called in C:\xampp\**snipped**\zend\library\Zend\ServiceManager\AbstractPluginManager.php on line 177 and defined in C:\xampp\**snipped**\Application\src\Application\Model\MenusTable.php on line 14
Everything works fine from the main controllers, but here I seem to hit a big problem - I'm new to Zend, but it appears to not be getting the factory from the Module.php file - is there any way to get it?
I have this in my Module.php - as said it works fine in a regular controller, but in a view helper it's not processed for some reason:
public function getServiceConfig()
{
return array
(
'factories' => array
(
'Application\Model\MenusTable' => function($sm)
{
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new MenusTable($dbAdapter);
return $table;
},
),
);
}
After re-reading your question I realized that your using ZF2.
here is a tutorial on using ServiceLocators http://framework.zend.com/wiki/display/ZFDEV2/Proposal+for+ServiceLocator+and+DependencyInjector
From the Documentation you need to define your DB connection.
$services = new ServiceLocator();
// Registering an object:
$services->set('db', $db);
// Lazy-loading by registering a closure:
$services->set('db', function() use ($config) {
$db = Db::factory($config->db);
return $db;
});
// Retrieving:
$db = $services->get('db');
First you should use the getServiceConfig() in your module ::
public function getServiceConfig()
{
return array(
'factories' => array(
'MODULE\Model\MenusTable' => function($sm) {
$tableGateway = $sm->get('MenusTableGateway');
$table = new MenusTable($tableGateway);
return $table;
},
'MenusTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Menus());
return new TableGateway('menus', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
THE ADAPTER might be in your /config/autoload/global.php, like this :
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
// CONNECTION DB
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=YOURDBNAME;host=localhost',
'username' => 'root',
'password' => '',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
Next your View helper must extend AbstractHelper but also implement ServiceLocatorAwareInterface
class MyViewHelper extends AbstractHelper implements ServiceLocatorAwareInterface
I'll put the code in my website