ZF2: How to attach listener on the event in the Module class? - zend-framework2

I want to set a basePath to be the same for every component of my Mvc for a given request. I mean when I call these methods I want to get the same result, lets say '/spam/ham/':
echo $this->headLink()->prependStylesheet($this->basePath() . '/styles.css') // $this->basePath() has to be '/spam/ham/'
$this->getServiceLocator()
->get('viewhelpermanager')
->get('headLink')
->rependStylesheet($this->getRequest()->getBasePath() . '/styles.css') // $this->setRequest()->getBasePath() has to be /spam/ham/
How to set the basePath for the first case I have found already, here's my question. By the way, the original manual doesn't have any info I received from the answer.
And now the second one - the basePath has to be set in the Request:
$this->getRequest()->getBasePath()
Here I found some answer that in fact doesn't work at all http://zend-framework-community.634137.n4.nabble.com/Setting-the-base-url-in-ZF2-MVC-td3946284.html. As said here StaticEventManager is deprecated so I changed it with SharedEventManager :
// In my Application\Module.php
namespace Application;
use Zend\EventManager\SharedEventManager
class Module {
public function init() {
$events = new SharedEventManager();
$events->attach('bootstrap', 'bootstrap', array($this, 'registerBasePath'));
}
public function registerBasePath($e) {
$modules = $e->getParam('modules');
$config = $modules->getMergedConfig();
$app = $e->getParam('application');
$request = $app->getRequest();
$request->setBasePath($config->base_path);
}
}
}
And in my modules/Application/configs/module.config.php I add:
'base_path' => '/spam/ham/'
But it desn't work. The problems are:
1) The run never comes to the registerBasePath function. But it has to. I've attached an event with the listener in the init function.
2) When I change SharedEventManager for just EventManager it happens to come to the registerBasePath function but an exeption is thrown:
Fatal error: Call to undefined method Zend\EventManager\EventManager::getParam()
What do I do wrong? Why the run of the program doesn't come to the registerBasePath function? If this is the only way to set the basePath globally then how to do it right?

I know the documentation is lacking of these kinds of things. But you are right in the way to approach this:
Be early (so at bootstrap)
Grab the request from the application
Set the base path in the request
The docs are lacking this information and the post you refer to is quite old. The fastest and easiest way to do this is using the onBootstrap() method:
namespace MyModule;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$app->getRequest()->setBasePath('/foo/bar');
}
}
If you want to grab the base path from your config, you can load the service manager there:
namespace MyModule;
class Module
{
public function onBootstrap($e)
{
$app = $e->getApplication();
$sm = $app->getServiceManager();
$config = $sm->get('config');
$path = $config->base_path;
$app->getRequest()->setBasePath($path);
}
}

Related

Nestjs, met some problems when using dependency injected class's method in interceptors, inject can't be resolved

I injected a provider(FileFilter) in my controller, and I want to use its filter method in Interceptors.
#Controller('file-uploader')
export class FileUploaderController {
constructor(private fileFilter: FileFilter) {}
#Post()
#UseInterceptors(
FileInterceptor('file', {
fileFilter: this.fileFilter.filter,
}))
uploadFile(#UploadedFile() file) {
return file;
}
}
here is FileFilter
#Injectable()
export class FileFilter {
filter(req: any, file: MulterFile, callback: any) {
if (!file.mimetype.match(ASSESSMENT_FILE_TYPE)) {
return callback(new HttpException(null, HttpStatus.BAD_REQUEST), false);
}
return callback(null, true);
}
}
when I use postman to request the API, the error message is like the following:
fileFilter: this.fileFilter.filter,
[0] ^
[0] TypeError: Cannot read property 'filter' of undefined
BUT inside the post method, the filter can be used which means the FileFilter is injected correctly, then who can explain why this doesn't work in an interceptor? or is this about the init order or something? Help, please.
Decorators have a different Lexical this which does not belong to the class, so this.fileFilter.filter is undefined as this does not have a property called fileFilter. I believe you would need to save the filter method as a function and not part of a class to use it like that

Problem in creating a service in a contair to inject a dependency into a class

