Property Type Configuration via XML/YAML - api-platform.com

I'm in a project and there is a POST endpoint that uses an Input Dto. However, by way of rules we don't use annotations in the properties of the classes, for that we use xml.
How can I define to which entity it should be deserialized via the configuration file?
<?php
class PersonInput {
/**
* #var Purchase[]
*/
public array $purchases;
}

Related

When using Spring R2DBC repositories can I provide my own custom R2dbcEntityTemplate?

I can make required tweaks via:
#EnableR2dbcRepositories(repositoryBaseClass = BaseRepo::class)
but this is too high level. Essentially I override top level method with custom behaviour which needs to be done at R2dbcEntityTemplate.class level so would be great if I could provide custom R2DBC teamplate. I tried declaring bean but it doesn't pick mine, predictably due to being hardcoded in:
/*
* (non-Javadoc)
* #see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryInformation)
*/
#Override
protected Object getTargetRepository(RepositoryInformation information) {
RelationalEntityInformation<?, ?> entityInformation = getEntityInformation(information.getDomainType(),
information);
return getTargetRepositoryViaReflection(information, entityInformation,
new R2dbcEntityTemplate(this.databaseClient, this.dataAccessStrategy), this.converter);
}
Instead of repositoryBaseClass, you can use
#EnableR2dbcRepositories(repositoryFactoryBeanClass = MyR2dbcRepositoryFactoryBean.class)
Then on your MyR2dbcRepositoryFactoryBean you can set your own R2dbcEntityTemplate use the method setEntityOperations

RepositoryConfigurationExtensionSupport => useRepositoryConfiguration => "Reactive Repositories are not supported by %s. Offending repository is %s!"

with org.springframework.boot update from 2.0.4.RELEASE to 2.0.5.RELEASE start to get exception:
RepositoryConfigurationExtensionSupport
=> useRepositoryConfiguration
=> InvalidDataAccessApiUsageException: "Reactive Repositories are not supported by %s. Offending repository is %s!"
what is the best/simplest Spring Data workaround for this? Could someone provide example? if it is possible without redefinition of #EnableJpaRepositories and JpaRepositoriesRegistrar...
This is solution, but I don't like it.. +3 new classes..
EnableXxxJpaRepositories is practically exact copy of EnableJpaRepositories..
EnableXxxJpaRepositories:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Inherited
#Import(XxxJpaRepositoriesRegistrar.class)
public #interface EnableXxxJpaRepositories {
/**
* Alias for the {#link #basePackages()} attribute. Allows for more concise annotation
* declarations e.g.: {#code #EnableXxxJpaRepositories("org.my.pkg")} instead of {#code
*
* #EnableXxxJpaRepositories(basePackages="org.my.pkg")}.
*/
String[] value() default {};
/**
* Base packages to scan for annotated components. {#link #value()} is an alias for (and mutually
* exclusive with) this attribute. Use {#link #basePackageClasses()} for a type-safe alternative
* to String-based package names.
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {#link #basePackages()} for specifying the packages to scan for
* annotated components. The package of each class specified will be scanned. Consider creating a
* special no-op marker class or interface in each package that serves no purpose other than being
* referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
/**
* Specifies which types are eligible for component scanning. Further narrows the set of candidate
* components from everything in {#link #basePackages()} to everything in the base packages that
* matches the given filter or filters.
*/
Filter[] includeFilters() default {};
/**
* Specifies which types are not eligible for component scanning.
*/
Filter[] excludeFilters() default {};
/**
* Returns the postfix to be used when looking up custom repository implementations. Defaults to
* {#literal Impl}. So for a repository named {#code PersonRepository} the corresponding
* implementation class will be looked up scanning for {#code PersonRepositoryImpl}.
*/
String repositoryImplementationPostfix() default "Impl";
/**
* Configures the location of where to find the Spring Data named queries properties file. Will
* default to {#code META-INF/jpa-named-queries.properties}.
*/
String namedQueriesLocation() default "";
/**
* Returns the key of the {#link QueryLookupStrategy} to be used for lookup queries for query
* methods. Defaults to {#link Key#CREATE_IF_NOT_FOUND}.
*/
Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;
/**
* Returns the {#link FactoryBean} class to be used for each repository instance. Defaults to
* {#link JpaRepositoryFactoryBean}.
*/
Class<?> repositoryFactoryBeanClass() default JpaRepositoryFactoryBean.class;
/**
* Configure the repository base class to be used to create repository proxies for this particular
* configuration.
*
* #since 1.9
*/
Class<?> repositoryBaseClass() default DefaultRepositoryBaseClass.class;
// JPA specific configuration
/**
* Configures the name of the {#link EntityManagerFactory} bean definition to be used to create
* repositories discovered through this annotation. Defaults to {#code entityManagerFactory}.
*/
String entityManagerFactoryRef() default "entityManagerFactory";
/**
* Configures the name of the {#link PlatformTransactionManager} bean definition to be used to
* create repositories discovered through this annotation. Defaults to {#code
* transactionManager}.
*/
String transactionManagerRef() default "transactionManager";
/**
* Configures whether nested repository-interfaces (e.g. defined as inner classes) should be
* discovered by the repositories infrastructure.
*/
boolean considerNestedRepositories() default false;
/**
* Configures whether to enable default transactions for Spring Data JPA repositories. Defaults to
* {#literal true}. If disabled, repositories must be used behind a facade that's configuring
* transactions (e.g. using Spring's annotation driven transaction facilities) or repository
* methods have to be used to demarcate transactions.
*
* #return whether to enable default transactions, defaults to {#literal true}.
*/
boolean enableDefaultTransactions() default true;
}
XxxJpaRepositoriesRegistrar:
#Configuration
public class XxxJpaRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
#Override
protected Class<? extends Annotation> getAnnotation() {
return EnableXxxJpaRepositories.class;
}
#Override
protected RepositoryConfigurationExtension getExtension() {
return new XxxJpaRepositoryConfigExtension();
}
}
XxxJpaRepositoryConfigExtension:
#Component
public class XxxJpaRepositoryConfigExtension extends JpaRepositoryConfigExtension {
#Override
protected boolean useRepositoryConfiguration(RepositoryMetadata metadata) {
//return super.useRepositoryConfiguration(metadata);
//return metadata.isReactiveRepository();
return true;
}
}

