zendframework 3 - identity view helper error - zend-framework3

I try to use identity view helper in my layout.phtml
$this->identity();
but get this error:
No AuthenticationServiceInterface instance provided in vendor\zendframework\zend-view\src\Helper\Identity.php on line 38

Did you actually setup Zend-Authentication and registered it within your services of the ServiceManager?
Because the factory for the IdentityHelper will set the AuthenticationService.
See: https://github.com/zendframework/zend-mvc-plugin-identity/blob/1.1.0/src/IdentityFactory.php#L27-L31
if ($container->has(AuthenticationService::class)) {
$plugin->setAuthenticationService($container->get(AuthenticationService::class));
} elseif ($container->has(AuthenticationServiceInterface::class)) {
$plugin->setAuthenticationService($container->get(AuthenticationServiceInterface::class));
}
Register the AuthenticationService within your Applications module.config.php:
'service_manager' => [
'factories' => [
\Zend\Authentication\AuthenticationService::class => \Application\Service\Factory\AuthenticationServiceFactory::class,
]
],
Create a factory for your AuthenticationService where you tell the service which adapter to use on how to check if the identity is valid. See https://docs.zendframework.com/zend-authentication/intro/#usage

Related

Tools for non regression testing on REST API?

I have developed a project with a symfony server as backend and a mobile application as frontend.
I am unemployed but I hope to start my own business :)
What tool(s) should I use for non regression testing ?
Thank you for your help!
I suppose you don't use API Platform. It provides the ApiTestCase that provides several assertions to test JSON responses :
class BooksTest extends ApiTestCase
{
// This trait provided by AliceBundle will take care of refreshing the database content to a known state before each test
use RefreshDatabaseTrait;
public function testGetCollection(): void
{
// The client implements Symfony HttpClient's `HttpClientInterface`, and the response `ResponseInterface`
$response = static::createClient()->request('GET', '/books');
$this->assertResponseIsSuccessful();
// Asserts that the returned content type is JSON-LD (the default)
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
// Asserts that the returned JSON is a superset of this one
$this->assertJsonContains([
'#context' => '/contexts/Book',
'#id' => '/books',
'#type' => 'hydra:Collection',
'hydra:totalItems' => 100,
'hydra:view' => [
'#id' => '/books?page=1',
'#type' => 'hydra:PartialCollectionView',
'hydra:first' => '/books?page=1',
'hydra:last' => '/books?page=4',
'hydra:next' => '/books?page=2',
],
]);
As you can see, in this example, the /books endpoint of the API is tested. But you can also use the standard WebTestCase provided by Symfony to do this manually.

How to create api with resource not based on entity API Platform?

I need to create a GET endpoint to return a resource which is fetched from another application via http client, not based on entity. The resource I fetched is an array:
[
"id" => 1234
"first_name" => ""
"last_name" => ""
"email" => ""
"country" => 1
"country_code" => 93
"phone_number" => "3434343"
"nationality" => "AF"
"professional_industry" => "Health Care"
"job_title" => "Medical Doctor - General Practitioner"
"specialisation" => "No specialisation"
"career_length_month" => 1
"career_length_year" => 1
]
Then I need to query database to fetch some data to add to the resource array.
So I created it in src/Controller/MyController.php:
/**
* #Route("/api/v1/get-profile", name="get_profile")
* #return JsonResponse
*/
public function getMemberInfo(): JsonResponse
{
// step 1 : use http client to request data from another application
// step 2 : query DB to fetch some data and add to data array
return new JsonResponse($data, Response::HTTP_OK);
}
But now, I would like my api return json api response format : https://jsonapi.org/.
With resource based on entity, it is supported completely by api-platform. I don't need to do much. I just adding "key" #[ApiResource] in entity class and config some things. Then I have a api with json api format, so easily:
{
"data": {
"id": "",
"type": "",
"attributes": {}
}
}
But how about with resource not based on Entity? Is there any built-in feature of api-platform I could use, or I have to do a transformer by myself ?
You need override the OpenAPI specification how described in documentation:
https://api-platform.com/docs/core/openapi/#overriding-the-openapi-specification
Then, in the new class, you must add the schema definition that you require, adding new PathItem instances, each PathItem require new Operation instances, etc.
Sorry for not paste examples, it require so many code. I'm working this way in a project, but it's not public for now.
I hope I put you in the way.
The good practice is to can create a custom data provider. This custom data provider will be responsible to fetch data from the external source. Then, API-Platform will be able to use it like a regular entity.
Documentation
Full example in the API-Platform demo

OroPlatform: add custom field on core Entity

I'm currently working on an OroPlatform project and I need to add a custom field on the BusinessUnit core entity.
I have read the Oro documentation section about the way to extend core entities : https://doc.oroinc.com/backend/entities/extend-entities/#id1
<?php
namespace MyBundle\Bundle\AppBundle\Migrations\Schema\v1_0;
use Doctrine\DBAL\Schema\Schema;
use Oro\Bundle\EntityExtendBundle\EntityConfig\ExtendScope;
use Oro\Bundle\MigrationBundle\Migration\Migration;
use Oro\Bundle\MigrationBundle\Migration\QueryBag;
class AddColumnsToBusinessUnit implements Migration
{
public function up(Schema $schema, QueryBag $queries)
{
$table = $schema->getTable('oro_business_unit');
$table->addColumn('siret', 'string', [
'oro_options' => [
'extend' => ['owner' => ExtendScope::OWNER_CUSTOM],
'entity' => ['label' => 'siret'],
],
]);
}
}
When I run the command symfony console oro:migration:load --force, it works and the migration is applied to my database.
Now, I want a required field. I have seen the instruction 'notnull' => true to setup a non nullable field on the database.
Everything works well, but my field hasn't any JavaScript validation on the organization/business_unit/create route. Any ideas ?
You can validate the new field by extending the validation metadata that is already defined for the core entity you are extending.
To do this, please follow the official Symfony documentation and use the YML format:
https://symfony.com/doc/4.4/validation.html#constraint-configuration
The constraint that you can use for the field is "not blank."
Here is an example:
# src/<YourBundlePath>/Resources/config/validation.yml
Oro\Bundle\OrganizationBundle\Entity\BusinessUnit:
properties:
siret:
- NotBlank: ~

JWT key for mercure

I try generate JWT key for Mercure settings
I use this manual
https://medium.com/#stefan.poeltl/instant-realtime-notifications-with-symfony-and-mercure-e45270f7c8a5
for pass myJWTKey JWT is
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InN1YnNjcmliZSI6W10sInB1Ymxpc2giOlsiKiJdfX0.iTVjHoLv9bB-O5RNnTtzOFxIW-YECk2JXZeMekZ4GwA
I found a token builder ( Signed JSON Web Token )
http://jwtbuilder.jamiekurtz.com/
but I find no setting that generates a correct JWT. How do I do it? What I miss?
I tried generate token for env settings
MERCURE_PUBLISH_URL=http://mercure.dev:3000/.well-known/mercure
# The default token is signed with the secret key: !ChangeMe!
MERCURE_JWT_TOKEN=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXJjdXJlIjp7InN1YnNjcmliZSI6W10sInB1Ymxpc2giOlsiKiJdfX0.iTVjHoLv9bB-O5RNnTtzOFxIW-YECk2JXZeMekZ4GwA
###< symfony/mercure-bundle ###
This token is for default password in docker-compose
mercure:
image: dunglas/mercure
environment:
# You should definitely change all these values in production
- JWT_KEY=myJWTKey
- DEMO=1
- ALLOW_ANONYMOUS=1
- HEARTBEAT_INTERVAL=30s
- ADDR=:3000
if I change myJWTKey to mysecure pass - how I can generate token?
Just an addition to a great answer by #Daidon. Mercure bundle uses lcobucci/jwt and registers it's factory as a service.
If you want to generate JWT do the following
Pass the factory as an argument with #mercure.hub.default.jwt.factory (here default is for your hub name)
In your service/controller
public function generateJwt(LcobucciFactory $factory): string
{
return $factory->create(['*']);
}
UPD: even easier way to get a JWT token
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Mercure\Authorization;
public function generateJwt(Request $request, Authorization $authorization): string
{
return $authorization->createCookie($request, ['*'])->getValue();
}
You can use different libraries for doing that, a very simple and fast one would be php-jwt
Then do
composer require firebase/php-jwt
And in the code you can do then:
use \Firebase\JWT\JWT;
$key = "12345678";
$payload = [
'mercure' => [
'publish' => ['*'],
],
];
$jwt = JWT::encode($payload, $key); // holds valid jwt now
The library will automatically inject the headers that you need (default: alg HS256, typ: jwt) and set the payload for you. Then it encodes it to base64 and signs it also.
Go on and set a cookie with this jwt or use it in authorization header now :-)
If you want to use the JWT for subscriber authentication, don't forget to put the subscribe key in the payload.
$payload = [
'mercure' => [
'subscribe' => ['*'], // make this a list of concrete topics, don't use *
],
];
Also for that usecase, you can carry around some data in the cookie, by providing a payload key with an object:
$payload = [
'mercure' => [
'subscribe' => ['*'],
'payload' => [
'userId' => $user->getId()
]
],
];
Apologize for late answer, you can simply generate new jwt token once using the official page https://jwt.io/.

How to get translator inside controller plugin on ZF3

I want to create a plugin to use zend-i18n/translate on controller. On zf2 I have a controller plugin that does this for me, but on zf3 I could not get this to work. How can I use zend-i18n inside a controller or via controller plugin with zf3?
==========
I just found what I need here on zf doc: https://docs.zendframework.com/zend-mvc-i18n/services/#mvctranslator-and-translatorfactory
if you already have config the translator as factory on your module.config.php, you can inject on your controller plugin.
You can virtually do the same as the answer that #hkulekci referred to in his comment.
'service_manager' => [
'factories' => [
\Zend\I18n\Translator\TranslatorInterface::class => \Zend\I18n\Translator\TranslatorServiceFactory::class,
]
]
and
'controller_plugins' => [
'invokables' => [
'translate' => \Zend\I18n\View\Helper\Translate::class
]
]
After that you can get the translate plugin like in your controller action methods like this:
public someAction(){
$translator = $this->translate;
}
Check the Zend Framework documentation or this Zend Framework blog for more details on the controller plugin manager.
For translate in model and controller, I did this in my module.config.php
'service_manager' => [
'factories' => [
\Zend\I18n\Translator\Translator::class => \Zend\I18n\Translator\TranslatorServiceFactory::class,
],
],
Then from my controller or model which has serviceContainer initialised I do:
$this->myVar = $serviceContainer->get(\Zend\I18n\Translator\Translator::class);
Then I can access it by doing
$this->myVar->translate('lorem ipsum');

Resources