I am trying to inject a dependency into a class in Slim framework. I created a service in a container to do it but I got this error.
PHP Catchable fatal error: Argument 2 passed to Api\Controllers\StudentWorkPriceController::__construct() must be an instance of Api\Models\StudentWorkPrice, none given, called in /studentwork/vendor/slim/slim/Slim/CallableResolver.php on line 93 and defined in /studentwork/src/api/Controllers/StudentWorkPriceController.php on line 29
My code is as below:
dependencies.php
$container = $app->getContainer();
$container['\Api\Controllers\StudentWorkPriceController']=function ($c){
$studentWorkPrice = new \Api\Models\StudentWorkPrice();
return new \Api\Controllers\StudentWorkPriceController($c,$studentWorkPrice);
};
index.php
use Api\Controllers\StudentWorkPriceController;
require __DIR__ . '/src/dependencies.php';
$app->get('/stuworkprice[/{params:.*}]',StudentWorkPriceController::class . ':select')->setName('StudentWorkPrice.select');
StudentWorkPriceController.php
use Api\Models\StudentWorkPrice as StudentWorkPrice;
class StudentWorkPriceController
{
// protected $logger;
// protected $pdo;
protected $stuWorkPrice;
/**
* StudentWorkPriceController constructor.
* #param ContainerInterface $container
*/
public function __construct(ContainerInterface $container, StudentWorkPrice $stuWorkPrice)
{
// $this->logger = $container->get('logger');
// $this->pdo = $container->get('pdo');
$this->stuWorkPrice = $stuWorkPrice;
}
public function select(){
}
}
It seems that the service I defined in container doesn't run! Could anybody please help me to figure out what's happening here!
Thanks a lot

ZF3 - EventManager and dispatch event

in an older ZF2 application I change the layout in a dispatch listener, if the matched route starts with admin. Now I started a new project and want to use ZF3 components, but the event manager does have some changes and I get the following exception:
Uncaught TypeError: Argument 2 passed to Zend\EventManager\EventManager::attach() must be callable, none given
I don't know really how to handle this in ZF3. Here are my relevant source codes to change the layout in my ZF2 application:
Module.php
namespace Admin;
use Zend\EventManager\EventInterface;
use Zend\ModuleManager\Feature\BootstrapListenerInterface;
class Module implements BootstrapListenerInterface {
public function onBootstrap(EventInterface $event) {
$application = $event->getApplication();
$eventManager = $application->getEventManager();
$serviceManager = $application->getServiceManager();
$eventManager->attach($serviceManager->get('Admin\Listener\Dispatch'));
}
}
DispatchListener.php
namespace Admin\Listener;
use Zend\EventManager\AbstractListenerAggregate;
use Zend\EventManager\EventInterface;
use Zend\EventManager\EventManagerInterface;
use Zend\Mvc\MvcEvent;
class DispatchListener extends AbstractListenerAggregate {
public function attach(EventManagerInterface $eventManager) {
$this->listeners[] = $eventManager->attach(
MvcEvent::EVENT_DISPATCH, array($this, 'onDispatch'), 100
);
}
public function onDispatch(EventInterface $event) {
$matchedRouteName = $event->getRouteMatch()->getMatchedRouteName();
if (strpos($matchedRouteName, 'admin') === 0) {
$event->getViewModel()->setTemplate('layout/admin');
}
}
}
zf3 is more focused on decoupling components, it seems aggregates has been removed to attach event see the api document
event manager
for short the attach message says
attach($eventName, callable $listener, $priority = 1) : callable
I hope since you are not specifying the eventName you are getting the error message
update:
see the link to migration guide from v2 to v3 for event manager
Removed functions
In ZF3 you can change your layout for your controller this easy way:
<?php
namespace YourCompanyModule;
use Zend\ModuleManager\ModuleManager;
use Zend\Mvc\MvcEvent;
class Module
{
// The "init" method is called on application start-up and
// allows to register an event listener.
public function init(ModuleManager $manager)
{
// Get event manager.
$eventManager = $manager->getEventManager();
$sharedEventManager = $eventManager->getSharedManager();
// Register the event listener method.
$sharedEventManager->attach(__NAMESPACE__, 'dispatch',
[$this, 'onDispatch'], 100);
}
// Event listener method.
public function onDispatch(MvcEvent $event)
{
// Get controller to which the HTTP request was dispatched.
$controller = $event->getTarget();
// Get fully qualified class name of the controller.
$controllerClass = get_class($controller);
// Get module name of the controller.
$moduleNamespace = substr($controllerClass, 0, strpos($controllerClass, '\\'));
// Switch layout only for controllers belonging to our module.
if ($moduleNamespace == __NAMESPACE__) {
$viewModel = $event->getViewModel();
$viewModel->setTemplate('layout/layout2');
}
}
// ...
}

