JMSSerializerBundle. no control over third party meta data - serialization

I have two entities I wish to serialize with the JMSSerializerBundle. The Music Entity has a mapping-file with exclusion_policy: NONE.
The Music entity has a field of the entity User from FOSUserBundle. The User entity has a mapping-file with exclusion_policy: ALL with a few fields set to expose: true, so they will be serialized.
The problem is, the User field gets fully serialized. It does not matter if I change the mapping-file of the User entity.
This is how it looks:
#My/Bundle/Resources/config/serializer/Entity.Music.yml
xxx\xxx\Entity\Music:
exclusion_policy: NONE
#My/Bundle/Resources/config/serializer/Entity.User.yml
xxx\xxx\Entity\User:
exclusion_policy: ALL
properties:
id:
expose: true
username:
expose: true
username_canonical:
exclude: true
email:
exclude: true
email_canonical:
exclude: true
enabled:
exclude: true
salt:
exclude: true
password:
exclude: true
last_login:
exclude: true
confirmation_token:
exclude: true
password_requested_at:
exclude: true
groups:
exclude: true
locked:
exclude: true
expired:
exclude: true
expires_at:
exclude: true
roles:
expose: true
credentials_expired:
exclude: true
credentials_expired_at:
exclude: true
Why does it not refer to it's own mapping file? Or am I mistaken somewhere?
What have I tried thusfar
I have read the third party meta data documentation. It simply says to add a new directory in my serializer service. I have done that, but I have to extend the FOS\UserBundle\Entity class, and that also does not have access to the parent protected fields I'm trying to exclude.

I bet xxx\xxx\Entity\User: refers to your own namespace and class.
If it is, it is the wrong way to do.
The rules must be applied to the class where the properties live.
Given the property you exposed in your configuration, I guess you're using FOSUserBundle.
Therefore, you must apply your rules on FOS\UserBundle\Model\User.
Then you need to add a JMSSerializer config to indicate where the serializer metadata live for the given namespace.
It should look like:
jms_serializer:
metadata:
auto_detection: true
directories:
FOSUserBundle:
namespace_prefix: "FOS\\UserBundle"
path: "#YourUserBundle/Resources/config/serializer/fos"
In fos/ directory you should have Model.User.yml
With something like:
FOS\UserBundle\Model\User:
exclusion_policy: ALL
properties:
id:
expose: true
groups: [list, details]
username:
expose: true
groups: [details]
email:
expose: true
groups: [me]
roles:
expose: true
groups: [details]
Details:
When applying rules to the Serializer through metadata, the Serializer looks for the property which are declared inside the class which is defined in the Metadata.
Example:
class Foo {
protected $foo;
}
class Bar extends Foo {
protected $bar;
}
Your metadata will look like this:
Foo:
exclusion_policy: ALL
properties:
foo:
expose: true
Bar:
exclusion_policy: ALL
properties:
bar:
expose: true
THE EXAMPLE BELOW IS NOT THE CORRECT WAY TO DO
Bar:
exclusion_policy: ALL
properties:
foo:
expose: true
bar:
expose: true
if you do this, only the rules on the property bar will be applied (and exposed).

I had this problem that I was getting the serializer in a wrong way. You need JMSSerializerBundle and use the service for configuration to take effect.
So instead of:
//In controller we can use $this instead of $container
$serializer = $this->get('jms_serializer'); //JMSSerializerBundle
I used:
$serializer = SerializerBuilder::create()->build(); //JMSSerializer
Using the first way will load your configuration. Since I'm using Propel, I needed to ignore all BaseObject fields:
#app/config.yml
jms_serializer:
metadata:
auto_detection: true
directories:
Propel:
namespace_prefix: ""
path: "#MySupporterBundle/Resources/config/serializer"
Note that BaseObject has no namespace and you need the following packages for this to work (bugged before metadata 1.2):
"jms/serializer": "0.12.*",
"jms/serializer-bundle" : "0.12.*#dev",
"jms/metadata" : "1.3.*",
So I made this file:
#My/SupporterBundle/Resources/config/serializer/BaseObject.yml
BaseObject:
exclusion_policy: ALL
and for specific objects(in Model namespace) you need files (with default namespace as My/OtherBundle):
My/OtherBundle/Resources/config/serializer/Model.om.BaseClass.yml
My/OtherBundle/Resources/config/serializer/Model.Class.yml
Note: You need to clear cache when creating new serializer files

