Workflow in Symfony doesn't work with "multiple_state" - php

In one of the configuration files of Symfony 5.2.8 with Workflow 5.2.7 I have:
framework:
workflows:
register_participation:
type: 'workflow' # or 'state_machine'
audit_trail:
enabled: true
marking_store:
type: 'multiple_state'
arguments:
- complexState
# [...]
When I execute bin/console I have error:
Unrecognized option "arguments" under framework.workflows.workflows.register_participation.marking_store". Available options are "property", "service", "type".
When I change the configuration to:
framework:
workflows:
register_participation:
type: 'workflow' # or 'state_machine'
audit_trail:
enabled: true
marking_store:
type: 'multiple_state'
property: state
# [...]
I get the error:
The value "multiple_state" is not allowed for path framework.workflows.workflows.register_participation.marking_store.type". Permissible values: "method"
It works when I change to this:
marking_store:
type: 'method'
property: main_state
Anybody have idea what can I do to works with multiple_state? Thanks in advance.

From the symfony workflow documentation:
The marking store type could be “multiple_state” or “single_state”. A
single state marking store does not support a model being on multiple
places at the same time. This means a “workflow” must use a
“multiple_state” marking store and a “state_machine” must use a
“single_state” marking store. Symfony configures the marking store
according to the “type” by default, so it’s preferable to not
configure it.
A single state marking store uses a string to store the data. A
multiple state marking store uses an array to store the data.
So if you configure type "workflow" it should automatically be "multiple_state". You could dump your entity and the state property should be of type array

Related

How to add simple processing in symfony config

I am trying to create a simple processing code to Symfony configuration.
Here is the final effect I want to do (config pseudocode):
# config/packages/monolog.yml
monolog:
handlers:
debug_log:
type: '%env(LOGS_ROTATE) > 0 ? "rotating_file" : "stream"%'
max_files: '%env(LOGS_ROTATE) ?? null%'
...
The idea is that if LOGS_ROTATE env is set to a positive number,
type should be rotating_file and max_files should be that number,
otherwise type should be stream and max_files should be skipped
Is it possible to do that?
I was considering using env processors, but those cannot take any parameters,
and using hardcoding config values inside such a processor feels bad.
edit:
I also tried to use symfony expression language, but got an error:
There is no handler class defined for handler "#=%env(logs_rotate) > 0 ? rotating_file : stream".
monolog:
handlers:
debug_log:
type: "#=%env(LOGS_ROTATE) > 0 ? rotating_file : stream"

How define some PHP constant in the Symfony configuration?

this is my first post, so i will try to be clear
So i need to define some constants in the Symfony configuration (in a .yaml file, i guess)
I know i could define them throw public const MY_CONST but that is not what I want.
I guess this is what i need (the second part, i am not using Abstract controller as i am not in a controller)
https://symfony.com/doc/current/configuration.html#accessing-configuration-parameters
But I just can't get it to work. Could anyone help me, by giving me an exemple, or maybe an other way to do ?
Thanks guys.
The parameters you described can be used in the configuration defined as eg;
parameters:
the_answer: 42
You can then use these values in further configuration things (see below for example). Or if you want to handle these values in a controller you can (not recommended anymore) use $this->getParameter('the_answer') to get the value.
Binding arguments (recommended):
This approach wil bind values which you can then get (auto-magically injected) in a controller function/service by referencing the argument.
The values can range from simple scalar values to services, .env variables, php constants and all of the other things the configuration can parse.
# config/services.yaml
services:
_defaults:
bind:
string $helloWorld: 'Hello world!' # simple string
int $theAnswer: '%the_answer%' # reference an already defined parameter.
string $apiKey: '%env(REMOTE_API)%' # env variable.
Then these get injected in a service/controller function when we do something like:
public function hello(string $apiKey, int $theAnswer, string $helloWorld) {
// do things with $apiKey, $theAnswer and $helloWorld
}
More details and examples can be found in the symfony docs https://symfony.com/doc/current/service_container.html#binding-arguments-by-name-or-type
Inject into service (alternative)
You can also directly inject it into the defined service using arguments.
# config/services.yaml
services:
# explicitly configure the service
App\Updates\SiteUpdateManager:
arguments:
$adminEmail: 'manager#example.com'

Is it possible to load Swagger annotations from a different class or file?

