Passing variables between Middlewares using zend-mvc - zend-framework3

I'm trying to decipher how to properly blend variables between ZF3 Middleware under the latest release of zend-mvc.
Imagine a route like this:
'sandwich-test' => [
'type' => \Zend\Router\Http\Literal::class,
'options' => [
'route' => '/events/sandwich',
'defaults' => [
'middleware' => [
\Foo\Middleware\JsonWrappingMiddleware::class,
\Foo\Middleware\TestMiddleware::class,
],
],
],
],
In my simple test, I'd like for JsonWrappingMiddleware to simply return in a JsonResponse, the variables returned by TestMiddleware.
Individually, this works:
use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response\JsonResponse;
class JsonWrappingMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, DelegateInterface $delegate)
{
return new JsonResponse(['c' => 'd']);
}
}
...and...
use Interop\Http\ServerMiddleware\DelegateInterface;
use Interop\Http\ServerMiddleware\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Zend\Diactoros\Response\JsonResponse;
class TestMiddleware implements MiddlewareInterface
{
public function process(ServerRequestInterface $request, DelegateInterface $delegate)
{
return new JsonResponse(['a' => 'b']);
}
}
But then, how to make them work together to return
[ 'a' => 'b', 'c' => 'd', ]

You are sending response twice, if you want a middleware to pass some data then use $request->withAttribute($name, $value): RequestInterface and then in second (or just simply last) middleware get that data and convert it to proper JsonResponse

Related

How to create a JMSSerialization Handler for for base types, e.g. array <-> csv string

How to create a custom JMSSerializen handler for base types like strings or arrays? The goal would be to (de)serialize some properties in non-default ways. For example to specify that one array property should be deserialized to a CSV string instead to a default JSON array or one string string property to to an encrypted / encoded string, etc.
While creating such a handler for a custom class was no problem, I struggle to do the same for base types.
class SyncableEntityHandler implements SubscribingHandlerInterface {
public static function getSubscribingMethods() {
return [
[
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => 'SomeClass',
'method' => 'serializeSomeClassToJson',
],
[
'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
'format' => 'json',
'type' => 'SomeClass',
'method' => 'deserializeSomeClassFromJson',
],
];
}
public function serializeSomeClassToJson(JsonSerializationVisitor $visitor, AbstractSyncableEntity $entity, array $type, Context $context) {
...
}
public function deserializeSomeClassFromJson(JsonDeserializationVisitor $visitor, $entityGuid, array $type, Context $context) {
...
}
}
class OtherClass {
/*
* #JMS\Type("SomeClass")
*/
protected $someProperty;
/*
* #JMS\Type("array")
*/
protected $serializeToDefaultArray;
/*
* #JMS\Type("csv_array") // How to do this?
*/
protected $serializeToCSVString;
}
While I can create a handler with 'type' => 'array' to change the (de)serializiation of all arrays, I do not know to only select some arrays.
I already thought about using getters and setters instead (e.g. getPropertyAsCsvString() and setPropertyFromCsvString()). While this would work with custom classes, I would like to serialize some third-party classes as well where I specify the serialization options not with annotations but in .yaml files. Adding getter and setters to these classes is not (easily) possible. Additionally creating these getters and setters would add a lot of overhead.
So, is there a way to create and specify special handlers for some properties?
The implementation is quite straightforward:
class CsvArrayHandler implements SubscribingHandlerInterface {
public static function getSubscribingMethods() {
return [
[
'direction' => GraphNavigator::DIRECTION_SERIALIZATION,
'format' => 'json',
'type' => 'csv_array',
'method' => 'serializeToJson',
],
[
'direction' => GraphNavigator::DIRECTION_DESERIALIZATION,
'format' => 'json',
'type' => 'csv_array',
'method' => 'deserializeFromJson',
],
];
}
public function serializeSomeClassToJson(JsonSerializationVisitor $visitor, array $array, array $type, Context $context) {
return implode(',', $array);
}
public function deserializeSomeClassFromJson(JsonDeserializationVisitor $visitor, string $csvString, array $type, Context $context) {
return explode(',', $csvString);
}
}
Then just annotate your property with #JMS\Type("csv_array") and register the handler.
Note that using explode and implode does not escape the input so you may want to use something like league/csv instead.

How to Update Order custom field in Shopware 6 during order process?

I want to add a selector for date during order process in checkout. In which step should the custom field of an order be updated? And how is the custom field update done for order or other entity?
I want to add the fields as it is shown in official docs.
$this->customFieldSetRepository->create([
[
'name' => 'swag_example',
'customFields' => [
['name' => 'swag_example_size', 'type' => CustomFieldTypes::INT],
['name' => 'swag_example_color', 'type' => CustomFieldTypes::TEXT]
]
]
], $context);
Where exactly do you want to add that data during the order process?
One example would be from confirm to finish -> the cart is converted to an order.
You just need to create a Subscriber for that:
<?php
class OrderProcessSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
CartConvertedEvent::class => 'addCustomFieldsToConvertedCart',
];
}
public function addCustomFieldsToConvertedCart(CartConvertedEvent $event)
{
$convertedCart['customFields']['my_custom_field'] = 'test';
$event->setConvertedCart($convertedCart);
}
}
?>

OroPlatform: Override core entity form builder

