I want to allow user creating oEmbed content to my website.
There is a lot of information how to implement it but none about creating a enpoint.
Quick question: is there some ready php code samples for creating (returning) oEmbed response for third party websites?
If no, how to create it? Ex youtube link looks like this:
http://www.youtube.com/oembed?url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DiwGFalTRHDA
and the response is :
{
"html": "<iframe width=\"459\" height=\"344\" src=\"https://www.youtube.com/embed/iwGFalTRHDA?feature=oembed\" frameborder=\"0\" allowfullscreen></iframe>",
"thumbnail_height": 360,
"thumbnail_width": 480,
"provider_name": "YouTube",
"author_url": "https://www.youtube.com/user/KamoKatt",
"thumbnail_url": "https://i.ytimg.com/vi/iwGFalTRHDA/hqdefault.jpg",
"author_name": "KamoKatt",
"provider_url": "https://www.youtube.com/",
"type": "video",
"version": "1.0",
"width": 459,
"title": "Trololo",
"height": 344
}
My question is: how they know which video it is? They are using regexp to parse videoID?
What is 'best practice' for this kind of request? Should it be created as Controller, Service, Provider or how?
Finally I have created it like this:
I have created a service:
namespace AppBundle\Service;
use AppBundle\Entity\PlaceMarker;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception as Ex;
use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
class EmbedService
{
CONST THUMBNAIL_WIDTH = 400;
CONST THUMBNAIL_HEIGHT = 300;
CONST HTML_WIDTH = 459;
CONST HTML_HEIGHT = 344;
/**
* #var string
*/
protected $baseUrl;
/**
* #var array
*/
private $params = [];
/**
* #var EntityManager
*/
private $entityManager;
/** #var \Twig_Environment */
private $twig;
public function __construct($baseUrl, EntityManager $entityManager, \Twig_Environment $twig)
{
$this->baseUrl = strtolower($baseUrl);
$this->entityManager = $entityManager;
$this->twig = $twig;
}
/**
*
* #param Request $request
* #param null $format
* #throws \Exception
*/
public function handleRequest(Request $request, $format = null)
{
$this->params = [];
// $baseUrl = $request->getSchemeAndHttpHost();
/** handle url parameter */
$this->params['url'] = $request->query->get('url');
if (!$this->params['url']) {
throw new Ex\BadRequestHttpException('A URL parameter must be provided');
}
/** check if url matches site url */
$this->params['path'] = substr($request->query->get('url'), strlen($this->baseUrl));
if (substr(strtolower($request->query->get('url')), 0, strlen($this->baseUrl)) !== strtolower($this->baseUrl)) {
throw new Ex\BadRequestHttpException('This is not a valid URL parameter');
}
/** handle format parameters */
$this->params['format'] = $format;
if (null === $format) {
$this->params['format'] = $request->query->get('format', 'json');
}
if (!in_array($this->params['format'], ['json', 'xml'])) {
throw new \Exception('Disallowed format parameter \'' . $this->params['format'] . '\'');
}
$maxWidth = $request->query->get('maxwidth', null);
if (is_numeric($maxWidth) || is_null($maxWidth)) {
$this->params['maxWidth'] = $maxWidth;
}
$maxHeight = $request->query->get('maxheight', null);
if (is_numeric($maxHeight) || is_null($maxHeight)) {
$this->params['maxHeight'] = $maxHeight;
}
$this->params['attr'] = $this->matchRoute($this->params['path']);
}
public function matchRoute($path)
{
$route1 = new Route('/place-marker/{id}/show', ['controller' => 'PlaceMarkerController']);
$routes = new RouteCollection();
$routes->add('place-marker', $route1);
$context = new RequestContext('/');
$matcher = new UrlMatcher($routes, $context);
try {
return $matcher->match($path);
} catch (\Exception $ex) {
throw new Ex\NotFoundHttpException('No implemented!');
}
}
/**
* #return array
*/
public function create()
{
if (!$this->params) {
throw new Exception('Unable to create oEmbed. Did you use handleRequest() first?');
}
$oEmbed = [
'version' => '1.0',
'provider_url' => $this->baseUrl,
'provider_name' => 'Pixdor.com'
];
switch ($this->params['attr']['_route']) {
case 'place-marker':
/**
* #var PlaceMarker $pMarker
*/
$pMarker = $this->entityManager->getRepository(PlaceMarker::class)->find($this->params['attr']['id']);
$oEmbed['title'] = $pMarker->getName();
$oEmbed['url'] = $pMarker->getUrl();
$oEmbed['description'] = $pMarker->getDescription();
$oEmbed['caption'] = $pMarker->getCaption();
$oEmbed['html'] = $this->twig->render(':place_marker:embed.html.twig');
$oEmbed['width'] = self::HTML_WIDTH;
$oEmbed['height'] = self::HTML_HEIGHT;
$oEmbed['rich'] = 'photo';
break;
}
$oEmbed['thumbnail_width'] = isset($this->params['maxWidth']) ? $this->params['maxWidth'] : self::THUMBNAIL_WIDTH;
$oEmbed['thumbnail_height'] = isset($this->params['thumbnail_height']) ? $this->params['thumbnail_height'] : self::THUMBNAIL_HEIGHT;
$oEmbed['thumbnail_url'] = sprintf('http://placehold.it/%dx%d', $oEmbed['thumbnail_width'], $oEmbed['thumbnail_height']);
return $oEmbed;
}
/**
* Returns format type (json|xml)
* #return string
*/
public function getFormat()
{
if (!$this->params) {
throw new Exception('Unknown format type. Did you use handleRequest() first?');
}
return $this->params['format'];
}
}
services.yml
app.embed:
class: AppBundle\Service\EmbedService
arguments: ["%base_url%", "#doctrine.orm.entity_manager", "#twig"]
parameters.yml
base_url: "http://project.local"
next in the controller:
/**
* #Route("/oembed.{_format}",
* name="embed",
* defaults={"_format": null}
* )
* #param Request $request
* #param $_format
* #return \Symfony\Component\HttpFoundation\Response
* #throws \Exception
*/
public function generateAction(Request $request, $_format)
{
$oEmbed = $this->get('app.embed');
$oEmbed->handleRequest($request, $_format);
$view = View::create()
->setFormat($oEmbed->getFormat())
->setStatusCode(200)
->setData($oEmbed->create());
return $this->handleView($view);
}
you call it like this:
http://project.local/oembed?url=http://project.local/place-marker/4/show
Related
I'm writing PHPUnit tests and running coverage tests. I admit its very difficult to have 100% coverage, however, I'd like to get as close as possible. In a following scenario, how to mock variables in a clause in order to test the code block?
class CalendarClientService
{
/** #var array SCOPES */
public const SCOPES = [Google_Service_Calendar::CALENDAR];
/** #var string ACCESS_TYPE */
public const ACCESS_TYPE = "offline";
/** #var string CALENDAR_ID */
public const CALENDAR_ID = "primary";
/** #var int MAX_RESULTS */
public const MAX_RESULTS = 25;
/** #var string ORDER_BY */
public const ORDER_BY = "startTime";
/** #var bool SINGLE_EVENTS */
public const SINGLE_EVENTS = true;
/** #var string|null TIME_MIN */
public const TIME_MIN = null;
/** #var bool CACHE_TIME_TO_LIVE */
public const CACHE_TIME_TO_LIVE = 604800;
/** #var string */
public string $clientSecretPath = "";
/** #var StorageAdapterFactoryInterface */
protected StorageAdapterFactoryInterface $storageAdapterFactory;
/** #var StorageInterface */
protected StorageInterface $storageInterfaceCache;
/**
* CalendarClientService constructor.
* #param string $clientSecretPath
* #param StorageAdapterFactoryInterface $storageAdapterFactory
* #param StorageInterface $storageInterfaceCache
*/
public function __construct(
string $clientSecretPath,
StorageAdapterFactoryInterface $storageAdapterFactory,
StorageInterface $storageInterfaceCache
) {
$this->clientSecretPath = $clientSecretPath;
$this->storageAdapterFactory = $storageAdapterFactory;
$this->storageInterfaceCache = $storageInterfaceCache;
}
/** #return string */
public function getClientSecretPath()
{
return $this->clientSecretPath;
}
/** #param string $secretFile */
public function setClientSecretPath(string $secretFile)
{
$this->clientSecretPath = $secretFile;
}
/**
* #param array
* #return Google_Service_Calendar_Event
*/
public function getGoogleServiceCalendarEvent($eventData)
{
return new Google_Service_Calendar_Event($eventData);
}
/**
* #param string
* #return Google_Service_Calendar_EventDateTime
*/
public function getGoogleServiceCalendarEventDateTime($dateTime)
{
$eventDateTime = new Google_Service_Calendar_EventDateTime();
$eventDateTime->setDateTime(Carbon::parse($dateTime)->toW3cString());
$eventDateTime->setTimeZone(Carbon::parse($dateTime)->timezone->getName());
return $eventDateTime;
}
/**
* #param Google_Client $client
* #return Events
*/
public function getGoogleServiceCalendarResourceEvents(Google_Client $client)
{
$service = new Google_Service_Calendar($client);
return $service->events;
}
/**
* #param int
* #return array
* #throws Exception
* #throws ExceptionInterface
*/
public function getEventData($id)
{
$client = $this->getClient();
if (!$this->authenticateClient($client)) {
return [
"error" => "authentication",
"url" => filter_var($client->createAuthUrl(), FILTER_SANITIZE_URL),
];
}
$service = $this->getGoogleServiceCalendarResourceEvents($client);
return ["event" => $service->get(self::CALENDAR_ID, $id)];
}
/**
* #return Google_Client
* #throws Exception
*/
public function getClient()
{
$client = new Google_Client();
$client->setApplicationName(Module::MODULE_NAME);
$client->setScopes(self::SCOPES);
$client->setAuthConfig($this->clientSecretPath);
$client->setAccessType(self::ACCESS_TYPE);
return $client;
}
/**
* #param Google_Client $client
* #return bool
* #throws ExceptionInterface
*/
public function authenticateClient(Google_Client $client)
{
if ($this->storageInterfaceCache->hasItem("api_access_token")) {
$accessToken = json_decode($this->storageInterfaceCache->getItem("api_access_token"), true);
if ($accessToken["error"] == "invalid_grant" || empty($accessToken)) {
$this->storageInterfaceCache->removeItem("api_access_token");
} else {
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$client->setAccessToken($accessToken);
}
}
if ($client->isAccessTokenExpired()) {
$tokenValid = false;
if ($client->getRefreshToken()) {
$client->fetchAccessTokenWithRefreshToken($client->getRefreshToken());
$accessToken = $client->getAccessToken();
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$tokenValid = true;
} else {
$helper = new Helper();
if(!$helper->verifyAuthCode($_GET["code"])){
return $tokenValid;
}
$authCode = $_GET["code"];
$accessToken = $client->fetchAccessTokenWithAuthCode($authCode);
if ($accessToken["error"] == "invalid_grant" || empty($accessToken)) {
$this->storageInterfaceCache->removeItem("api_access_token");
} else {
$this->storageInterfaceCache->setItem("api_access_token", json_encode($accessToken));
$client->setAccessToken($accessToken);
$tokenValid = true;
}
}
} else {
$tokenValid = true;
}
return isset($tokenValid) ? $tokenValid : false;
}
I want to test this 6th line from top in authenticateClient method and want to mock this clause $accessToken["error"] == "invalid_grant" || empty($accessToken).
Now how to go about it?
Edit: Here's a test that I've written. Now whatever value I'm mocking in the $this->storageInterfaceCacheMock->method("getItem"), it always returns empty $accessToken. I've also attached the image for better understanding of what's happening and what I want.
public function testGetEventDataReturnsArrayOnSuccessfulAuthenticateClientThroughCache()
{
$this->storageInterfaceCacheMock->method("hasItem")->willReturn(true);
$this->storageInterfaceCacheMock->method("getItem")->willReturn(json_encode('{"access_token":"ya29.a0ARrdaM99pJTf1XzmD1ngxAH3XJud8lvHb0aTaOOABYdfdhsdfgsdfgVD9OoH4heiKoskDF7DMkHj1_aPuWIO5TE14KHJidFf66xwn_pTCkkSow6Kg4lRHwGrNQBQGI8sPlgnFO5U5hJvYdqgxDMHEqw1TER2w","expires_in":3599,"scope":"https:\/\/www.googleapis.com\/auth\/calendar","token_type":"Bearer","created":1637312218,"refresh_token":"1\/\/03psr5omKiljUCgYFDHDGJHGSHSNwF-L9Iraor5zcfe-h3BeCHSFGSDFGDGJHjy4UnEtKj974LXthS5bWexQcjviVGfJsdfGHSHgIrDn6Yk"}'));
$this->assertIsArray($this->calendarClientService->getEventData(1));
}
Another test which isn't performing as per required is mentioned below. (also visible in the screenshot)
public function testAccessTokenIsExpiredAndGotRefreshToken()
{
$this->googleClientMock->method("isAccessTokenExpired")->willReturn(true);
$this->googleClientMock->method("getRefreshToken")->willReturn(true);
$this->googleClientMock->method("fetchAccessTokenWithRefreshToken")->willReturnSelf();
$this->googleClientMock->method("getAccessToken")->willReturnSelf();
$this->assertTrue($this->calendarClientService->authenticateClient($this->googleClientMock));
}
I believe you want json_decode you don't need double encode here:
$this->storageInterfaceCacheMock->method("getItem")->willReturn(json_encode('{"access_token":"...."}'));
just
$this->storageInterfaceCacheMock->method("getItem")->willReturn('{"access_token":"...."}');
Here's how I resolved the issue and got the test to be successful.
I declared a dummy ACCESS_TOKEN as below and then used in the test method.
class CalendarControllerTest extends AbstractApplicationTestCase
{
/** #var string CLIENT_SECRET */
public const CLIENT_SECRET = __DIR__ . "/../_fixtures/config/client_secret.json";
/** #var string CLIENT_SECRET */
public const ACCESS_TOKEN = [
"access_token" => "test-data",
"expires_in" => 3592,
"scope" => "https://www.googleapis.com/auth/calendar",
"token_type" => "Bearer",
"created" => 1640858809,
];
...
...
...
}
public function setUp(): void
{
parent::setUp();
$this->googleClientMock = $this->getMockBuilder(Google_Client::class)
->disableOriginalConstructor()
->onlyMethods(
[
"isAccessTokenExpired",
"setAuthConfig",
"getRefreshToken",
"fetchAccessTokenWithRefreshToken",
"fetchAccessTokenWithAuthCode",
"getAccessToken",
"setAccessToken",
]
)
->getMock();
$this->googleServiceCalendarResourceEventsMock = $this->getMockBuilder(Events::class)
->disableOriginalConstructor()
->onlyMethods(["get"])
->getMock();
$this->googleServiceCalendarEventMock = $this->getMockBuilder(Event::class)
->disableOriginalConstructor()
->getMock();
$this->storageInterfaceCacheMock = $this->getMockForAbstractClass(StorageInterface::class);
$this->container->setAllowOverride(true);
$this->container->setService(Google_Client::class, $this->googleClientMock);
$this->container->setService(Events::class, $this->googleServiceCalendarResourceEventsMock);
$this->container->setService(Event::class, $this->googleServiceCalendarEventMock);
$this->container->setService(StorageInterface::class, $this->storageInterfaceCacheMock);
$this->container->setAllowOverride(true);
$this->googleClientMock->method("setAuthConfig")->willReturn(true);
$this->calendarClientService = $this->container->get("ServiceManager")->get(CalendarClientService::class);
$this->calendarClientService->setClientSecretPath(CalendarControllerTest::CLIENT_SECRET);
}
/** #throws ExceptionInterface */
public function testAccessTokenIsExpiredAndFailureToRefreshTokenWillGenerateNewAccessToken()
{
$this->calendarClientService->setAuthCode(CalendarControllerTest::DEFAULT_TESTING_VALUE);
$this->googleClientMock->method("isAccessTokenExpired")->willReturn(true);
$this->googleClientMock->method("getRefreshToken")->willReturn(false);
$this->googleClientMock->method("fetchAccessTokenWithAuthCode")->willReturn(
CalendarControllerTest::ACCESS_TOKEN
);
$this->storageInterfaceCacheMock->method("setItem")->willReturn(true);
$this->googleClientMock->method("setAccessToken")->willReturnSelf();
$this->assertTrue($this->calendarClientService->authenticateClient($this->googleClientMock));
}
I'm trying to create a listener to when a new Rating is created. I followed all the documentation but I keep getting the same error:
Argument 1 passed to "Symfony\Component\EventDispatcher\EventDispatcherInterface::dispatch()" must be an instance of "Symfony\Component\EventDispatcher\Event", "App\Event\AverageRatingEvent" given.
I'm trying to use Symfony\Component\EventDispatcher\Event in the event but it keeps saying that it is deprecated and according to documents to use Symfony\Contracts\EventDispatcher\Event instead.
I register my event in the services and the following is my event, eventlistener and class
Class Rating
class RatingApiController extends AbstractController
{
/**
* #Route("api/rating/create", name="CreateRating", methods={"POST"})
* #param DocumentManager $dm
* #param Request $request
* #param EventDispatcher $eventDispatcher
* #return RedirectResponse|Response
* #throws MongoDBException
*
*/
public function addRating(Request $request, EventDispatcherInterface $eventDispatcher)
{
$response = [];
$form = $this->
createForm(RatingType::class, new Rating() ,array('csrf_protection' => false));
$request = json_decode($request->getContent(), true);
$form->submit($request);
if($form->isSubmitted() && $form->isValid())
{
$rating = $form->getData();
$this->documentManager->persist($rating);
$this->documentManager->flush();
$averageRatingEvent = new AverageRatingEvent($rating);
$eventDispatcher->dispatch( AverageRatingEvent::NAME, $averageRatingEvent);
$status = 200;
$response = ["status" => $status, "success" => true, "data" => $rating->getId()];
// return $this->redirectToRoute('rating_list');
}
}
Event
<?php
namespace App\Event;
use App\Document\Rating;
use Symfony\Contracts\EventDispatcher\Event;
class AverageRatingEvent extends Event
{
/**
* #var Rating $rating
*/
protected $rating;
public const NAME = "average.rating";
public function __construct(Rating $rating)
{
$this->rating = $rating;
}
public function getRating()
{
return $this->rating;
}
}
Listener
<?php
namespace App\Event;
use App\Document\Rating;
use Doctrine\ODM\MongoDB\Event\LifecycleEventArgs;
class AverageRatingListener
{
public function postPersist(LifecycleEventArgs $args)
{
$document = $args->getObject();
if(!$document instanceof Rating)
return;
}
public function RatingCreated()
{
dump("Hello a rating was just added");
}
}
Inside AverageRatingEvent you extend Event.
The use needs to be changed from
use Symfony\Contracts\EventDispatcher\Event;
to
use Symfony\Component\EventDispatcher\Event;
I have created this resource in order to request a password reset token:
POST {{api_base_url}}/users/password/reset-request
Payload example
{
"email" :"user#example.com"
}
Everything works fine but the response doesn't serialize ResetPasswordRequestOutput to show the result. I got this response instead (as User type)
{
"#context": {
"#vocab": "http://dev.api.xxxxxxxxxx.com/docs.jsonld#",
"hydra": "http://www.w3.org/ns/hydra/core#",
"token": "ResetPasswordRequestOutput/token"
},
"#type": "User",
"#id": "/users/00000000-0000-0000-0000-000000000002",
"token": "ORGOsGh01sr8R91J"
}
Expected output: (of type: ResetPasswordRequestOutput)
{
"#type": "ResetPasswordRequestOutput",
"token": "ORGOsGh01sr8R91J"
}
Code:
The controller class of the custom operation:
final class ResetPasswordRequest {
private $validator;
private $entityManager;
public function __construct(ValidatorInterface $validator, EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
$this->validator = $validator;
}
public function __invoke(ResetPasswordRequestInput $data)
{
$this->validator->validate($data);
$userRepository = $this->entityManager->getRepository(User::class);
/** #var User $user */
$user = $userRepository->findOneBy(['email' => $data->email]);
if (!$user) {
throw new ItemNotFoundException("invalid token");
}
if ($user->getStatus() !== UserStatus::ACTIVE) {
throw new AccessDeniedException("user is inactive");
}
$generator = (new Factory())->getGenerator(new Strength(Strength::MEDIUM));
$token = $generator->generateString(16, 'BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789');
$user->setToken($token);
return $user;
}
}
The data transofrmer that converts User object to ResetPasswordRequestOutput
namespace App\DataTransformer;
final class ResetPasswordRequestOutputDataTransformer implements DataTransformerInterface
{
private $normalizer;
public function __construct(NormalizerInterface $normalizer)
{
$this->normalizer = $normalizer;
}
/**
* {#inheritdoc}
*/
public function transform($data, string $to, array $context = [])
{
$output = new ResetPasswordRequestOutput();
$output->token = $data->getToken();
return $output;
}
/**
* {#inheritdoc}
*/
public function supportsTransformation($data, string $to, array $context = []): bool
{
return ResetPasswordRequestOutput::class === $to && $data instanceof User;
}
DTO object that holds input data
<?php
namespace App\Dto;
final class ResetPasswordRequestInput
{
/**
* #var string
*
* #Assert\Email
* #Groups({"user:write"})
*/
public $email;
}
DTO object that holds output data
namespace App\Dto;
final class ResetPasswordRequestOutput
{
/**
* #var string
*
* #Assert\NotNull()
* #Groups({"user:read"})
*/
public $token;
}
User Entity class with ApiResource annotation (partial) action=reset_password_request
/**
* #ApiResource(
* normalizationContext={"groups"={"user", "user:read"}},
* denormalizationContext={"groups"={"user", "user:write"}},
* collectionOperations={
* "get",
* "post",
* "reset_password_request" = {
* "method"= "POST",
* "read"=false,
* "path"="/users/password/reset-request",
* "controller"=ResetPasswordRequest::class,
* "status"=200,
* "input"=ResetPasswordRequestInput::class,
* "output"=ResetPasswordRequestOutput::class,
* "normalization_context"={"jsonld_embed_context"=false}
* },
I'm using jms/serializer-bundle 2.4.3 on a symfony 4.2 and a I noticed an annoying problem in my application :
when I post an entity, the DoctrineObjectConstructor uses id in content to retrieve another entity and thus patch it while it is excluded by my security groups
see rather entity
class Entity
{
/**
* #var int
*
* #ORM\Column(name="id", type="int")
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
* #Serializer\Groups({"GetEntity"})
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string")
* #Serializer\Groups({"GetEntity", "PostEntity"})
*/
private $name;
}
controller
/**
* #Route("/entity", name="post_entity", methods={"POST"})
*/
public function postEntity(Request $request, EntityManagerInterface $entityManager, SerializerInterface $serializer): JsonResponse
{
$deserializationContext = DeserializationContext::create();
$deserializationContext->setGroups(['PostEntity']);
$entity = $serializer->deserialize($request->getContent(), Entity::class, 'json', $deserializationContext);
$entityManager->persist($entity);
$entityManager->flush();
return $this->json($entity, Response::HTTP_OK, [], ['groups' => ['GetEntity']]);
}
I have some JMS configurations changes in services
jms_serializer.object_constructor:
alias: jms_serializer.doctrine_object_constructor
public: true
jms_serializer.unserialize_object_constructor:
class: App\Serializer\ObjectConstructor
If anyone can explain to me how to ignore the id in this case I'm open to any suggestions.
Regards and thanks for any help
To resolve, just add override in your services.yaml
jms_serializer.doctrine_object_constructor:
class: App\Serializer\DoctrineObjectConstructor
arguments:
- '#doctrine'
- '#jms_serializer.unserialize_object_constructor'
jms_serializer.object_constructor:
alias: jms_serializer.doctrine_object_constructor
and add a local DoctrineObjectConstructor updated to ignore entities without current deserialization group on id property
class DoctrineObjectConstructor implements ObjectConstructorInterface
{
const ON_MISSING_NULL = 'null';
const ON_MISSING_EXCEPTION = 'exception';
const ON_MISSING_FALLBACK = 'fallback';
private $fallbackStrategy;
private $managerRegistry;
private $fallbackConstructor;
/**
* Constructor.
*
* #param ManagerRegistry $managerRegistry Manager registry
* #param ObjectConstructorInterface $fallbackConstructor Fallback object constructor
* #param string $fallbackStrategy
*/
public function __construct(ManagerRegistry $managerRegistry, ObjectConstructorInterface $fallbackConstructor, $fallbackStrategy = self::ON_MISSING_NULL)
{
$this->managerRegistry = $managerRegistry;
$this->fallbackConstructor = $fallbackConstructor;
$this->fallbackStrategy = $fallbackStrategy;
}
/**
* {#inheritdoc}
*/
public function construct(VisitorInterface $visitor, ClassMetadata $metadata, $data, array $type, DeserializationContext $context)
{
// Locate possible ObjectManager
$objectManager = $this->managerRegistry->getManagerForClass($metadata->name);
if (!$objectManager) {
// No ObjectManager found, proceed with normal deserialization
return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
}
// Locate possible ClassMetadata
$classMetadataFactory = $objectManager->getMetadataFactory();
if ($classMetadataFactory->isTransient($metadata->name)) {
// No ClassMetadata found, proceed with normal deserialization
return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
}
// Managed entity, check for proxy load
if (!\is_array($data)) {
// Single identifier, load proxy
return $objectManager->getReference($metadata->name, $data);
}
// Fallback to default constructor if missing identifier(s)
$classMetadata = $objectManager->getClassMetadata($metadata->name);
$identifierList = [];
foreach ($classMetadata->getIdentifierFieldNames() as $name) {
$propertyGroups = [];
if ($visitor instanceof AbstractVisitor) {
/** #var PropertyNamingStrategyInterface $namingStrategy */
$namingStrategy = $visitor->getNamingStrategy();
$dataName = $namingStrategy->translateName($metadata->propertyMetadata[$name]);
$propertyGroups = $metadata->propertyMetadata[$name]->groups;
} else {
$dataName = $name;
}
if (!array_key_exists($dataName, $data) || true === empty(array_intersect($context->getAttribute('groups'), $propertyGroups))) {
return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
}
$identifierList[$name] = $data[$dataName];
}
// Entity update, load it from database
$object = $objectManager->find($metadata->name, $identifierList);
if (null === $object) {
switch ($this->fallbackStrategy) {
case self::ON_MISSING_NULL:
return null;
case self::ON_MISSING_EXCEPTION:
throw new ObjectConstructionException(sprintf('Entity %s can not be found', $metadata->name));
case self::ON_MISSING_FALLBACK:
return $this->fallbackConstructor->construct($visitor, $metadata, $data, $type, $context);
default:
throw new InvalidArgumentException('The provided fallback strategy for the object constructor is not valid');
}
}
$objectManager->initializeObject($object);
return $object;
}
}
It just my thought i just want to do like the same, I haven't try this because of i haven't any idea about this means how it will be done.
For Example:
I have - mysite.com/view?user_id=12 , I don't want to show url's parameters (?user_id=12) on url, On the place of this, I want to show like
mysite.com/view?_signature=encryptedparameter
(like : mysite.com/view?_signature=853ef7a0ff5aea6f24152b1d1ed4d771)
853ef7a0ff5aea6f24152b1d1ed4d771 will denotes user_id=12.
If i have multiple parameters it would be like the same and i will have a single encrypted string and i will get all parameters with that string.
Yes but i am using in Laravel 5.1
assume if i have "mysite.com/view?user_id=12"
And i want "mysite.com/view?_signature=encryptedparameter"
Please fallow some steps
laravel>packages>myfolder>core
+=>folder
-=>file
+packages
+Folder
+core
+src
+Faundation
-Application.php
+Routing
-RoutingServiceProvider.php
-UriGenerator.php
+Support
+Middleware
-UrlParamRevealerMiddleware.php
+ServiceProvider
-CoreServiceProvider.php
-UriParamProtector.php
<<IN APPLICATION.PHP>>
<?php
namespace Folder\Core\Foundation;
use Illuminate\Events\EventServiceProvider;
use Folder\Core\Routing\RoutingServiceProvider;
use Illuminate\Foundation\Application as BaseApplication;
use Folder\Core\Support\ServiceProvider\CoreServiceProvider;
class Application extends BaseApplication
{
/**
* Register all of the base service providers.
*
* #return void
*/
protected function registerBaseServiceProviders()
{
$this->register(new EventServiceProvider($this));
$this->register(new CoreServiceProvider($this));
$this->register(new RoutingServiceProvider($this));
}
}
<<//IN APPLICATION.PHP>>
<<-RoutingServiceProvider>>
<?php
namespace Folder\Core\Routing;
use Folder\Core\Routing\UrlGenerator;
use Illuminate\Routing\RoutingServiceProvider as BaseServiceProvider;
class RoutingServiceProvider extends BaseServiceProvider
{
/**
* Register the URL generator service.
*
* #return void
*/
protected function registerUrlGenerator()
{
$this->app['url'] = $this->app->share(function ($app) {
$routes = $app['router']->getRoutes();
// The URL generator needs the route collection that exists on the router.
// Keep in mind this is an object, so we're passing by references here
// and all the registered routes will be available to the generator.
$app->instance('routes', $routes);
$url = $this->getUrlGenerator($routes);
$url->setSessionResolver(function () {
return $this->app['session'];
});
// If the route collection is "rebound", for example, when the routes stay
// cached for the application, we will need to rebind the routes on the
// URL generator instance so it has the latest version of the routes.
$app->rebinding('routes', function ($app, $routes) {
$app['url']->setRoutes($routes);
});
return $url;
});
}
/**
* Get the url generator instance.
*
* #param \Illuminate\Routing\RouteCollection $routes
* #return \Folder\Core\Routing\UrlGenerator
*/
protected function getUrlGenerator($routes)
{
$url = new UrlGenerator(
$routes,
$this->app->rebinding(
'request',
$this->requestRebinder()
)
);
return $url;
}
}
<</-RoutingServiceProvider>>
<<UriGenerator.php>>
<?php
namespace Folder\Core\Routing;
use ErrorException;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Routing\UrlGenerator as BaseUrlGenerator;
class UrlGenerator extends BaseUrlGenerator
{
/**
* Get the URL to a named route.
*
* #param string $name
* #param mixed $parameters
* #param bool $absolute
* #return string
*
* #throws \InvalidArgumentException
*/
public function route($name, $parameters = [], $absolute = true)
{
$encryptedParameters = $parameters;
if (Auth::guest() === false) {
$encryptedParameters = $this->encrypt($name, $parameters);
}
return parent::route($name, $encryptedParameters, $absolute);
}
/**
* Get the cryptic engine.
*
* #return \Folder\Core\Support\UrlParamEncrypter
*
* #throws \ErrorException
*/
protected function getCrypt()
{
$app = App::getInstance();
if (isset($app['urlencryptor'])) {
return $app['urlencryptor'];
}
throw new ErrorException('URL Encryptor was not found.');
}
/**
* Get the protector engine.
*
* #return #return \Folder\Core\Support\UrlParamProtector
*
* #throws \ErrorException
*/
protected function getProtector()
{
$app = App::getInstance();
if (isset($app['urlprotector'])) {
return $app['urlprotector'];
}
throw new ErrorException('URL Protector was not found.');
}
/**
* Encrypts the parameter passed as querystring in URL.
*
* #param array $parameters
* #return array
*/
protected function encrypt($routeName, $parameters = [])
{
if (! is_array($parameters)) {
return $parameters;
}
if (count($parameters) === 0) {
return [];
}
if (Auth::guest() === true) {
return $parameters;
}
$protected = $this->getProtector()->protect($routeName, $parameters);
return ['__signature' => $protected];
}
}
<<//UriGenerator.php>>
<<UrlParamRevealerMiddleware.php>>
<?php
namespace Folder\Core\Support\Middleware;
use Closure;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Folder\Core\Support\UrlParamProtector;
class UrlParamRevealerMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
(! Auth::guest()) && App::make(UrlParamProtector::class)->reveal($request);
return $next($request);
}
}
<<//UrlParamRevealerMiddleware.php>>
<<CoreServiceProvider.php>>
<?php
namespace Folder\Core\Support\ServiceProvider;
use Illuminate\Support\ServiceProvider;
use Folder\Core\Support\UrlParamProtector;
class CoreServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
$this->app->make('Illuminate\Contracts\Http\Kernel')
->pushMiddleware('Folder\Core\Support\Middleware\UrlParamRevealerMiddleware');
}
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->registerUrlProtector();
}
/**
* Register UrlProtector class.
*/
protected function registerUrlProtector()
{
$this->app->singleton('urlprotector', function () {
return new UrlParamProtector();
});
}
}
<<//CoreServiceProvider.php>>
<<-UriParamProtector.php>>
<?php
namespace Folder\Core\Support;
use Illuminate\Support\Str;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
class UrlParamProtector
{
/**
* Session key.
*
* #var string
*/
protected $sessionKey = '__url_protector__';
/**
* Request class.
*
* #var \Illuminate\Http\Request
*/
protected $request;
/**
* Values those needs to be merged in request object.
*
* #var array
*/
protected $valuesToBeMerged;
/**
* Create and returns VALID RFC 4211 COMPLIANT
* Universally Unique IDentifiers (UUID) version 4.
*
* #return string
*/
protected function getNewGuid()
{
if (function_exists('com_create_guid') === true) {
return trim(com_create_guid(), '{}');
}
return sprintf(
'%04X%04X-%04X-%04X-%04X-%04X%04X%04X',
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(16384, 20479),
mt_rand(32768, 49151),
mt_rand(0, 65535),
mt_rand(0, 65535),
mt_rand(0, 65535)
);
}
/**
* Create the route key.
*
* #param string $routeName
* #param array $parameters
* #return string
*/
protected function getRouteKey($routeName, array $parameters = [])
{
if (count($parameters) <= 0) {
$paramToString = '';
} else {
$paramToString = implode('-', array_map(
function ($k, $v) {
return $k . '-' . $v;
},
array_keys($parameters),
array_values($parameters)
));
}
$routeKey = 'route__' . $routeName . (empty($paramToString) ? '' : '-' . $paramToString);
return $routeKey;
}
/**
* Returns a GUID for a URL parameter.
*
* #param string $routeName
* #param array $parameters
* #return string
*/
public function protect($routeName, array $parameters)
{
$routeKey = $this->getRouteKey($routeName, $parameters);
if (Session::has($this->sessionKey . '.' . $routeKey) === false) {
$guid = Str::lower($this->getNewGuid());
Session::set($this->sessionKey . '.' . $routeKey, [
'guid' => $guid,
'loggedin_user_id' => (Auth::guest() ? 0 : Auth::user()->id),
'params' => $parameters,
]);
} else {
$guid = Session::get($this->sessionKey . '.' . $routeKey . '.guid');
}
return $guid;
}
/**
* Check whether guid passed is a valid one or not.
*
* #param string $guid
* #return boolean
*/
protected function isValidGuid($guid)
{
foreach (Session::get($this->sessionKey) as $key => $value) {
if (!isset($value['guid'])) {
list($innerKey, $val) = each($value);
} else {
$val = $value;
}
if ($val['guid'] === $guid) {
$this->valuesToBeMerged = $val['params'];
return true;
}
}
return false;
}
/**
* Check whether guid passed is a valid one or not.
*
* #param string $guid
* #return boolean
*/
public function isValidGuidForPost($guid)
{
foreach (Session::get($this->sessionKey) as $key => $value) {
if ($value['guid'] === $guid && Auth::user()->id === $value['loggedin_user_id']) {
$this->valuesToBeMerged = $value['params'];
return true;
}
}
return false;
}
/**
* Merge the request with our revealed values.
*/
protected function mergeRequest()
{
$this->request->merge($this->valuesToBeMerged);
}
/**
* Check whether a "__signature" is correct or not.
*
* #param \Illuminate\Http\Request $request
* #return boolean
*/
public function reveal(Request &$request)
{
$this->request = $request;
$guid = ($this->request->query('__signature') ? : false);
if ($guid === false) {
return false;
}
if ($this->isValidGuid($guid) === false) {
App::abort(400);
}
$this->mergeRequest();
}
}
<<//-UriParamProtector.php>>
==============================================
after that in "bootstrap>App.php"
use this=>
$app = new Folder\Core\Foundation\Application(
realpath(__DIR__.'/../')
);
instad of =>
$app = new Illuminate\Foundation\Application(
realpath(__DIR__.'/../')
);
in any link use "data-href"
<a data-href="route('modify_lead_status',['user_id' => $users->id])" href="javascript:void(0)"><i class=\"fa fa-random\"></i></a>"
and after that any controller,Routing,middleware will be same.....
>>composer auto-dump
<<Please check spealing be sure use same>>
i hope this is help full....thanks