I have the following simple PHP method like the following
/**
*
* (swagger annotation to be called from a different class)
*
*/
public function getApiCall()
{
//Do something
}
and I need to include long Swagger documentation into the annotation above the method, so
is it possible to write the annotation in a different class ? and call it here with something like
/**
*
*call('App\Http\Controllers\testAnnotation');
*/
The main purpose is to have a clean class without so many lines of documentation and annotations in it.
Loading "annotations from a different class" is not something that makes a lot of sense. Annotations are read in the annotated code, that's their whole purpose.
But if you want to keep configuration and code separated, you do not have to use Swagger-Php to generate your swagger configuration file.
The package is simply a convenience way to generate the swagger.json file from code annotations.
But if you do not want to use annotations in the first place, and keep your classes clean from extraneous configuration (something that I personally applaud), just... do not use Swagger-Php and build your own configuration files outside of your classes.
You could even write it in YAML, if you feel more comfortable than writing JSON by hand. For example::
openapi: 3.0.0
info:
title: 'Search API'
version: 1.0.0
servers:
- url:
description: Current host server
- url: https:your-server.com
description: Prod server
paths:
/foo:
post:
summary: 'Creates a new foo'
description: 'Builds a new Foo and makes it available to Bar'
requestBody:
description: 'Foo '
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Foo'
responses:
'201':
description: Foo created
'202':
description: Foo queued, it will be eventually created.
components:
schemas:
Foo:
type: object
required:
- name
- size
properties:
name:
type: string
size:
type: integer
This, once converted to JSON (there are many libraries to do this, or you could even use a free service like this one), you can feed the resulting JSON to swagger directly.
E.g. the YAML above parses to this JSON file. You can easily test it out by heading to the Swagger demo instance, and past the JSON URL in the "explore" location bar, and you'll get something like this:
In the end, it's not much more work than using annotations (if any more work at all), and you can keep your entity classes clean from configuration concerns.

How to use a DTO and Messenger with Api-Platform?

For one of our resources, we'd like to route the request through a command handler. Creating a new item for this resource has a number of side-effects and prior requirements, so regular REST is not enough.
Since we already have a Messenger handler written for use in different parts of the application, and a simple command object, we thought to use Messenger with an Input Object, as described in the documentation, that says:
Set the messenger attribute to input, and API Platform will automatically dispatch the given Input as a message instead of the Resource. Indeed, it'll add a default DataTransformer (see input/output documentation) that handles the given input
My resource is described thus:
App\Domain\Entity\Bid:
input: 'App\Application\Command\Lead\BidOnLead'
messenger: "input"
itemOperations:
get: ~
collectionOperations:
get: ~
post: ~
But, when I load the api-docs the schema I'm shown as input is the schema for App\Domain\Entity\Bid, not the schema for App\Application\Command\Lead\BidOnLead, as I would expect.
In case it was only a matter of the documentation being generated incorrectly, I've tried sending a JSON describing the input object (it's a very simple object with a couple of properties), but it fails because it's trying to deserialize into the resource object, not into the input object.
What I'm doing wrong, and how can I implement this?
I haven't tested this, but per documentation here:
https://api-platform.com/docs/core/messenger/#symfony-messenger-integration-cqrs-and-async-message-processing
input should be under attributes key:
App\Domain\Entity\Bid:
attributes:
input: 'App\Application\Command\Lead\BidOnLead'
messenger: "input"
itemOperations:
get: ~
collectionOperations:
get: ~
post: ~
It may be misleading if you just copying things from annotations to yaml as documentation for yaml is not thorough in ApiPlatform.

Change filename on custom monolog file

I use a rotating monolog handler
monolog:
channels: ['import']
handlers:
import_client:
level: debug
type: rotating_file
max_files: 10
path: '%kernel.logs_dir%/import.log'
channels: [import_client]
All works fine except I don't like the filename. I get import-2018-02-22.log.
Does it exist a way to change this format?
I would like the filename to be like import-"date(YmdHis)".log.
Is possible to rewrite the filename format? Did you have any solutions ?
I found the solution, need to add in config handler a new parameter :
date_format: 'YmdHms'
The RotatingFileHandler Logs records to a file and creates one logfile per day. It will also delete files older than $maxFiles. You should use logrotate for high profile setups though, this is just meant as a quick and dirty solution.
As you can see in the original RotatingFileHandler: you could possibly change the rotate dateformat
public function setFilenameFormat($filenameFormat, $dateFormat)
But I don't see any configuration option in the symfony monolog reference.
You could call a service using
services:
app.custom_rotating_service:
# ...
calls:
- method: setFilenameFormat
arguments:
- 'yourFilenameFormat'
- 'Ymd'
It seems to me you would get into soemthing complex for no added value of a date format.
TLDR
It's not possible to have a logfile By Hour/Minute with monolog
Changing Date format or the rotation frequency to months/year of the handler seems (to me) doable but not supported by the symfony monolog configuration. you could create a service and try to call the method automatically on service isntance creation
You should use logrotate if you have a custom need of rotating log

Categories