Doctrine2 dynamic table prefix based on logged in user in Symfony2 - symfony

I am trying to get a multi-tenant system setup where each user has their own prefixed tables.
So my database might look like
users
acme_posts
my_posts
their_posts
our_posts
A solution like this is a good start, but it does not allow for the prefix to be dynamically created.
Is it possible to modify the doctrine solution above to set the database prefix based on the logged in user?
Another approach might be to have a main users database and then have separate databases for the user specific tables, but I am not sure if Doctrine can handle relationships between multiple databases.
All suggestions are welcome.

You can quite easily get access to the service container in a Doctrine EventListener like that, simply by defining the EventListener as a service (instructions located here). However, that approach won't help you for your situation, as all the class metadata will be loaded just once and cached, so it can't know about different users.
I don't know your use-case, obviously, but is there any reason that you can't simply add a field to your *_posts table, such that you have one posts table with "user_namespace" or similar as part of the key?
If your objection is simply to cluttering your controller logic with information about what user is logged in, you can simplify things by using a prePersist Doctrine EventListener to set the appropriate user_namespace on new entities, and either a Filter (for Doctrine >=2.2) or a custom DQL walker (for everything else) to restrict all your queries to only retrieve entities from the appropriate user_namespace.

Related

Symfony working with different entity managers

I want to create an application with some subsections like a blog and a forum for example. Now I want users to be able to create an account on my site, and with that account they can use the forum and the blog. That's easy so far. But I want to keep the tables in seperate databases to keep a nice and clean structure. Let's say I use 3 databases, one for the UserBundle, one for the BlogBundle and one for the ForumBundle. This requires 3 entity managers. But that means that I can't use relationships from entities from ForumBundle or BlogBundle to the user entity in UserBundle. Simply adding UserBundle under the mappings for the other managers will create new tables in the other databases and that's the thing I'm trying to avoid.
So, is there a way to make bundles 'aware' of entities in other bundles?
I know it technically isn't a good thing to make bundles dependent on other bundles, but how else would I acheive my idea?
One approach that has worked reasonably well for me is to query using the event system.
Assume you are in the Forum Bundle, you have retrieved a list of posts for a given thread and now you need the user information for each post. You make an array of user id's then:
$userIds = array(...list of users you need information for...);
$findUsersEvent = new FindUsersEvent($userIds);
$dispatcher->dispatch('FindUsers',$findUsersEvent);
$users = $findUsersEvent->getUsers();
So now I have a list of user information all nicely indexed by user id from which I can then pull additional information.
The only coupling between the Forum and User bundles is the FindUsersEvent class which could be in a common bundle of some sort. The forum bundles does not care how the users are loaded. The user bundle just needs a listener.
==================================================================
A second approach is to basically use a REST like api for grabbing user information.

Symfony2: how can I load a user taking into account its mapping entity?

Although I'm using Symfony 2.1 with FOSUserBundle and everything works perfectly, I don't know how I can resolve a problem.
Basically, I would like to know if there is a way to find (load or get) a user from the database taking into account a relationship with another entity.
This is the situation:
I have made that users can also login into my site thru a social network (Google, Facebook, LinkedIn, etc). I besides ask them for an offline access, so I can access their social accounts any time.
As each user can have as many connections as they want (or maybe none cause they are optionals), I've decided not to save this information in the user table. I've created an abstract entity called "SocialConnection" which is extended by the real ones (Google, Facebook, ect). In this entity I store the user information that I get when the user logs in my site thru those networks (user_id, social_id, access_token, etc), so in my User class I have mapped a collection of the abstract "SocialEngine" that allows me to have all networks together.
In order to be able to add others networks like Twitter, Yahoo and so on in the future, I think it is the way it should be.
So, the problem now is that when the user logs into my site thru any of these social networks I need to load him from the database knowing his social id, but I don't know how to do it.
I've seen that the method $this->findUserBy of UserManager find a user regarding a property but I think this is not the case.
What should I do to find a nice solution?
Thanks in advance.
Best regards,
Izzy.
To achieve this, you need to get deeper into doctrine's api. The base repositories methods (find, findBy etc...) won't be enough.
You need to use doctrine's DQL. It looks like SQL but you query based on your mapping metadata and not based on the database schema directly.
If your User has a OneToMany $socialAccounts property to the SocialEngine. You will be able to do something like:
SELECT u
FROM Bundle:User AS u
JOIN u.socialAccounts AS sa
WHERE sa.id = 34
But you can only query on SocialEngine's properties, not on the subclasses one ... (ie: You can't query on a SocialFacebookEngine's facebookId).
You either have to put all the twitter/facebook/etc data in the base SocialEngine class, on in the User class.
Or you could create an entity for each "Social Engine", and create a OneToOne relation relation between each of theses engines and the User.

ASP.NET Dynamic Data: Access rights only to specific rows

