I would like to set a cookie in a listener, if the query parameter "source" is set. I tried the following but the cookie does not exist.
How can I set the cookie correct?
class DispatchListener extends AbstractListenerAggregate {
public function attach(EventManagerInterface $eventManager) {
$this->listeners[] = $eventManager->getSharedManager()->attach(
'Zend\Stdlib\DispatchableInterface',
MvcEvent::EVENT_DISPATCH,
array($this, 'setCookie'),
-80
);
}
/**
* #var \Zend\Stdlib\RequestInterface
*/
protected $request;
/**
* #param \Zend\Stdlib\RequestInterface $request
*/
public function __construct(RequestInterface $request) {
$this->request = $request;
}
public function setCookie(EventInterface $event) {
if ($source = $this->request->getQuery('source')) {
$this->request->setCookies([
'source' => $source
]);
}
}
}
--------------------------------- UPDATE -----------------------------------
class Module implements ConfigProviderInterface, BootstrapListenerInterface {
public function onBootstrap(EventInterface $event) {
$target = $event->getTarget();
$serviceManager = $target->getServiceManager();
$eventManager = $target->getEventManager();
$eventManager->attach($serviceManager->get('Application\Listener\Dispatch'));
}
}
Seems like there are a few issues with your code, which we can rule out first.
You haven't provided code for how you are attaching your listener
Not sure why you are setting the cookie on the request, do you want to do this on the response?
Attaching the event listener:
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$app = $e->getApplication();
$em = $app->getEventManager();
// Attach event to attach listener after routing when query will be populated
$em->attach(MvcEvent::EVENT_ROUTE, function($e) use ($eventManager) {
$request = $e->getRequest();
// attach our listener
$eventManager->attach(new DispatchListener($request));
});
}
Updated setCookie method:
public function setCookie(EventInterface $event) {
if ($source = $this->request->getQuery('source')) {
$this->request->setCookies([
'source' => $source
]);
$request = $this->request;
$cookieData = $request->getCookie('someCookie', 'default');
var_dump($cookieData);
}
}
The var_dump prints the following:
object(Zend\Http\Header\Cookie)[274]
protected 'encodeValue' => boolean true
private 'storage' (ArrayObject) =>
array (size=1)
'source' => string 'test' (length=4)
Do you want a cookie in your request object or do you want to create a cookie for the response. You probably want to create a cookie and set it on the response object.
Check for example this answer.
public function setCookie(EventInterface $event) {
if ($source = $this->request->getQuery('source')) {
$cookie = new \Zend\Http\Header\SetCookie('source', $source);
$headers = $this->getResponse()->getHeaders();
$headers->addHeader($cookie);
}
}
Related
last couple of days I've been busy making a form using Doctrine and MongoDB. Companies should be able to reserve tables, chairs, .. at a certain event by use of this form. The snippet below shows the controller for this form.
The 'ObjectMap' object maps the amount of a certain object to the object itself. The controller creates all the 'ObjectMap' objects, and adds them to the company object. However, the 'ObjectMap' objects are persisted by Doctrine (they show up in the database) but the company object isn't modified at all, there is no database request made by MongoDB. The persist() function seems to have no effect at all.
public function logisticsAction(Company $company)
{
$form = $this->createForm(new LogisticsForm($this->getDoctrine()->getManager()), $company);
if ($this->getRequest()->isMethod('POST')) {
$form->bind($this->getRequest());
if ($form->isValid()) {
$formData = $this->getRequest()->request->get('_company_logistics_edit');
$objects = $this->getDoctrine()->getManager()
->getRepository('Jobfair\AppBundle\Document\Company\Logistics\Object')
->findAll();
foreach($objects as $object) {
$requirement = $formData['objectRequirement_'.$object->getId()];
$map = new ObjectMap($requirement, $object);
$this->getDoctrine()->getManager()->persist($map);
$company->addObjectMap($map);
//print_r($company->getObjectMaps());
}
$this->getDoctrine()->getManager()->persist($company);
$this->getDoctrine()->getManager()->flush();
$this->getRequest()->getSession()->getFlashBag()->add(
'success',
'The information was successfully updated!'
);
return $this->redirect(
$this->generateUrl(
'_company_settings_logistics',
array(
'company' => $company->getId(),
)
)
);
}
}
The Company object is defined here:
class Company{
/**
* #ODM\Id
*/
private $id;
/*
* #ODM\ReferenceMany(targetDocument="Jobfair\AppBundle\Document\Company\Logistics\ObjectMap", cascade={"persist", "remove"})
*/
private $objectMaps;
public function __construct($name = null, $description = null)
{
$this->objectMaps = new ArrayCollection();
}
public function getId()
{
return $this->id;
}
public function getObjectMaps()
{
return $this->objectMaps;
}
public function getObjectsArray()
{
$objects = array();
foreach($this->objectMaps as $map)
$objects[] = array(
'name' => $map->getObject()->getName(),
'amount' => $map->getRequirement()
);
return $objects;
}
public function addObjectMap(ObjectMapDocument $objectMap)
{
$this->objectMaps[] = $objectMap;
}
public function removeObject(ObjectMapDocument $objectMap)
{
$this->objectMaps->removeElement($objectMap);
}
}
I have a class social which has:
protected $id;
public function __construct($request, $id)
{
Log::info('Processing...', ['request' => $request, 'id' => $id]);
try {
$client = new Client();
$url = sprintf($request);
$response = $client->get($url);
$json = json_decode((string) $response->getBody(), true);
return $json;
} catch (ClientException $exception) {
$responseBody = $exception->getResponse()->getBody(true);
Log::error($responseBody, ['entity_id' => $id]);
}
}
public function wikipedia($wikipedia_url, $id)
{
dd($json);
try {
$wikipedia_array = $json['parse']['text'];
$wikipedia_array = array_slice($wikipedia_array, 0, 9);
$wikipedia_array = implode($wikipedia_array, ',');
Log::info('Processed Wikipedia for', ['entity_id' => $id]);
return $wikipedia_array;
} catch (Exception $e) {
Log::error('Wikipedia:', ['message' => $e->getMessage(), 'entity_id' => $id]);
}
}
In another function I am calling a facade like this:
$id = $entity->id;
$wikipedia_id = $entity->wikipedia;
if (!empty($wikipedia_id)) {
$wikipedia_url = 'http://en.wikipedia.org/w/api.php?action=parse&prop=text§ion=0&disablelimitreport=1&format=json&page='.$wikipedia_id;
$wikipedia_html = Social::wikipedia($wikipedia_url, $id);
Log::info('Wikipedia ok for', ['entity_id' => $id]);
}
However I get this:
Type error: Too few arguments to function App\Helpers\Social::__construct(), 0 passed in /home/vagrant/liveandnow/app/Providers/SocialServiceProvider.php on line 35 and exactly 2 expected
Can anyone explain to me how to call a method, pass parameters to it but also pass them along to construct?
Here's my facade:
<?php
namespace App\Facade;
use Illuminate\Support\Facades\Facade;
class Social extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'social';
}
}
and service provider:
public function register()
{
$this->app->bind('social', function ($app) {
return new Social;
});
}
the error lies in the service provider.
You define a constructor with 2 parameters,
public function __construct($request, $id)
but in your service provider you call it like this:
public function register()
{
$this->app->bind('social', function ($app) {
return new Social;
});
}
You need to add both arguments when instantiating the Social class, for example like
return new Social("http://xyz.de", 1);
Hope this helps.
Is there any way I can send multiple requests with guzzle using a middleware and according to certain parameters?
To be more specific I need:
class MyMiddleware
{
/**
* #param callable $handler
* #return \Closure
*/
public function __invoke(callable $handler)
{
return function (RequestInterface $request, array $options) use ($handler) {
if(!isset($options['token']){
//request the token from a url
}
//after the token is aquired proceed with the original request
return $handler($request, $options);
};
}
}
Is this similar to what you are inquiring about? I have done similar to it.
$handler = GuzzleHttp\HandlerStack::create();
$client = new GuzzleHttp\Client([
'handler' = $handler,
// other options
])
$handler->push(GuzzleHttp\Middleware::mapRequest(
function (Psr\Http\Message\RequestInterface $request) use ($client) {
if ('POST' !== $request->getMethod()) {
return $request;
}
if($RequestIsOkAsIs) {
return $request;
}
$response = $client->get($someUrl, $requestOptions);
// Play with the response to modify the body
$newBody = 'results of stuff';
return new GuzzleHttp\Psr7\Request(
$request->getMethod(),
$request->getUri(),
$request->getHeaders(),
$newBody,
$request->getProtocolVersion()
);
}
);
I'm trying to profile the requests made to an API server from a PHP client using Guzzle (v 6).
In the Guzzle 5.3 there is this complete and before event handling.
class GuzzleProfiler implements SubscriberInterface
{
public function getEvents()
{
return [
'before' => ['onBefore'],
'complete' => ['onComplete']
];
}
public function onBefore(BeforeEvent $event, $name)
{
start_profiling();
}
public function onComplete(CompleteEvent $event, $name)
{
end_profiling();
}
}
But how do I do this in v6?
Just found it using Middleware. Here's the code.
class Profiler {
/**
* #return callable
*/
public static function profile() {
return function(callable $handler) {
return function(\Psr\Http\Message\RequestInterface $request, array $options) use ($handler) {
start_profiling();
return $handler($request, $options)->then(function(\Psr\Http\Message\ResponseInterface $response) use ($token) {
end_profiling();
return $response;
});
};
};
}
}
And then attach the profiler like this.
$stack = \GuzzleHttp\HandlerStack::create();
$stack->push(Profiler::profile());
$client = new \GuzzleHttp\Client([
'handler' => $stack
]);
Hi can someone help me to prevent bjyauthorize to catch my api event error raised?
bjyauthorize redirect non logged user to login form as added to config. But since my api are allowed for all roles even for guest i just want it to return Json error message catched by ApiProblemListener
ApplicationRest\Module.php
class Module implements
ConfigProviderInterface,
AutoloaderProviderInterface
{
public function onBootstrap(MvcEvent $e)
{
$app = $e->getApplication();
$sm = $app->getServiceManager();
$events = $app->getEventManager();
$listener = $sm->get('ApplicationRest\ApiAuthenticationListener');
$events->getSharedManager()->attach('ApplicationRest\Controller', 'dispatch', $listener, 500);
$events->attach('render', array($this, 'onRender'), 100);
$events->attach($sm->get('ApplicationRest\ApiProblemListener'));
}
/**
* Listener for the render event
* Attaches a rendering/response strategy to the View.
*
* #param \Zend\Mvc\MvcEvent $e
*/
public function onRender($e)
{
$result = $e->getResult();
if (!$result instanceof RestfulJsonModel) {
return;
}
//var_dump(123);exit();
$app = $e->getTarget();
$services = $app->getServiceManager();
$view = $services->get('View');
$restfulJsonStrategy = $services->get('ApplicationRest\RestfulJsonStrategy');
$events = $view->getEventManager();
// register at high priority, to "beat" normal json strategy registered
// via view manager
$events->attach($restfulJsonStrategy, 500);
}
}
Have many modules and i am really thinking to move away my apiModule "ApplicationRest" to another project but don't really want to update model and service each time i make some updates on main project.
Any suggestions would welcome!
Thanks for your time!
EDIT: Provided more HeaderAuthentication class
class HeaderAuthentication implements AdapterInterface
{
const AUTHORIZATION_HEADER = 'Authorization';
const CRYPTO = 'sha256';
protected $request;
protected $repository;
public function __construct(RequestInterface $request, UserRepository $repository)
{
$this->request = $request;
$this->repository = $repository;
}
/**
* Authorization: Key={key} Timestamp={timestamp} Signature={signature}
* #return Result
*/
public function authenticate()
{
$request = $this->getRequest();
if (!$request instanceof Request) {
return;
}
$headers = $request->getHeaders();
// Check Authorization header presence
if (!$headers->has(static::AUTHORIZATION_HEADER)) {
return new Result(Result::FAILURE, null, array(
'Authorization header missing'
));
}
$authorization = $headers->get(static::AUTHORIZATION_HEADER)->getFieldValue();
// Validate public key
$publicKey = $this->extractPublicKey($authorization);
$user = $this->getUserRepository()
->findOneByApiSecret($publicKey);
if (null === $user) {
$code = Result::FAILURE_IDENTITY_NOT_FOUND;
return new Result($code, null, array(
'User not found based on public key'
));
}
// Validate signature
$signature = $this->extractSignature($authorization);
/*$hmac = $this->getHmac($request, $user);
if ($signature !== $hmac) {
$code = Result::FAILURE_CREDENTIAL_INVALID;
return new Result($code, null, array(
'Signature does not match'
));
}*/
return new Result(Result::SUCCESS, $user);
}
}
ApiAuthenticationListener
class ApiAuthenticationListener
{
protected $adapter;
public function __construct(HeaderAuthentication $adapter)
{
$this->adapter = $adapter;
}
public function __invoke(MvcEvent $event)
{
$result = $this->adapter->authenticate();
if (!$result->isValid()) {
$response = $event->getResponse();
// Set some response content
$response->setStatusCode(401);
return $response;
}
// All is OK
$event->setParam('user', $result->getIdentity());
}
}
I'm guessing you configured guards on your route. You need to tell BJYAuthorize, through your module config, that this controller or route shouldn't be protected.
'bjyauthorize' => [
'default_role' => 'guest',
...
'guards' => [
'BjyAuthorize\Guard\Controller' => [
// system tools
['controller' => 'Application\Controller\Api', 'roles' => [] ],
['controller' => 'error', 'roles' => []],
],
],
],
I cut out the nitty gritty that's app specific, but this type of thing is quickly solved. I had a similar need for CLI routes to be unprotected by what is otherwise, http auth.