Where is the http.get() function in Angular2 defined? - http

I'm new to Typescript and Angular 2.
I wanted to look at the exact implementation of http.get(), so I opened the file in ./node_modules/angular2/src/http/http.d.ts and scrolled to the get function. This is what I found:
/**
* Performs a request with `get` http method.
*/
get(url: string, options?: RequestOptionsArgs): Observable<Response>;
/**
* Performs a request with `post` http method.
*/
post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response>;
/**
....
Basically, there is no function definition. It seems like an abstract method (in Java lingo). I looked through the other http files, used VSCode intellisense, and couldn't find the code for the body of the function.
Where is it and how can I find it?

It is defined here: https://github.com/angular/angular/blob/master/modules/angular2/src/http/http.ts
What you are seeing is the TypeScript typings file. It contains the definitions, but not the implementation.

Related

App\\Entity\\Project object not found by the #ParamConverter annotation

Bit of an obscure one this. I'm reading that Symfony get's muddled when dealing with more than one route of a similar pattern. Here goes, this is what I've tried thus far:-
For starters, I hit the endpoint: https://127.0.0.1:8000/api/contracts/12345/new which returns the 404 error in full:-
{type: "https://tools.ietf.org/html/rfc2616#section-10", title: "An error occurred", status: 404,…}
class
:
"Symfony\\Component\\HttpKernel\\Exception\\NotFoundHttpException"
detail
:
"App\\Entity\\Project object not found by the #ParamConverter annotation."
status
:
404
title
:
"An error occurred"
trace
:
[{namespace: "", short_class: "", class: "", type: "", function: "",…},…]
type
:
"https://tools.ietf.org/html/rfc2616#section-10"
Here's a snapshot of my URL patterns:-
docker-compose exec app bin/console debug:router
new_contract POST ANY ANY /api/contracts/{id}/new
api_edit_project POST ANY ANY /api/contracts/{id}/edit
They're very similar but I'm using the new endpoint from above. Here's the controller:-
/**
* #Route("/api")
*/
class ContractController extends BaseApiController
{
/**
* #Post ("/contracts/{id}/new", name="new_contract")
*/
public function postNewContractAction(){
// -- we don't hit this method at all
}
/**
* #Post ("/contracts/{id}/edit", name="api_edit_project")
*/
public function postEditContractAction(){}
}
Further to this, I've tried moving the controller methods around in terms of ordering, but this has no effect.
Any ideas?
As statet in the Symfony Documentation, receiving a 404 Error, when trying to fetch an object by it's id automatically using the paramConverter magic, this usually means there is no data for that id.
If no Post object is found, a 404 Response is generated;
I suspect there is no Project with id=12345.
Why are you asking for an {id} in the /new route, actually? To my understanding you would not have an ID in that case, yet.
I always try to set the parameters at last position in routes, as it may avoid route collisions.

Symfony Tactician-bundle Typehints = Missing handler method error