I want to use ASP.NET Dynamic Data for my next project, but there is a problem a can't manage to solve. In the database we manage authorization on a per-row basis. For example no user is permitted to see all rows of the Contracts table. So there is a Many to Many Relationship between Contracts and Users. So everytime Dynamic Data performs a Select to show all Contracts it has to look into the ContractUsers junction table to see what contracts the current user is permitted to see (filtered by UserID which will be stored in a session variable). Of course these junction tables should be invisible to the users.
By default Dynamic Data returns all rows of a table, so is it possible to customize this behaviour for every query the user performs?
I want to use Dynamic Data together with LINQ to SQL but if this task would much easier to accomplish using Entity Framework I would look into that too.
Thanks for your help and time.
Implementing such a solution in Dynamic Data it will probably require the creation of a custom Entity Template; not really easy but once done it will not require the creation of custom pages just the editing of the page templates.
I think it will be really usefull to check the excellent work on DD done by S.J.Naughton and presented on his blog.
Greetings, F.
You should not use dynamic data because you need full control over querying and manually write all linq queries to add your data level security. If you still insist on dynamic data be aware that you will still write most of pages yourselves and you will only use dynamic templates. You will have to manually define ever data source and correctly pass where condition to filter results based on logged user.
In addition linq-to-sql is not able to hide junction table and entity framework is able to do that only if junction table contains just two FKs for many-to-many relation. If this table contains any other column you want to use in the application you will have to map it as any other entity and dynamic data will show it as an entity.
Dynamic data are technology for quick creation of simple application where you need to provide access to database through web interface but what you describe is not a simple scenario. You need per record authorization which can differ among entity types.

ASP.NET Membership - A design for tracking additional information

I'm working on an ASP.NET4.0/C# application for a public site that needs to authenticate only the employees that work at the associated business. The idea is for the site to have a CMS such that employees can go in and make changes to certain content without having to work with any html.
My question relates to the design and use of a ASP.NET membership provider. I'm not trying to make the site work with an existing database, so there's no need to create my own MembershipProvider for that purpose. However, since each user is an employee, I want to track additional information such as name and office number. I can think of two readily apparent ways to accomplish this:
Use the default SqlMembershipProvider class. As a result, I would need to add the appropriate tables to my database and create a separate table for any "additional" information I want to store. This effectively creates a vertical partition on the user table, since I would use the asp.net-assigned userID as the primary key of the employee table as well. To retrieve the "additional" information, I could ask the provider for information about the current user and requery the database in the event I want to know anything else.
Create one table for all employee information (including login and password) and create my own custom MembershipProvider and MembershipUser classes with the functionality I desire.
I've also considered the use of profiles to store such information, however, the site will publicly contain employee listings, and these pages will need to access some of this information. As a result, I should probably cache this data and it seems like using the serialized fields that profiles provide would cause a problem.
Thus, purely in regards to design... would it be best to make a distinction between a user and an employee and use the default SqlMembershipProvider and associated tables, or write my own user tables that store the information I need and my own MembershipProvider for accessing that information?
If I understand your question correctly, you'd like to store additional user info within the ASP.NET Membership. I've created a number of sites using the following setup.
Install the default .NET Membership using the aspnet_regsql.exe tool
Create a UserProfile table with a uniqueidentifier (PK) UserID column that is linked via a foreign key to the aspnet_Users table
To access that information, all you need is the UserId of a particular User, then you can query your custom table for more information.
Microsoft has written an excellent post on how to do this.
Good luck!
M
I am doing something similar, using your option 1. Works great for me.
My business logic has some functions for mutating users. It knows when to touch my users table or the Membership functionality.
Using a custom MembershipProvider for this sort of thing will give you more work than you bargained for.
SQL Table profile provider (http://weblogs.asp.net/scottgu/archive/2006/01/10/435038.aspx ) will help you do just that.
You will get the power of the Profiles and on the same time not worry about caching or serialization since this provider stores the profile information in clear database table without any serialization. You can use them directly in your queries.

Use Multiple ASP.NET Role Providers Simultaneously

I'm developing an ASP.NET system that has two different 'tiers' of roles. The main tier will use Active Directory groups to determine membership, while the second tier will use a database. All users will have a tier-1 AD role, but not all users will have a tier-2 database role.
I know I can use the AspNetWindowsTokenRoleProvider to manage the AD roles, and I know I can use the SqlRoleProvider to manage the database roles... what I'd like to do is use both, simultaneously - is this possible?
I would recommend deriving from WindowsTokenRoleProvider, then overriding GetAllRoles, GetRolesForUser, etc.
Call the base class first, then append the appropriate list of roles from your database.
BTW, as the database key I'd recommend using the account SID (or a hash of it) instead of the DOMAIN\username string, since the username may change (marriage, etc.) and leave orphaned role entries. Happens more often than you expect :-(
Providers are built so as to be "pluggable" - in theory you can drop in whichever one you need and have it just work work. They are also documented so that you can extend the existing ones or use your own.
Basically therefore you want your own provider that will allow you to combine the two - to do this you can either, as suggested by #devstuff, inherit from one or other and then merge the results in overriden methods or you can create what is in effect a proxy class (there's probably a proper name for the pattern) that has instances of both the AD and SQL provider and passes the calls through and merges the results that way.
Fundamentally however the answer is to author your own provider combining the two stock providers to meet your specific requirement.

Resources