Related

Adding Two Versions of Same API to Product in APIC

I am using IBM API Connect v5. We have an API with two different versions, 1.0.0 and 2.0.0. We have both APIs inside a single Product. From APIMgr we are able to stage and deploy the Product to Marketplace. However, when running CLI we get an error like the below:
"\u001b[31mError:\u001b[39m The Plan Default Plan refers to an API team-api:1.0.0 which is not present in the product."
The product yaml looks like the below
product: "1.0.0" info: name: "team-product" title: "Team Product"
version: "1.0.0" visibility: view:
enabled: true
type: "public"
tags: []
orgs: [] subscribe:
enabled: true
type: "authenticated"
tags: []
orgs: [] apis: team-api:
$ref: "team-api_1.0.0.yaml" team-api_1:
$ref: "team-api_2.0.0.yaml" plans: default:
title: "Default Plan"
description: "Default Plan"
approval: false
rate-limit:
hard-limit: false
value: "100/hour"
Does anyone know how to specify the APIs explicitly in the Product yaml file so that when running apic publish from CLI this error does not occur?
A Product can have many APIs (but remember, when you deploy a one version the second version will also be deployed! Accordingly, there will be downtime for both versions)
We have APIC v5 and use yaml like this:
product: 1.0.0
info:
name: test-datapower-product
title: Test-DataPower product
version: 1.0.0
visibility:
view:
enabled: true
type: public
tags: []
orgs: []
subscribe:
enabled: true
type: authenticated
tags: []
orgs: []
apis:
api-first-version:
id: 5f04285fe4b0e12ae4d9803f
api-second-version:
id: 5fb2b1aee4b0cab276cdafc1
plans:
default:
title: Default Plan
description: Default Plan
approval: false
rate-limit:
hard-limit: true
value: 100/hour

How to set provider.apiGateway.shouldStartNameWithService in a serverless.ts file?

I am kicking off a new project with a new Serverless TypeScript monorepo! Used the aws-nodejs-typescript template, which gave a serverless.ts config file. After some weeks, I am now getting the nice warning below from Serverless on command line:
Serverless: Deprecation warning: Starting with next major version, API Gateway naming will be changed from “{stage}-{service}” to “{service}-{stage}”.
Set “provider.apiGateway.shouldStartNameWithService” to “true” to adapt to the new behavior now.
More Info: https://www.serverless.com/framework/docs/deprecations/#AWS_API_GATEWAY_NAME_STARTING_WITH_SERVICE
Ok! Looks great, and I like the new naming. And since it’s a new project, better to apply the new naming now, before we release anything. However, it looks like the TypeScript definitions are rather strict, and do not seem to allow for the new variable yet:
Loading failed with: TSError: ⨯ Unable to compile TypeScript:
serverless.ts(44,7): error TS2322: Type ‘{ minimumCompressionSize: number; shouldStartNameWithService: true; }’ is not assignable to type ‘ApiGateway’.
Object literal may only specify known properties, and ‘shouldStartNameWithService’ does not exist in type ‘ApiGateway’.
awsProvider.d.ts(51, 9): The expected type comes from property ‘apiGateway’ which is declared here on type ‘Provider’
Is there a way to set the new property without reverting everything to YAML, which would be somewhat painful at this point?
Update 1
Many thanks to #NexGen for the pointer! Here is a minimal serverless.ts (emphasis on the TS!) showing the solution.
import type { Serverless, ApiGateway } from 'serverless/aws';
const serverlessConfiguration: Serverless = {
service: {
name: 'foo',
},
frameworkVersion: '2',
custom: {
webpack: {
webpackConfig: './webpack.config.js',
packager: 'yarn',
includeModules: true,
},
alerts: {
stages: ['stage', 'prod'],
definitions: {
functionErrors: { treatMissingData: 'notBreaching' },
},
alarms: ['functionErrors'],
},
},
package: {
individually: true,
},
plugins: [
'serverless-webpack',
'serverless-jest-plugin',
'serverless-plugin-aws-alerts',
],
provider: {
name: 'aws',
runtime: 'nodejs12.x',
region: 'us-west-2',
stage: "${opt:stage, 'dev'}",
apiGateway: {
minimumCompressionSize: 1024,
shouldStartNameWithService: true,
} as ApiGateway,
environment: {
AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
},
},
};
module.exports = serverlessConfiguration;
It is really simple to apply this change, all what you need to do is to add this to your serverless.yml file.
provider:
apiGateway:
shouldStartNameWithService: true
provider: {
name: 'aws',
runtime: 'nodejs12.x',
apiGateway: {
shouldStartNameWithService: true
} as ApiGateway,
stage: 'dev'
}

