I have created a new module to add a new step to the signup process to get the user's phone number. Everything works fine, except the fact that after the signup, I need to grab the phone number I have received in my specific step and add it to the users table. For this purpose, I have added a hook in my module's manifest file as follows to be triggered after signup completes:
<?php
return array(
'package' =>
array(
'type' => 'module',
'name' => 'advancedsmsplugin',
'version' => '4.0.0',
'sku' => 'com.company.sms',
'path' => 'application/modules/Advancedsmsplugin',
'title' => 'Advanced SMS Plugin',
'description' => 'Advanced SMS Plugin',
'author' => 'Company Ltd.',
'callback' =>
array(
'class' => 'Engine_Package_Installer_Module',
),
'actions' =>
array(
0 => 'install',
1 => 'upgrade',
2 => 'refresh',
3 => 'enable',
4 => 'disable',
),
'directories' =>
array(
0 => 'application/modules/Advancedsmsplugin',
),
'files' =>
array(
0 => 'application/languages/en/advancedsmsplugin.csv',
1 => 'application/modules/User/Form/Signup/Phone.php',
2 => 'application/modules/User/Plugin/Signup/Phone.php',
),
),
'hooks' => array(
array(
'event' => 'onUserCreateAfter',
'resource' => 'User_Plugin_Phone',
),
),
);
?>
I have also created the class that I named in the hook namely User_Plugin_Phone and saved it as application/modules/user/Plugin/Phone.php.
class User_Plugin_Phone extends Core_Plugin_Abstract {
public function onUserCreateAfter($event) {
echo '<script>console.log("Inside User_Plugin_Phone::onUserCreateAfter");</script>';
echo '<script>alert("Inside User_Plugin_Phone: onUserCreateAfter");</script>';
$payload = $event->getPayload();
}
}
But, logs show that the hook is not triggered at all. I have checked this and this, and I think I have followed them correctly. Any ideas why this does not work]?
Related
I have an application with three modules with several controllers in each module. All these controllers work fine. But now, I'm trying to create a new controller in my Privado module, in this route /domain/privado/querys/querys.
I have created the controller, her view, and config in module.config.php
'privado/querys' => array(
'type' => 'Literal',
'options' => array(
'route' => '/privado/querys',
'defaults' => array(
'__NAMESPACE__' => 'Privado\Controller',
'controller' => 'Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
//'route' => '/[:controller[/:action[/:id]]]',
'route' => '/[:controller[/:action][/:id/:system]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]*',
'system' => '[a-zA-Z][a-zA-Z0-9_-]*'
//'system' => '[0-9]*'
),
'defaults' => array(
),
),
),
),
),
'controllers' => array(
'invokables' => array(
'Privado\Controller\Index' => Controller\IndexController::class,
'Privado\Controller\Usuario' => Controller\UsuarioController::class,
'Privado\Controller\Profile' => Controller\ProfileController::class,
'Privado\Controller\Sistemas' => Controller\SistemasController::class,
'Privado\Controller\UnidadesServicio' => Controller\UnidadesServicioController::class,
'Privado\Controller\Metales' => Controller\MetalesController::class,
'Privado\Controller\Pases' => Controller\PasesController::class,
'Privado\Controller\Estado' => Controller\EstadoController::class,
'Privado\Controller\QuerysController' => Controller\QuerysController::class,
'Privado\Controller\TestController' => Controller\TestController::class
),
),
'view_manager' => array(
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
'privado/index/index' => __DIR__ . '/../view/privado/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
__DIR__ . '/../view',
),
/*
* Con este array de parĂ¡metros permitimos enviar datos y no mostrar vista
*/
'strategies' => array(
'ViewJsonStrategy',
),
),
And the controller returns me the layout from another module The controller returns me the layout from the Publico module. I just understand what I missed.
Edit 1:
I've got the wrong layout and this message on the screen:
A 404 error occurred Page not found.
The requested controller could not be mapped to an existing controller
class.
Controller:
Privado\Controller\Querysasdad(resolves to invalid controller class or alias: Privado\Controller\Querysasdad)
No Exception available
This is the error that I've got too, If I write a controller which doesn't exists in the url !
I have create another controller in other module following the same steps: create the controller, create the view, config module.config.php and works fine.
I have found my terrible error :
In my module.config.php I have in invocables ...
'Privado\Controller\QuerysController' => Controller\QuerysController::class,
'Privado\Controller\TestController' => Controller\TestController::class
I fix the problema, remove "Controller" from "Privado\Controller\QuerysController" and "Privado\Controller\TestController"
'Privado\Controller\Querys' => Controller\QuerysController::class,
'Privado\Controller\Test' => Controller\TestController::class
Can someone help me to set up a layout for the administration module and set up a layout for the application module ? . In the image below you can see my folder structure:
This is the content of my module.config.php from the administration module:
<?php
return array(
'controllers' => array(
'invokables' => array(
'Administration\Controller\Admin' => 'Administration\Controller\AdminController',
),
),
// The following section is new and should be added to your file
'router' => array(
'routes' => array(
'album' => array(
'type' => 'segment',
'options' => array(
'route' => '/administration[/:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+',
),
'defaults' => array(
'controller' => 'Administration\Controller\Admin',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
//'base_path' => 'http://www.attila-naghi.com/',
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
'layout/layout' => __DIR__ . '/../view/layout/layout2.phtml',
// 'administration/admin/index' => __DIR__ . '/../view/administration/admin/index.phtml',
// 'error/404' => __DIR__ . '/../view/error/404.phtml',
// 'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
DIR . '/../view',
),
),
)
?>
here i set up the layout. But for some reason if i access the application module, it loads the layout from the administration module. WHY ?
this is the content of the module.config.php file from the application module:
return array(
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '[:controller[/:action]][/:param1]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*'
),
'defaults' => array(
'action' => 'index',
'__NAMESPACE__' => 'Application\Controller',
// 'param1' => 'tralala'
)
)
)
)
),
),
),
'service_manager' => array(
'abstract_factories' => array(
'Zend\Cache\Service\StorageCacheAbstractServiceFactory',
'Zend\Log\LoggerAbstractServiceFactory',
),
'aliases' => array(
'translator' => 'MvcTranslator',
),
),
'translator' => array(
'locale' => 'en_US',
'translation_file_patterns' => array(
array(
'type' => 'gettext',
'base_dir' => __DIR__ . '/../language',
'pattern' => '%s.mo',
),
),
),
'controllers' => array(
'invokables' => array(
'Application\Controller\Index' => 'Application\Controller\IndexController',
'Application\Controller\Create' => 'Application\Controller\CreateController',
'Application\Controller\Blog' => 'Application\Controller\BlogController',
'Application\Controller\Portofolio' => 'Application\Controller\PortofolioController',
'Application\Controller\User' => 'Application\Controller\UserController',
),
),
'view_manager' => array(
'base_path' => 'http://www.attila-naghi.com/',
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_map' => array(
'layout/layout' => __DIR__ . '/../view/layout/layout.phtml',
'application/index/index' => __DIR__ . '/../view/application/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
__DIR__ . '/../view',
),
),
// Placeholder for console routes
'console' => array(
'router' => array(
'routes' => array(
),
),
),
);
and this is the application.config.file content:
return array(
// This should be an array of module namespaces used in the application.
'modules' => array(
'Application',
'Administration'
),
......
You have to change layout from the controller. just specify this code above the ViewModel
$this->layout('administration/admin/index');
The configs of all modules are merged into a single config. The last loaded module will overwrite the layout from the first module. You can use the module below to set layout per module.
https://github.com/EvanDotPro/EdpModuleLayouts
I have recently found a way to do it (someone else's solution).
Add this to your module.config.php (in my case the module is called Album, this is based on the demo application of ZF2):
'module_layouts' => array(
'Album' => 'layout/layout.phtml'
),
The other necessary change needs to be done in the main Module.php file (add this onBootstrap method there and edit as may be needed):
public function onBootstrap($e) {
$e->getApplication()
->getEventManager()
->getSharedManager()
->attach('Zend\Mvc\Controller\AbstractController', 'dispatch',
function($e) {
$controller = $e->getTarget();
$controllerClass = get_class($controller);
$moduleNamespace = substr($controllerClass, 0, strpos($controllerClass, '\\'));
$config = $e->getApplication()->getServiceManager()->get('config');
if (isset($config['module_layouts'][$moduleNamespace])) {
$controller->layout($config['module_layouts'][$moduleNamespace]);
}
}, 100);
}
As requested here is my way for different layouts. This was not my idea but since i cannot find the source i will post the code here. If someone does know please add the URL in comment and i will include it in the answer. If you read the sources i gave you in the other question and the above answers i am sure will understand what is happening here.
Module.php
use Zend\ModuleManager\ModuleManager;
> > public function init(ModuleManager $moduleManager)
> {
> $sharedEvents = $moduleManager->getEventManager()->getSharedManager();
> $sharedEvents->attach(__NAMESPACE__, 'dispatch', function($e) {
> // This event will only be fired when an ActionController under the MyModule namespace is dispatched.
>
> $controller = $e->getTarget();
$controller->layout('backofficeLayout');
>
> }, 100);
>
>
>
> }
module.config.php
'view_manager' => array(
'display_not_found_reason' => true,
'display_exceptions' => true,
'doctype' => 'HTML5',
'not_found_template' => 'error/404',
'exception_template' => 'error/index',
'template_path_stack' => array(
'backoffice' => __DIR__ . '/../view',
),
'template_map' => array(
'backofficeLayout' => __DIR__ . '/../view/layout/myaccount-backoffice.phtml',))
I have just noticed that is better to use custom name for each of the layout in your layout folder. Instead of using layout.phtml use layout-mymodulename.phtml. It worked better along with the previously highlighted points.
How i can set a success_handler (and failure_handler) for the form authentication provider?
Silex ignores me with this config:
<?php
use WebFactory\Security\UserProvider;
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'dev' => array(
'pattern' => '^/(_(profiler|wdt)|css|images|js)/',
'security' => false
),
'default' => array(
'pattern' => '^/.*$',
'anonymous' => true,
'form' => array(
'login_path' => '/login',
'check_path' => '/login_check',
'success_handler' => 'authentication_handler', //<-- here
'failure_handler' => 'authentication_handler', //<-- here
),
'logout' => array('logout_path' => '/logout'),
'users' => $app->share(function () use ($app) {
return new UserProvider($app['db']);
}),
),
),
'security.access_rules' => array(
array('^/login', 'IS_AUTHENTICATED_ANONYMOUSLY'),
array('^/private$', 'ROLE_ADMIN'),
),
'security.role_hierarchy' => array(
'ROLE_SIMPLE_USER' => array('ROLE_USER'),
'ROLE_ASSOCIATE' => array('ROLE_USER'),
)
));
And this my custom (never invoked)
$app['authentication_handler'] = $app->share(function ($app) {
return new \WebFactory\Security\AuthenticationHandler($app['url_generator']);
});
It is a bug?
The way you set success and failure handlers is by defining a service called security.authentication.success_handler.$name or security.authentication.failure_handler.$name, where $name is the name of the firewall.
For example:
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => array(
'foo' => ...,
),
));
$app['security.authentication.success_handler.foo'] = $app->share(function ($app) {
return new Your\Own\SuccessHandler();
});
The security service provider will then detect the handlers by convention.
I have a problem with the EdpModuleLayouts module. I put Module.php in module/EdpModuleLayouts/ directory with the following content:
<?php
namespace EdpModuleLayouts;
class Module {
public function onBootstrap($e) {
$e->getApplication()->getEventManager()->getSharedManager()->attach('Zend\Mvc\Controller\AbstractActionController', 'dispatch', function($e) {
$controller = $e->getTarget();
$controllerClass = get_class($controller);
$moduleNamespace = substr($controllerClass, 0, strpos($controllerClass, '\\'));
$config = $e->getApplication()->getServiceManager()->get('config');
if (isset($config['module_layouts'][$moduleNamespace])) {
$controller->layout($config['module_layouts'][$moduleNamespace]);
}
}, 100);
}
}
I also registered it in the config/application.config.php:
return array(
'modules' => array(
'EdpModuleLayouts',
'Main',
'Administrator',
'Object'
),
'module_layouts' => array(
'Main' => 'layout/main',
'Administrator' => 'layout/admin',
),
'module_listener_options' => array(
'module_paths' => array(
'./module',
),
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
),
);
The config ot the "main" module looks like:
<?php
return array(
'router' => array(
'routes' => array(
'Main' => array(
'type' => 'Literal',
'options' => array(
'route' => '/main',
'defaults' => array(
'__NAMESPACE__' => 'Main\Controller',
'controller' => 'Index',
'action' => 'index',
),
),
'may_terminate' => true,
'child_routes' => array(
'default' => array(
'type' => 'Segment',
'options' => array(
'route' => '[/:controller][/:action][/:id]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]*',
),
'defaults' => array(
),
),
),
),
),
),
),
'service_manager' => array(
'factories' => array(),
),
'controllers' => array(
'invokables' => array(
'Main\Controller\Index' => 'Main\Controller\EmailController',
'Main\Controller\Error' => 'Main\Controller\ErrorController',
'Main\Controller\FAQ' => 'Main\Controller\FAQController',
'Main\Controller\Index' => 'Main\Controller\IndexController',
'Main\Controller\Pages' => 'Main\Controller\PagesController',
'Main\Controller\Settings' => 'Main\Controller\SettingsController',
'Main\Controller\User' => 'Main\Controller\UserController',
),
),
'view_manager' => array(
'template_map' => array(
'layout/main' => __DIR__ . '/../view/layout/main_layout.phtml',
'layout/header' => __DIR__ . '/../view/layout/main_header.phtml',
'layout/footer' => __DIR__ . '/../view/layout/main_footer.phtml',
'index/index' => __DIR__ . '/../view/index/index.phtml',
'error/404' => __DIR__ . '/../view/error/404.phtml',
'error/index' => __DIR__ . '/../view/error/index.phtml',
),
'template_path_stack' => array(
__DIR__ . '/../view',
),
'display_exceptions' => true,
'exception_template' => 'error/index',
'display_not_found_reason' => true,
'not_found_template' => 'error/404',
),
);
But when I access whatever module in the application I want, it throws an exception:
( ! ) Fatal error: Uncaught exception 'Zend\View\Exception\RuntimeException' with message 'Zend\View\Renderer\PhpRenderer::render: Unable to render template "layout/layout"; resolver could not resolve to a file' in D:\WebServer\www\homepage\vendor\library\Zend\View\Renderer\PhpRenderer.php on line 461
( ! ) Zend\View\Exception\RuntimeException: Zend\View\Renderer\PhpRenderer::render: Unable to render template "layout/layout"; resolver could not resolve to a file in D:\WebServer\www\homepage\vendor\library\Zend\View\Renderer\PhpRenderer.php on line 461
What's the reason?
As a newcomer to ZF2, it took me a while to make EdpModuleLayouts module to work. The key is to configuring the "view_manager" and "template_map" settings. Please visit http://www.webtrafficexchange.com/zf2-configure-layout-each-module-edpmodulelayouts for configuration samples.
All this is doing is setting the appropriate layout.
controller->layout($config['module_layouts'][$moduleNamespace]);
The error message is telling you that it was unable to find the template it is trying to set. You still need to configure your layouts in the template map. Here is an example from one of my projects.
'view_manager' => array(
'template_map' => array(
'cms-admin/admin/dashboard' => __DIR__ . '/../view/cms-admin/admin/dashboard.phtml',
'cms-admin/login/login' => __DIR__ . '/../view/cms-admin/login/login.phtml',
'cms-admin/users/index' => __DIR__ . '/../view/cms-admin/admin/users/index.phtml'
)
),
'module_layouts' => array(
'CmsAdmin' => 'layout/admin-layout',
),
Does the if (isset($config['module_layouts'][$moduleNamespace])) evaluates to true? I think that your option module_layouts should be in the config directory:
./config/layouts.config.glob.php:
<?php
return array(
'module_layouts' => array(
'Main' => 'layout/main',
'Administrator' => 'layout/admin',
),
);
?>
Could you give that a try?
What I'm trying to accomplish
I'm building a favorites module and I need the ability to:
Select from a dropdown, hardcoded list of options
Have it save to the database
Upon refreshing the page, remove the already saved option from the list of options so it may not be added again
The third part is where I am unsure of how to proceed.
How my code is set up
This is my form:
/*
* Implentation of hook_form().
*/
function f25_favorites_form() {
$listOfPaths = f25_favorites_listOfPaths();
$form['path_options'] = array(
'#type' => 'value',
'#value' => array(
'default' => $listOfPaths['default']['#title'],
'concierge' => $listOfPaths['concierge']['#title'],
'concierge/add' => $listOfPaths['concierge/add']['#title'],
'survey-questions' => $listOfPaths['survey-questions']['#title'],
'survey-questions/add' => $listOfPaths['survey-questions/add']['#title'],
'profiles' => $listOfPaths['profiles']['#title'],
'profiles/add' => $listOfPaths['profiles/add']['#title'],
'statistics' => $listOfPaths['statistics']['#title'],
)
);
$form['path'] = array(
'#type' => 'select',
'#title' => t('Select Page'),
'#required' => TRUE,
'#weight' => '11',
'#options' => $form['path_options']['#value'],
);
$form[submit] = array(
'#type' => 'submit',
'#weight' => '1000000',
'#value' => t('Add')
);
return $form;
}
The name of the paths/options are called via a reference array:
/*
* List of Paths to add to favorites
*/
function f25_favorites_listOfPaths() {
$list = array();
$list = array(
'default' => array(
'#title' => t('Add to favorites'),
),
'concierge' => array(
'#title' => t('Concierge'),
'#image' => drupal_get_path('module', 'f25_favorites').'/img/concierge.png',
'#desc' => t('Concierge'),
),
'concierge/add' => array(
'#title' => t('New Concierge'),
'#image' => drupal_get_path('module', 'f25_favorites').'/img/concierge.png',
'#desc' => t('Concierge > Add'),
),
'survey-questions' => array(
'#title' => t('Survey Questions'),
'#image' => drupal_get_path('module', 'f25_favorites').'/img/survey-questions.png',
'#desc' => t('Current Survey Questions'),
),
'survey-questions/add' => array(
'#title' => t('New Survey Question'),
'#image' => drupal_get_path('module', 'f25_favorites').'/img/survey-questions.png',
'#desc' => t('Survery Question > Add'),
),
'profiles' => array(
'#title' => t('Profiles'),
'#image' => drupal_get_path('module', 'f25_favorites').'/img/profiles.png',
'#desc' => t('User Profiles'),
),
'profiles/add' => array(
'#title' => t('Add Profile'),
'#image' => drupal_get_path('module', 'f25_favorites').'/img/profiles.png',
'#desc' => t('Profiles > Add'),
),
'statistics' => array(
'#title' => t('Statistics'),
'#image' => drupal_get_path('module', 'f25_favorites').'/img/statistics.png',
'#desc' => t('Performance Stats'),
),
);
return $list;
}
And all this is what grabs the data on the databse:
/*
* Write Form data to database
*/
function f25_favorites_form_submit($form, &$form_state){
global $user;
$listOfPaths = f25_favorites_listOfPaths();
$selected = $form_state['values']['path'];
$data = array(
'uid' => $user->uid,
'path' => $selected,
'title' => $listOfPaths[$selected]['#title'],
'weight' => 10,
'timestamp' => time(),
);
drupal_write_record(f25_favorites, $data);
}
Possible Solutions
I've been told that I could used hook_form_alter() in order to modify my array but I am unsure as to when I should be comparing the db_query to my array and how to modify the differences accordingly.
I hope I've done a good job explaining what I'm try to do.
What would be the best way to accomplish this?
Instead of writing every response in f25_favorites_listOfPaths(), shouldn't you get them from the database?
You can then change whatever you want in the submit function to the database so that you don't fetch again the previously selected answer.
Example :
function f25_favorites_listOfPaths() {
return variable_get('f25_favorites_array_' . $user->uid, array(
// your $list array
));
}
function f25_favorites_submit_form($form, &$form_state) {
// your stuff already
drupal_write_record(f25_favorites, $data);
// Now what I propose you to do :)
variable_set('f25_favorites_array_' . $user->uid, array(
// new $list array without the favorite selected
));
}
The use of variable_get/set() should of course be replaced by your own table if you have too much datas.
P.S. : hook_form() does not exist :)