Zend Framework 2 - How to give declare folder path in terms of "use" and "namespace"

I am facing problem while creating adapter object in controller file named Listcontroller.My code is
namespace Blog\Controller;
use Blog\Service\PostServiceInterface;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\Db\Sql\Sql;
use Zend\Db\Adapter\Adapter;
class ListController extends AbstractActionController
{
/**
* #var \Blog\Service\PostServiceInterface
*/
protected $postService;
public function __construct(PostServiceInterface $postService)
{
$this->postService = $postService;
}
public function indexAction()
{
$adapter = new Zend\Db\Adapter\Adapter($configArray);
print_r($adapter);
//code ....
}
}
here it is serching to find Zend\Db\Adapter\Adapter inside Blog\Controller.
Error is -> Fatal error: Class 'Blog\Controller\Zend\Db\Adapter\Adapter' not found. Can anybody tell me please how can i move two folder back from above path. so that i can get proper object??
You don't need the fully qualified class name (FQCN) when instantiating a new Adapter since you declare that class path via use statement:
use Zend\Db\Adapter\Adapter;
Change this block
public function indexAction()
{
$adapter = new Zend\Db\Adapter\Adapter($configArray);
print_r($adapter);
}
to
public function indexAction()
{
$adapter = new Adapter($configArray);
print_r($adapter);
}
It should work.
Anyway, new \Zend\Db\Adapter\Adapter($configArray) also works (notice the first backslash) but its longer, harder to type and less readable than first example.
You may also want to read namespace aliasing/importing section of the documentation.

how to add form validation from controller in zend framework 2

I tried to add a validation from my controller like below. but it always shows this
if ($request->getPost('ownerType') == "Company") {
$form->getInputFilter()->get('companyName')->getValidatorChain()->addValidator('required');
}
shows error. I confused with below error.
Catchable fatal error: Argument 1 passed to Zend\Validator\ValidatorChain::addValidator() must implement interface Zend\Validator\ValidatorInterface, string given, called in E:\xampp\htdocs\hossbrag\module\WebApp\src\WebApp\Controller\JobController.php on line 177 and defined in E:\xampp\htdocs\hossbrag\vendor\zendframework\zendframework\library\Zend\Validator\ValidatorChain.php on line 100
My controller is here
<?php
namespace WebApp\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use WebApp\Entity\User;
use Zend\View\Model\JsonModel;
use vendor\mpdf\mpdf;
class JobController extends AuthenticatedController
{
public function createAction()
{
$form = new \WebApp\Form\JobpostingForm();
$form->get('companyName')->setValueOptions($company);
$checkAgreement = true;
$request = $this->getRequest();
if ($request->getPost('ownerType') == "Company") {
$form->getInputFilter()->get('companyName')->getValidatorChain()->addValidator('required');
}
}
}
What should to change in my controller to get appropriate solution.
If you encounter such a clear error, simply check out the sources ;)
First one to check would be Zend\Validator\ValidatorInterface. The Error shows you, that a Class implementing this interface is excepted. Looking at the code you'll see, the function wants a Class, not just a string.
But since you're used to ZF a little it becomes clear that you know there's other ways to add stuff. So let's take a look at Zend\InputFilter\InputFilter#add(). You'll see that the first param of the add() function indeed asks for a class implementing ValidatorInterface. But it also accepts some other stuff:
/**
* Add an input to the input filter
*
* #param array|Traversable|InputInterface|InputFilterInterface $input
* #param null|string $name
* #return InputFilter
*/
public function add($input, $name = null)
{
//...
}
It also accepts array, Traversable, InputInterface and InputFilterInterface. So choices are there.
Now, i have never done this myself and i sincerely hope this works (if not i suck!), but assuming you're using the array-syntax, all you have to do is this:
[...]->getValidatorChain()->add(array(
'type' => 'Zend\Validator\NotEmpty'
));
Let me know if this worked out for you ;)

Resources