I've used the thephpleague/tactician-bundle with Symfony before, but this is the first time I've used it with Symfony 4.* (specifically 4.1.4) and attempted to use a single handler Class for my Application Service.
When I execute a command in the Controller
public function postAction(Request $request, CommandBus $commandBus)
{
$form = $this->createForm(VenueType::class);
$form->submit($request->request->all(), true);
$data = $form->getData();
if($form->isValid()) {
$command = new CreateVenueCommand($data);
$commandBus->handle($command);
return $form->getData();
}
return $form;
}
... I get the following error:
"error": {
"code": 500,
"message": "Internal Server Error",
"exception": [
{
"message": "Could not invoke handler for command App\\Application\\Command\\CreateVenueCommand for reason: Method 'handle' does not exist on handler",
"class": "League\\Tactician\\Exception\\CanNotInvokeHandlerException",
"trace": [
I've seemingly followed the installation documents for the tactician-bundle and installed it using Flex. As far as I can tell everything is configured correctly, so I'm unsure what I'm missing in my implementation.
Implementation
As per the thephpleague/tactician-bundle installation guide I've installed using Flex and the bundle is registered and the config package installed:
tactician:
commandbus:
default:
middleware:
- tactician.middleware.locking
- tactician.middleware.doctrine
- tactician.middleware.command_handler
After creating the DTO Command Class 'CreateVenueCommand', I created the handler Class:
use App\Infrastructure\Domain\Model\VenueRepositoryInterface;
use App\Application\Command\CreateVenueCommand;
use App\Domain\Entity\Venue;
class VenueApplicationService
{
private $venueRepository;
public function __construct(VenueRepositoryInterface $venueRepository)
{
$this->venueRepository = $venueRepository;
}
/**
* #param CreateVenueCommand $aCommand
* #throws \Exception
*/
public function createVenue(CreateVenueCommand $aCommand)
{
$aVenue = new Venue($aCommand->getData())
if ($aVenue === null) {
throw new \LogicException('Venue not created');
}
$this->venueRepository->add($aVenue);
}
Then I registered the handler Class as a Service taking advantage of Symfony's autowiring and Tacticians typehints:
App\Application\VenueApplicationService:
arguments:
- '#App\Infrastructure\Persistence\Doctrine\DoctrineVenueRepository'
tags:
- { name: tactician.handler, typehints: true }
So according to the installation documents, typehints work if:
The method must be public.
The method must accept only one parameter.
The parameter must be typehinted with a class name.
Also, and this is specific to my use case:
If you have multiple commands going into a single handler, they will all be detected, provided they follow the rules above. The actual name of the method is NOT important.
So when I invoke the commandbus in the Controller Class, I'm unsure why I'm getting the error above.
If I change the Command Handler method to:
public function handle(CreateVenueCommand $aCommand)
{
... then it works fine. This would seem to suggest that the typehints aren't working as documented.
It seems in this case that the actual name of the method IS important. ... or I've made some form of error in my implementation ... or I'm misunderstanding the multiple commands going into a single handler use case??
Any assistance would be greatly appreciated.
Solution
With a big thanks to kunicmarko20 for pointing me in the right direction.
Specifically for my use case I simply needed to use one of Tacticians MethodNameInflector classes, configured in Symfony thus:
tactician:
commandbus:
default:
middleware:
- tactician.middleware.locking
- tactician.middleware.doctrine
- tactician.middleware.command_handler
method_inflector: tactician.handler.method_name_inflector.handle_class_name
... then it was simply a matter of naming each Handler method in my Application Service class 'handle{whateverYouLike}Command
Here under 1. is explained how the naming works, if you want to use a different name than in this table you can implement MethodNameInflector Interface and provide a name of the method.

Call a method on a service created dynamically by a bundle

I am using the m6web_guzzle bundle to register several http clients:
m6web_guzzlehttp:
clients:
myclient:
timeout: 3
headers:
"Accept": "application/json"
delay: 0
verify: false
I want to call a method on a service that it dynamically generates. In this case the generated service name is:
#m6web_guzzlehttp.guzzle.handlerstack.myclient
Here is what I do in my service constructor: (the 3rd parameter injected is '#m6web_guzzlehttp.guzzle.handlerstack.myclient')
/**
* #param array $parameters
* #param Client $client
* #param HandlerStack $handlerStack
*/
public function __construct(array $parameters, Client $client, HandlerStack $handlerStack)
{
$this->parameters = $parameters;
$this->client = $client;
$this->handlerStack->push(Middleware::retry([$this, 'retryDecider']));
}
So far, it works well, but how can I transfer the last line (the push call) in my services.yml file? Or another cleaner method to register this retry handler?
So compiler passes were mentioned before. That is one option.
Use factories to create instances
But you can nearly express this also directly in your services definition. I say nearly, because you will need some kind of code as Symfony service definitions cannot (AFAIK) evaluate to a Closure - which is what we need for the Guzzle Middleware.
I wrote up this services.yml as an example:
m6web_guzzlehttp.guzzle.handlerstack.myclient:
class: GuzzleHttp\HandlerStack
factory: ['GuzzleHttp\HandlerStack', create]
retry_decider:
class: MyBundle\RetryDecider
factory: ['MyBundle\RetryDecider', createInstance]
retry_handler:
class: GuzzleHttp\Middleware
factory: ['GuzzleHttp\Middleware', retry]
arguments:
- '#retry_decider'
handlerstack_pushed:
parent: m6web_guzzlehttp.guzzle.handlerstack.myclient
calls:
- [push, ['#retry_handler']]
What is what?
m6web_guzzlehttp.guzzle.handlerstack.myclient - Your dynamic service - remove from example as you have this already created.
retry_decider - Your decider. We return a Closure in the createInstance method. You can add more parameters if you need, just add arguments to your YML.
retry_handler - Here we compose the middleware using our decider
handlerstack_pushed - Here we push() our handler into the stack, using the dynamic service as a parent service.
Et voilà - we have the stack that the dynamic service defined, but pushed our retry middleware.
Here is the source for our decider:
<?php
namespace MyBundle;
class RetryDecider {
public static function createInstance() {
return function() {
// do your deciding here
};
}
}
--> You now have the service handlerstack_pushed which is the complete Stack.
Configuring more
Please note that you could add m6web_guzzlehttp.guzzle.handlerstack.myclient to parameters.yml:
parameters:
baseHandlerStackService: m6web_guzzlehttp.guzzle.handlerstack.myclient
Then use that on handlerstack_pushed:
handlerstack_pushed:
parent: "%baseHandlerStackService%"
calls:
- [push, ['#retry_handler']]
Just nicer like that ;-)
In your bundle's Extension.php file, you can override the load method and add:
$definition = $container->getDefinition('m6web_guzzlehttp.guzzle.handlerstack.myclient');
$definition->addMethodCall('push', [Middleware::retry([$this, 'retryDecider'])]);
You can write a compiler pass that grabs the definition in question and adds the method call to it.

Export type declaration outside of the function

I'm trying to use google closure compiler (I'll call it compiler for short) to validate JavaScript codebase like that:
java -jar compiler.jar --js='**.js' --jscomp_error newCheckTypes > NUL 2> gcc.log
The thing is we already have a lot of code in AMD and type annotations written for core modules like that:
define(function () {
/** #constructor */
MyClass () {}
/** #param {string} s */
MyClass.prototype.myMethod = function (s) {
alert(s);
}
return MyClass;
});
I'd like to reference the type /** #type {MyClass} */ in other modules, so if I call some method with wrong arguments, it will complaint.
Unfortunately, when I use such type annotations, compiler outputs:
Bad type annotation. Unknown type MyClass
/** #type {MyClass} */
If I strip out module-delcaring function, compiler "understands" my declaration, but I don't feel like rewriting our code in that way.
Is there a way to make compiler see my type declarations and apply in other modules?
The compiler has a --transform_amd_modules which will rewrite an AMD module to CommonJS. It only supports a limited number of define signatures and is not widely used or actively maintained.
With CommonJS modules, you can use the --process_common_js_modules flag to rewrite and rescope the code to a global type which can be checked by the compiler. The CommonJS modules functionality is actively maintained.

Override a symfony service tag with a compiler pass

I'm trying to override a tag in a symfony service definition with a compiler pass. The service as an example would be data_collector.translation.
The goal is to deactivate the data collector service to disable the element in the symfony web developer toolbar. To do this, I have to set the priority of the data_collector tag to 0.
I could also override it in my own service definition:
services:
data_collector.translation:
class: 'Symfony\Component\Translation\DataCollector\TranslationDataCollector'
tags:
- {name: 'data_collector', priority: '0'}
arguments: [#translator.data_collector]
But as I want to do this for a few of the data collectors, I would need to know the mandatory arguments for the data collector definition. The priority works the same for all collectors and therefore I would only need the name of the collector to disable it.
So I wrote the following compiler pass:
class DataCollectorCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->hasDefinition('data_collector.translation')) {
return;
}
$definition = $container->getDefinition('data_collector.translation');
$tags = $definition->getTags();
$tags['data_collector'][0]['priority'] = 0;
$definition->setTags($tags);
$container->setDefinition('data_collector.translation', $definition);
}
}
To make things more wired: When I run this command:
$ php app/console container:debug --show-private --tag='data_collector'
I get the following output:
data_collector.translation #WebProfiler/Collector/translation.html.twig translation 0 Symfony\Component\Translation\DataCollector\TranslationDataCollector
So the priority even in the debugger is set to 0.
But for which reason ever the element is still shown in the toolbar.
What did I do wrong here? Is there another mechanism for overwriting a tag within a compiler pass?
The compiler pass does run (tested it with printing out stuff)
I'm using Symfony 2.7.1
Turns out the code does work, the only problem is, that the CompilerPass is run after the ProfilerPass which is part of the FrameworkBundle. Putting my bundle with the CompilerPass before the FrameworkBundle in the AppKernel solves the problem (more information here). For not even initiating the data collectors it's better to remove all tags instead of just setting the priority to 0.
That's what the final solution looks like:
class DataCollectorCompilerPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$collectorsToRemove = [
'data_collector.form',
'data_collector.translation',
'data_collector.logger',
'data_collector.ajax',
'data_collector.twig'
];
foreach($collectorsToRemove as $dataCollector) {
if (!$container->hasDefinition($dataCollector)) {
continue;
}
$definition = $container->getDefinition($dataCollector);
$definition->clearTags();
}
}
}
Can you try this?
if (!$container->hasDefinition('data_collector.form')) {
return;
}
$definition = $container->getDefinition('data_collector.form');
$definition->clearTags();
$container->setDefinition('data_collector.form', $definition);
Why not use your compiler pass to manipulate directly the service Definition of the service holding all these collectors ?
If I look at the compiler pass responsible for loading the data collector, it seems that they are all injected using a method call injection.
You could use your compiler pass to rewrite the method call array using methods like setMethodCalls, removeMethodCall, ... of the Definition entity.
The method call manipulation documentation : link

Resources