Question on the version of 8.
How to place entities in package for Doctrine? I have it not mapping to DB(
This is taken from a new document I've written on how to do this in V8:
http://documentation.concrete5.org/developers/packages/custom-database-tables-in-packages/including-doctrine-orm-entities-in-your-package-version-8-and-above
Standard Behavior
By default, entities in packages are provided in the following way:
Using the Annotation Driver, which loads database information from annotations provided directly in PHP code.
If the legacy \Src namespace is enabled in a package, which is the case if the package doesn't use any custom autoloaders, and supports concrete5 prior to version 8, then the entire packages/package_handle/src/ directory is scanned for entities and their annotations.
If the legacy \Src namespace is not enabled, then the class locations specified by $pkg->getPackageAutoloaderRegistries(), and any files found in packages/your_package/src/Concrete/Entity are scanned for entities.
This behavior can all be found in Concrete\Core\Database\EntityManager\Provider\DefaultPackageProvider, which is the default entity manager provider class used if another one isn't provided.
Annotation Driver Functionality
Much of the documentation found in the earlier Doctrine ORM package documentation is still accurate, with one large change:
If your package contains entity classes that use annotations, and the package requires version 8 or greater, you must include #ORM in your annotations. So instead of this:
<?php
namespace Concrete\Package\Statistics\Src\Entity;
/**
* #Entity
* #Table(name="StatisticsUserAgents")
*/
class UserAgent
{
/**
* #Id #Column(type="integer")
* #GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #Column(type="string")
*/
protected $value;
/**
* #Column(type="string")
*/
protected $hash;
}
You must import the ORM namespace, and preface all annotations with ORM:
<?php
namespace Concrete\Package\Statistics\Src\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* #ORM\Entity
* #ORM\Table(name="StatisticsUserAgents")
*/
class UserAgent
{
/**
* #ORM\Id #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string")
*/
protected $value;
/**
* #ORM\Column(type="string")
*/
protected $hash;
}
Why did we do this? Not just to make your life more difficult. Once the #ORM namespace is included, it makes it so that your Doctrine can do much, much more. For example, any packages that run on version 8 will be able to support Doctrine Extensions and more.
Customizable Behavior
It's easy to customize the behavior of the package entity manager. What can you do with a customizable entity manager configuration?
If you have one specific portion of your package that contains entities, and you don't want your entire package's code base scanned for entities, provide a custom package provider that points just to the spots in the filesystem that contain your entity classes.
Provide additional Doctrine types or extensions
Provide your entity information in alternate formats, like XML or YAML (instead of annotations in PHP classes.)
To customize the way your package configures the entities it provides, do one of the following
Make your package's controller implement the Concrete\Core\Database\EntityManager\Provider\ProviderAggregateInterface, which will be responsible for implementing the getEntityManagerProvider() method, which returns an object of the Concrete\Core\Database\EntityManager\Provider\ProviderInterface interface,
Make your package's controller implement the Concrete\Core\Database\EntityManager\Provider\ProviderInterface method, which which returns an array of Concrete\Core\Database\EntityManager\Driver\DriverInterface objects.
In both cases, you'll ultimately be providing at least one Concrete\Core\Database\EntityManager\Driver\DriverInterface object.
Example
Here's a simple example. Let's say you have a package that contains entities in the following locations:
Concrete\Package\YourPackage\Entity (which is automatically loaded by concrete5 from packages/src/your_package/Concrete/Entity)
PortlandLabs\Testing\Entity, which you have set up as a custom class location using $pkgAutoloaderRegistries:
protected $pkgAutoloaderRegistries = array(
'src/Testing' => '\PortlandLabs\Testing',
);
Instead of scanning all files found in packages/your_package/src/ (which is the default, standard behavior), you just want to load classes using the standard annotation driver from these two locations. First, modify your package controller so that it implements the ProviderAggregateInterface, and import the interface, as well as the StandardPackageProvider class:
use Concrete\Core\Database\EntityManager\Provider\ProviderAggregateInterface;
use Concrete\Core\Database\EntityManager\Provider\StandardPackageProvider;
class Controller extends Package implements ProviderAggregateInterface
Then, implement the provider class:
public function getEntityManagerProvider()
{
$provider = new StandardPackageProvider($this->app, $this, [
'src/Concrete/Entity' => 'Concrete\Package\YourPackage\Entity',
'src/Testing/Entity' => 'PortlandLabs\Testing\Entity'
]);
return $provider;
}
That's it! The standard package provider is a simple library that most classes that want to use annotated entities but load them from custom locations can use.
Other File Formats
Other classes exist to provide the entity definitions in different formats. Check out Concrete\Core\Database\EntityManager\Provider\YamlProvider and Concrete\Core\Database\EntityManager\Provider\XmlProvider if you want to provide your package entities in YAML or XML formats.
Related
I am using ASP.Net core with latest Automapper. This is related to this and this. I think I am doing what needs to be done according to those questions, but still I get below error from Automapper.
AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.
Mapping types:
ToDoDto -> CreateTodoCommand
Module.Todo.Domain.Dto.ToDoDto -> Module.Todo.Domain.Commands.CreateTodoCommand
at lambda_method19(Closure , ToDoDto , CreateTodoCommand , ResolutionContext )
I have an interface which will be implemented by classes that needs to participate in mappings.
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
But mapping classes can be in many assemblies since I have a plugin architecture. So, lot of stuff are being loaded dynamically by the host application. My Assembly locating method use below line to load Assembly in a loop until it finishes loading all modules.
AssemblyLoadContext.Default.LoadFromAssemblyPath(file.FullName); //file.FullName is full path to Dll like E:\Project\Modules\Module.Todo\bin\Module.Todo.dll
Once it's done I can see loaded assemblies in watch window
Above loading method gets called in ConfigureServices(). I know this should work because the same assembly collection is passed to MediatR services.AddMediatR(assemblies) as well as Automapper services.AddAutoMapper(assemblies);
MediatR scans and find all Commands etc. but Automapper fails to locate mappings from other assemblies. However Automapper loads profiles properly from directly linked assemblies via Assembly.GetExecutingAssembly().GetReferencedAssemblies()
What may be the problem?
I got my assemblies to load properly and setup the mappings to work by making my mappings by inheriting Profile class like
public class MyProfile:Profile
{
public MyProfile()
{
CreateMap<A,B>();
}
}
and not using
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
Say I have a web service / a REST resource that is called with some HTTP header parameters. The resource method builds a complex data object (currently a POJO) and eventually returns it to the client (via Gson as JSON, but that doesn't matter).
So I have this call hierarchy:
#Path(foo) ProjectResource #GET getProject()
-> new Project()
-> new List<Participant> which contains lots of new Participant()s
-> new Affiliation()
If I want the Affiliation object to be e.g. populated in English or German depending on a header parameter, I have to pass that as a parameter down the chain. I want to avoid having to do that. Maybe this is just fundamentally impossible, but it feels so wrong. All these objects only live inside the request, so wouldn't it be convenient to be able to access information tied to the request from anywhere?
I was hoping I could e.g. define a CDI #RequestScoped object that initialized itself (or gets populated by some WebFilter) and that I can then inject where I might need it.
But obviously that doesn't work from inside the POJOs, and I also had trouble getting hold of the headers from inside the request-scoped object.
I've read many SO questions/answers about EJBs and JAX-RS Context and CDI but I can't wrap my head around it.
Am I expecting too much? Is passing down the parameter really the preferred option?
If I understand what you need, you can try the following (just wrote this solution from the top of my head, but it should work):
Defining a class to store the data you need
Define a class annotated with #RequestScoped which will store the data you need:
#RequestScoped
public class RequestMetadata {
private Locale language;
// Default constructor, getters and setters ommited
}
Ensure you are using the #RequestScoped annotation from the javax.enterprise.context package.
Creating a request filter
Create a ContainerRequestFilter to populate the RequestMetadata:
#Provider
#PreMatching
public class RequestMetadataFilter implements ContainerRequestFilter {
#Inject
private RequestMetadata requestMetadata;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
requestMetadata.setLanguage(requestContext.getLanguage());
}
}
Performing the injection
And then you can finally perform the injection of the RequestMetadata using #Inject:
#Stateless
public class Foo {
#Inject
private RequestMetadata requestMetadata;
...
}
Please, be aware that anywhere is too broad: The injection will work into beans managed by the container, such as servlets, JAX-RS classes, EJB and CDI beans, for example.
You won't be able to perform injections into beans created by yourself neither into JPA entities.
How can I use EL to specify trace listeners and formatters for only one subsystem (say, DLL) of a large system?
I'm writing a sub-module of a very large large application (thick client, not web app) that uses a gateway/portal model to load its various subsystems. I'd like use EL 5.0 (already in use) to manage logging/tracing configuration, but just for my subsystem. It looks like app.config is getting converted by VS to foo.dll.config. Can I convince EL to pick up the settings in foo.dll.config (at run-time) and merge them into its existing configuration data, in memory? (Not into a merged config file.)
(Looks like, based on Enterprise Library Class Library App.Config, it can't be done.)
I wouldn't recommend trying to merge configuration -- it can can get messy.
Instead, I would configure your sub-module to configure and use private references to the appropriate Enterprise Library objects you need.
I'm assuming your module is a class library that has an app.config. When compiled it generates a module.dll.config file in the output directory. To take an example of logging using Enterprise Library 6, I would create a helper class to load your own configuration and maintain a reference to your module's LogWriter. In this way your module loads its own configuration and does not interfere and is not influenced by other configuration in the application.
namespace MyModule
{
public class MyModuleClass
{
public void DoSomething()
{
MyModuleLogger.LogWriter.Write("MyModule Test", "General");
}
}
public static class MyModuleLogger
{
private static Lazy<LogWriter> logWriter = new Lazy<LogWriter>(() =>
{
FileConfigurationSource configSource =
new FileConfigurationSource("MyModule.dll.config");
LogWriterFactory factory = new LogWriterFactory(configSource);
return factory.Create();
});
public static LogWriter LogWriter
{
get { return logWriter.Value; }
}
}
}
I've used a static class but you could use a variety of approaches that may fit with your design (singleton, factory, etc.)
You will have to ensure that your dll.config file is deployed along with your assembly. You could also hit problems if there are version issues with Enterprise Library (e.g. you are using Version 6 while the application uses Version 5.)
I'm trying to register to implementations of same interface using named instances
kernel.Bind<IRepository>().To<CachedRepository>().InSingletonScope();
kernel.Bind<IRepository>().To<DbRepository>().InSingletonScope().Named("db");
the idea, is that if I not specify the name then the CachedRepository gets created, if I need a DB oriented one then I'd use the Named attribute, but this miserable fails when a simple object would get created
public class TripManagerController : Controller
{
[Inject]
public IRepository Repository { get; set; } // default Cached repo must be created
public TripManagerController()
{
ViewBag.LogedEmail = "test#test.com";
}
}
the error is
Error activating IRepository More than one matching bindings are
available. Activation path: 2) Injection of dependency IRepository
into parameter repository of constructor of type TripManagerController
1) Request for TripManagerController
Suggestions: 1) Ensure that you have defined a binding for
IRepository only once.
Is there a way to achieve what I want without creating a new interface for BD oriented repositories?
Thx
The [Named] attribute as shown in the wiki should work.
BTW stay away from anything other than ctor injection!
It would seem you cannot do what you're trying, I've just come across the same issue and as well as finding your question I also found this one where the author of Ninject Remo Gloor replied.
https://stackoverflow.com/a/4051391/495964
While Remo didn't explicitly say it couldn't be done his answer was to name both bindings (or use custom attribute binding, amounting the same thing).
In Kohana 3, how can I override/extend a module class?
E.g. I want to add functionality to the Auth module that is specific to my application. In this case I want to extend the abstract Auth class located in the classes folder of the Auth module.
What naming convention should I use for my Auth class and where in the file system do I place my class file?
To solve this issue it's important to understand the hierarchical nature of the Kohana 3 framework. When it comes to overriding or extending modules you need to do the following.
Let's extend the Auth module. When you look at the Auth module file system structure you notice that in the classes directory there is a file called auth.php. When you open this file you see the following:
<?php defined('SYSPATH') OR die('No direct access allowed.');
abstract class Auth extends Kohana_Auth { }
Here an abstract class named Auth is defined which is extending the Kohana_Auth class. When you use any references to the Auth class in your application you're referring to this abstract class. The actual implementation of Auth is actually kept in the Kohana_Auth class which is located in the Kohana folder which part of the module directory structure.
To extend the Auth module, i.e. add your own functionality, you simply place an auth.php file in the classes folder of your application directory. In your auth.php file you extend your version of the Auth module by extending the Kohana_Auth class. Like so:
<?php defined('SYSPATH') OR die('No direct access allowed.');
class Auth extends Kohana_Auth {
public function get_user()
{
$result = parent::get_user()
// implement your functionality here.
return $result;
}
public function my_added_functionality()
{
}
}
Because of the hierarchical nature of the framework, the abstract class Auth defined as part of the module will never be loaded because the framework loads your Auth class first because it takes precedence. The class you extend, Kohana_Auth, provides all the auth original functionality you can no extent and/or override.
For more information on the behavior checkout this part of the documentation.