How to get underlying class name from Facade name in Laravel

I am finding it a bit difficult to understand Facades. Particularly how to find the underlying class name/location from a facade name. I have gone through the documentation but still not clear. For example, when using Auth::login()
, i found that there is no login() method in the Auth facade.
class Auth extends Facade
{
/**
* Get the registered name of the component.
*
* #return string
*/
protected static function getFacadeAccessor()
{
return 'auth';
}
/**
* Register the typical authentication routes for an application.
*
* #return void
*/
public static function routes()
{
static::$app->make('router')->auth();
}
}
The Auth facades getFacadeAccessor() method returns a string auth. But to which auth class should i be looking at? How to resolve the actual class?
Thanks,
You can use getFacadeRoot()
For example
$object = Auth::getFacadeRoot() // Illuminate\Auth\AuthManager instance
or to get the fully qualified class name
$class = get_class(Auth::getFacadeRoot()) // 'Illuminate\Auth\AuthManager'
Also you can use the container to resolve a class by it's accessor. This is what Laravel does under the hood when resolving a Facade.
$object = resolve('auth'); // Illuminate\Auth\AuthManager instance
Somewhere in a Serviceprovider the auth key is registered to something. For the auth key that's in vendor/laravel/frameworksrc/Illuminate/Auth/AuthServiceProvider.php. You can see that in the registerAuthenticator() method, the auth key is registered to the Illuminate\Auth\AuthManager with a singleton pattern.
The container has several ways to bind a key to a specific class. methods like bind and singleton for example. Facades are just an extra class to call the main class statically from the root namespace.
If you want to check out which class is used, you can use the following code: get_class(resolve('auth')). Ofcourse, you can replace auth with any string you want to check.
Bonus: I think you can override this behaviour by registering your own manager in some kind of way. I would advise you to extend the normal AuthManager and overwrite the methods that you want to see changed.
One option is to utilise the #see annotations on the facade
/**
* #see \Illuminate\Auth\AuthManager
* #see \Illuminate\Contracts\Auth\Factory
* #see \Illuminate\Contracts\Auth\Guard
* #see \Illuminate\Contracts\Auth\StatefulGuard
*/
class Auth extends Facade
Usually the method should exist on these classes/interfaces
For example, Auth::check() exists on \Illuminate\Contracts\Auth\Guard::check().
If you use an editor that allows you to follow through these definitions it can be a bit easier to traverse. Usually there's only one #see annotation so it's pretty easy to find the class.
You can use getFacadeRoot() on the package/service to get its object:
For example, I write a helper function to get Facade object so I can use that Cart object with ease from anywhere:
function cart() {
return \Gloudemans\Shoppingcart\Facades\Cart::getFacadeRoot();
}