Symfony 3.4 JMS Serializer DoctrineObjectConstructor::__construct() expect ManagerRegistry, instance of Doctrine\Bundle\DoctrineBundle\Registry given

Please help me , I am stuck here. I have recently upgraded Symfony version from 2.8 to Symfony 3.4 LTS version. All works fine except the Rest API end point where I extend the Sonata\UserBundle\Controller\Api\UserController on my custom controller. When i run the API i get the following error
Type error: Argument 1 passed to JMS\Serializer\Construction\DoctrineObjectConstructor::__construct() must be an instance of Doctrine\Persistence\ManagerRegistry, instance of Doctrine\Bundle\DoctrineBundle\Registry given, called in /var/www/html/var/cache/dev/Container9bzqz8e/appDevDebugProjectContainer.php on line 3303
This started happening after the upgrade.
My Controller
use FOS\RestBundle\View\View;
use Sonata\UserBundle\Controller\Api\UserController as SonataUserController;
use League\Fractal\Manager;
use League\Fractal\Resource\Item;
class CustomerUserController extends SonataUserController {
protected $formFactory;
/**
* #var CustomerUserService
*/
private $customerUserService;
/**
* #var Manager
*/
private $fractal;
/**
* CustomerUserController constructor.
* #param UserManagerInterface $userManager
* #param FormFactory $formFactory
* #param CustomerUserService $customerUserService
* #param LoggerInterface $logger
* #param GroupManagerInterface $groupManager
*/
public function __construct(
UserManagerInterface $userManager,
FormFactory $formFactory,
CustomerUserService $customerUserService,
LoggerInterface $logger,
GroupManagerInterface $groupManager
) {
parent::__construct($userManager, $groupManager, $formFactory);
$this->formFactory = $formFactory;
$this->customerUserService = $customerUserService;
$this->fractal = new Manager();
$this->logger = $logger;
$this->fractal->setSerializer(new CleanCollectionArraySerializer());
}
/**
* Retrieves a specific CustomerUser
*
* #param integer $id
* #return array
*/
public function getUserAction($id)
{
/** #var User $user */
$user = parent::getUserAction($id);
$this->ensureUserIsCustomerUser($user);
$this->fractal->parseIncludes('customer');
$userObject = new Item($user, new UserTransformer());
return $this->fractal->createData($userObject)->toArray();
}}
Composer Info
I have added only relevant bundles
doctrine/annotations 1.10.3
doctrine/cache 1.10.2
doctrine/collections 1.6.6
doctrine/common v2.8.1
doctrine/data-fixtures 1.3.3
doctrine/dbal v2.6.3
doctrine/doctrine-bundle 1.10.3
doctrine/doctrine-cache-bundle 1.4.0
doctrine/doctrine-fixtures-bundle v2.4.1
doctrine/doctrine-migrations-bundle v1.3.2
doctrine/inflector 1.4.3
doctrine/instantiator 1.0.5
doctrine/lexer 1.2.1
doctrine/migrations v1.8.1
doctrine/orm v2.5.14
friendsofsymfony/rest-bundle 2.8.1
friendsofsymfony/user-bundle v2.1.2
jms-serializer/serializer 1.3.0
jms/metadata 1.7.0
jms/parser-lib 1.0.0
jms/serializer 1.14.1
jms/serializer-bundle 2.4.4
sonata-project/user-bundle 4.5.1
Config.yaml
jms_serializer:
metadata:
directories:
AppUserBundle:
namespace_prefix: "App\\UserBundle"
path: "#AppUserBundle/Resources/config/serializer"
SonataUserBundle:
namespace_prefix: "Sonata\\UserBundle"
path: "#AppUserBundle/Resources/config/serializer"
FOSUserBundle:
namespace_prefix: "FOS\\UserBundle"
path: "#AppUserBundle/Resources/config/serializer"
fos_rest:
param_fetcher_listener: true
body_listener: true
format_listener: true
view:
view_response_listener: 'force'
formats:
json: true
force_redirects:
html: true
json: true
routing_loader:
default_format: json
body_converter:
enabled: true
validate: true
disable_csrf_role: ROLE_API
exception:
enabled: true
messages:
'App\UserBundle\Controller\Api\Exception': true
Serlializer Entity.User.yaml file
Sonata\UserBundle\Model\User:
exclusion_policy: ALL
properties:
firstname:
expose: true
groups: [sonata_api_read, sonata_api_write]
lastname:
expose: true
groups: [sonata_api_read, sonata_api_write]
FOS\UserBundle\Model\User:
exclusion_policy: ALL
properties:
id:
expose: true
groups: [sonata_api_read, sonata_api_write]
username:
expose: true
skip_when_empty: true
groups: [sonata_api_read, sonata_api_write]
email:
expose: true
skip_when_empty: true
groups: [sonata_api_read, sonata_api_write]
enabled:
expose: true
groups: [sonata_api_read, sonata_api_write]
locked:
expose: true
groups: [sonata_api_read, sonata_api_write]
expired:
expose: true
groups: [sonata_api_read, sonata_api_write]
credentialsExpired:
expose: true
skip_when_empty: true
groups: [sonata_api_read, sonata_api_write]
Any help much appreciated.
I manage to resolve the issue by explicitly adding
"jms/serializer-bundle": "^1.0 | ^2.4"
in my composer.json file.
Hope this helps someone