Context
I'm trying to change the form type of one field on one of the core entity: Business Unit
The default form field is TextField and I want to change it to ChoiceType.
Here is my custom field on Business Unit entity created with migration :
$table->addColumn('periodicite', 'string', [
'oro_options' => [
'extend' => ['owner' => ExtendScope::OWNER_CUSTOM],
'entity' => ['label' => 'Périodicité'],
],
]);
Issue
I've seen on the Oro documentation that entity_config.yml could solve my problem. I've tried to put these lines but it doesn't work :
entity_config:
business_unit:
entity:
items:
periodicite:
form:
type: Symfony\Component\Form\Extension\Core\Type\ChoiceType
options:
choices:
Mensuel: Mensuel
Trimestriel: Trimestriel
placeholder: false
required: true
label: "Périodicite"
I have also tried to create a new migration to change the field type on my custom field but it doesn't work
<?php
namespace Baltimore\Bundle\AppBundle\Migrations\Schema\v1_1;
use Doctrine\DBAL\Schema\Schema;
use Oro\Bundle\EntityConfigBundle\Migration\UpdateEntityConfigFieldValueQuery;
use Oro\Bundle\EntityExtendBundle\EntityConfig\ExtendScope;
use Oro\Bundle\EntityExtendBundle\Migration\Extension\ExtendExtension;
use Oro\Bundle\EntityExtendBundle\Migration\Extension\ExtendExtensionAwareInterface;
use Oro\Bundle\MigrationBundle\Migration\Migration;
use Oro\Bundle\MigrationBundle\Migration\QueryBag;
use Oro\Bundle\OrganizationBundle\Entity\BusinessUnit;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
class UpdateBusinessUnitField implements Migration, ExtendExtensionAwareInterface
{
/** #var ExtendExtension */
protected $extendExtension;
/**
* #inheritdoc
*/
public function setExtendExtension(ExtendExtension $extendExtension)
{
$this->extendExtension = $extendExtension;
}
public function up(Schema $schema, QueryBag $queries)
{
$queries->addQuery(
new UpdateEntityConfigFieldValueQuery(
BusinessUnit::class,
'periodicite',
'form',
'form_type',
ChoiceType::class
)
);
$queries->addQuery(
new UpdateEntityConfigFieldValueQuery(
BusinessUnit::class,
'periodicite',
'form',
'form_options',
[
'choices' => [
'Mensuel' => 'Mensuel',
'Trimestriel' => 'Trimestriel',
'Annuel' => 'Annuel',
],
]
)
);
}
}
I have found a solution with the changeColumn method in my migration file and it works like a charm.
By the way, these properties works also with the addColumn method.
public function up(Schema $schema, QueryBag $queries)
{
$table = $schema->getTable('oro_business_unit');
$table->changeColumn('periodicite', [
'oro_options' => [
'extend' => ['owner' => ExtendScope::OWNER_CUSTOM],
'entity' => ['label' => 'Périodicité'],
'form' => [
'form_type' => ChoiceType::class,
'form_options' => [
'choices' => [
'Mensuel' => 'Mensuel',
'Trimestriel' => 'Trimestriel',
'Semestriel' => 'Semestriel',
'Annuel' => 'Annuel'
]
]
],
],
]);
}
I don't know about the possibility to override entity config metadata using the YAML file. If there is - please share the documentation you used to implement it in the comments.
But for sure, you can manage the same using the schema migration, like in this example:
class UpdateOpportunityRelationFormType implements Migration
{
/**
* {#inheritdoc}
*/
public function up(Schema $schema, QueryBag $queries)
{
$queries->addQuery(
new UpdateEntityConfigFieldValueQuery(
Quote::class,
'opportunity',
'form',
'form_type',
OpportunitySelectType::class
)
);
$queries->addQuery(
new UpdateEntityConfigFieldValueQuery(
Quote::class,
'opportunity',
'form',
'form_options',
['attr' => ['readonly' => true]]
)
);
}
}

Specify query for datagridfilter sonata

When using the doctrine_orm_model type for the datagridfilter. Is there a way to define a custom query to fetch the possible filter values?
Lets say I do not want to load all the entities for that specific type. I can not find any way to specify a query or something.
Yes you can like this your admin class. Important is 5 parameter, with query builder.
protected function configureDatagridFilters(DatagridMapper $datagridMapper)
{
$datagridMapper->add('modelField', null, [], 'entity', [
'class' => 'App\Entity\YourModel',
'choice_label' => 'name', // or something else as label
'query_builder' => function(YourModelRepository $repository) {
// return your query builder
}
]
);
}

Getting Symfony \ Component \ HttpKernel \ Exception \ MethodNotAllowedHttpException

I'm sending a PUT request that handles input data and updates a record, but I get the above response. The problem doesn't seem to be the route, however, because if I do dd($user) after the $user = User::whereId($id)->firstOrFail(); line, I get the object returned correctly.
Yet, when it comes time to validate it, it throws this error.
# routes
Route::resource('users', 'UsersController', ['only' => ['index', 'show', 'update']]);
# api call
PUT /users/2
# controller
public function update($id)
{
$user = User::whereId($id)->firstOrFail();
$input = Input::all();
$this->userForm->validate($input);
$user->fill($input)->save();
return $user->toJson();
}
# userForm class
<?php namespace Olp\Forms;
use Laracasts\Validation\FormValidator;
class UserForm extends FormValidator {
protected $rules = [
'email' => 'required|email|unique:users',
'password' => 'required',
'password_confirmation' => 'required|same:password',
'firstname' => 'required',
'lastname' => 'required',
'schoolname' => 'required',
'address1' => 'required',
'address2' => 'required',
'postcode' => 'required',
'city' => 'required'
];
}
and in my UserController:
use Olp\Forms\UserForm;
class UsersController extends \BaseController {
function __construct(UserForm $userForm)
{
$this->userForm = $userForm;
}
I'm not a Laravel guy, but a quick check on their documentation indicates that Resource Controllers support PUT in addition to other HTTP verbs.
I was not able to figure out how to add HTTP verb support to an arbitrary action, but this indicates that you can name a controller action prefixed with the verb it responds to
public function putUpdate($id)

Resources