Flex: BlazeDs deserialization

I'm working on a webapp built using Spring + Flex. Communication between front and back uses BlazeDS and I have a custom marshaller in order to serialize data from flex to backend as:
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://localhost:8080/${context.root.cpanel}/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<serialization>
<type-marshaller>es.onebox.flex.messaging.io.CustomTypeMarshaller</type-marshaller>
</serialization>
</properties>
</channel-definition>
Is there a way to configure how use a custom de-serializer from back to flex ? I need an interceptor to modify some fields of data sent from back to flex so I think this approach could work.
I've used an interceptor for Flex using:
<flex:message-interceptor ref="myMessageInterceptor"/>
And on my application.xml I've defined myMessageInterceptor as:
<bean id="myMessageInterceptor" class="es.onebox.flex.messaging.io.FlexInterceptor"/>
And this is de content of the interceptor:
public class FlexInterceptor implements ResourceHandlingMessageInterceptor
{
private static Logger logger = Logger.getLogger(FlexInterceptor.class);
public void afterCompletion(MessageProcessingContext context, Message inputMessage, Message outputMessage, Exception ex)
{
logger.info(inputMessage.getMessageId());
}
public Message postProcess(MessageProcessingContext context, Message inputMessage, Message outputMessage)
{
return outputMessage;
}
public Message preProcess(MessageProcessingContext context, Message inputMessage) {
return inputMessage;
}
}
In AMFEndpoint class [], there are fields
/**
* Returns the deserializer class name used by the endpoint.
*
* #return The deserializer class name used by the endpoint.
*/
#Override protected String getDeserializerClassName()
{
return "flex.messaging.io.amf.AmfMessageDeserializer";
}
/**
* Returns the serializer class name used by the endpoint.
*
* #return The serializer class name used by the endpoint.
*/
#Override protected String getSerializerClassName()
{
return "flex.messaging.io.amf.AmfMessageSerializer";
}
So I think you can extend the AMFendpoint and specify your own serializer/deserealizer and implement them, obviously. AmfMessageDeserializer source code is here:
http://opensource.adobe.com/svn/opensource/blazeds/branches/4.6_Apache/modules/core/src/flex/messaging/io/amf/AmfMessageDeserializer.java
Also I think if you want to change the messages sent from BlazeDS to Flex, you need to user Serializer rather than Deserializer.
Btw, downloading the whole source code for BlazeDS is pretty useful, you can add it to Eclipse and ctrl-click on classes and see the source with comments.

Is it correct to access entity manager in entity class (to ensure no duplicate username)

I want to ensure no duplicate username's when validating my entity
/**
* #var string $name
*
* #ORM\Column(name="name", type="string", length=32)
* #Assert\NotBlank();
* #Assert\Callback(methods={"isUniqueUsername"})
*/
private $name;
I suppose I need to use the Validator Callback. Then I will have to query database for users with that username, so I require entity manager? How do I access it? And access it "correctly"? Do I use a validator class instead? It seems quite troublesome to create a class just to validate 1 field?
In symfony2, there is a Unique validator you can use to ensure that a username, email address or any other field is unique. When using annotations, it works like this:
use Symfony\Bridge\Doctrine\Validator\Constraints as Unique;
/**
* #ORM\Entity
* #ORM\Table
* #Unique\UniqueEntity(fields={"email"},message="Your email is already registered")
*/
class User{
// ...
}
When trying to add a user through a form, you should get the message stated in the Unique annotation.
You shouldn't use the entity manager from within an entity - it breaks Separation of Concerns. Your entity class is a POPO (plain old PHP object) that should simply describe an entity - it should not be responsible for anything persistence related. If you need to run a custom query, do so either from a repository class, or a separate service. The repository class already has access to the entity manager. If you use a custom service, simply inject the entity manager into it.

Resources