filebeat add_fields processor with condition

I'd like to add a field "app" with the value "apache-access" to every line that is exported to Graylog by the Filebeat "apache" module.
The following configuration should add the field as I see a "event_dataset"="apache.access" field in Graylog but to does not do anything.
If I remove the condition, the "add_fields" processor does add a field though.
filebeat.inputs:
- type: log
enabled: false
paths:
- /var/log/*.log
filebeat.config.modules:
path: ${path.config}/modules.d/*.yml
reload.enabled: false
setup.template.settings:
index.number_of_shards: 1
setup.kibana:
output.logstash:
hosts: [ "localhost:5044" ]
processors:
- add_fields:
when:
equals:
event_dataset: "apache.access"
target: ""
fields:
app: "apache-access"
logging.level: info
For whatever reason the field is called "event.dataset" in filebeat but displayed as "event_dataset" in Graylog.

Codeception Content-disposition assert file

I want to assert a xls file. I get this back:
"attachment; filename="testify.xlsx""
How can I do assertions on the file?
I have the tmp Path from the $_SERVER['TMPDIR'] and a clean filename, but there is no file in directory.
There are no built-in methods for this purpose, you will have to write your own helper.
If you are using PhpBrowser or one of framework modules, they have two useful hidden methods:
_getResponseContent returns page(or file) content,
_savePageSource saves it to file.
So your helper method would look like this:
function seeXlsFileIsValid()
{
$fileContent = $this->getModule('PhpBrowser)->_getResponseContent();
$this->assertTrue(..., 'returned xls file is not valid');
}
If you want to assert response headers, copy seeHttpHeader method from REST module.
codeception.yml
actor: Tester
paths:
tests: tests
log: tests/_output
data: tests/_data
support: tests/_support
envs: tests/_envs
settings:
bootstrap: _bootstrap.php
colors: true
memory_limit: 1024M
shuffle: true
extensions:
enabled:
- Codeception\Extension\RunFailed
coverage:
enabled: true
c3_url: 'http://www-dev.testify.com:8080/c3.php'
remote: false
whitelist:
include:
- _php/*
api.suite.yml
class_name: ApiTester
modules:
enabled:
- PhpBrowser:
url: http://www-dev.testify.com:8080
clear_cookies: false
restart: false
curl:
CURLOPT_RETURNTRANSFER: true
- REST:
url: http://www-dev.testify.com:8080
depends: PhpBrowser
part: Json
- Asserts
- Helper\Api
- Db:
dsn: 'sqlite:tests/_output/database.sqlite'
user: ''
password: ''
env:
fast: