This isn't actually a task on Profile2, but I need a place to discuss this extension module.

Details to follow.

Comments

joachim’s picture

Profile2 creates profile entities, and several profile2 objects can be attached to a user. But Profile2 doesn't force the presence of a uid on its records.

This is where Profile Contacts comes in (or better name!) -- a separate contrib module which sits on top of Profile2.

Profile Contacts allows you to create a collection of profile objects that describes a person who is not a user.
What this needs to do:

- provide a UI to create contacts independently of users
- provide permissions for access to this UI.
- maintain a table to relate several profile IDs to contact IDs.
- use Drupal core hooks to associate a contact with a user when a user with a matching email address is created.

It was suggested at the BOF today that association with other types of (external) records would be a good thing too -- in other words, provide an API.

matt2000’s picture

Yes, it should be possible to associate a profile with any entity, so this implies a schema change for the profile table to (pid, name, entity_id, entity_type) where entity_type defaults to 'user', but can store any arbitrary string. This is the roughly same model as used by Voting API, and it's a good one, IMO.

matt2000’s picture

Also, I would suggest that matching contacts to users based on email may be a good default behavior, but ideally, there would be a UI that allows an admin to specify any arbitrary selection of fields as being appropriate to designate a 'match.'

But that's admittedly a scope creep that should not prevent a 1.0 release of the proposed extension, IMO.

joachim’s picture

> with any entity

Any entity? What, like taxonomy term? I think that's going beyond the scope of this. I do realize we're making a special case of a link between a user and a contact, but it's important enough for that.

> so this implies a schema change for the profile table to (pid, name, entity_id, entity_type) where entity_type defaults to 'user',

Sadly no. We can't justify that in Profile2 itself -- because it needs to be a candidate for Drupal 8 Core.

It's going to be a separate table with cid - pid(s).

matt2000’s picture

>Any entity? What, like taxonomy term?

Sure, why not? Here's a hypothetical use case: Imagine a site that exists to share academic research, and provides a taxonomy of universities. Later, someone gets the idea that the site should store some meta-data about these universities, like mailing addresses. And we've already got a user profile that stores mailing addresses, and some nifty custom code that helps us print envelope labels to send flyers for our annual conference. Someone could easily make a taxonomy_profile module that allows us to generically reusing the profiles without needing to care whether we're dealing with a user or not. And we can choose to do this with or without the overhead of a full-blown CRM application the depends on the existence of a Contact Entity that this example site may not have a need for. (or maybe this site started life in D6 before there was any such Contact Entity, and the costs of overhauling the taxonomy-based approach is too great.)

For conceptual reference, see also: http://en.wikipedia.org/wiki/Duck_typing

Of course, what I had in mind when said 'any entity' was something more along the lines of a 'Customer' or 'Order' entity in e-commerce module. But why should we artificially limit the use of the Profile Entity when it costs us nothing to open it up for creative, unforeseeable uses?

Or, why should we make a special case when we can make a general one? If a Profile is merely 'data about someone', why should we make assumptions about what kind of object represents that someone?

If there's a clear reason for forcing every module that wants to use profiles to create it's own intermediate table, I'm all for it, but lacking that clarity, my preference is to err on the side of the most generic approach that allows future developers to re-use components.

One last thing: without a common table, how would you do a query to the effect of "return all of the entities that use the 'foo' type profile" ? i.e., how can modules that extend profile2 know about the existence of other entities that might use profiles so as to provide options for filtering data or triggering profile-related actions based on entity type? Use case: maybe my email notifications action needs to be configurable to send a notification when foo data is collected for users and ducks but not contacts.

> We can't justify that in Profile2 itself -- because it needs to be a candidate for Drupal 8 Core.

Why would providing the means to efficiently handle Profiles in a generic way prevent it from being a candidate for core? I'm guessing the performance impact of a name--type--id unique index versus a simpler name--id index is negligible, but maybe I'm wrong. Is performance your concern, or is it something else I'm not seeing?

In summary, my thinking on this is driven by the 'entities are the new node' principle. Just as most modules that extend nodes should not care about node-type, modules that provide entities that interface with other entities ideally should not care about the type of those entities. Entities should make themselves available to any other entity that is smart enough to know how to ask for what they have to offer.

joachim’s picture

> Of course, what I had in mind when said 'any entity' was something more along the lines of a 'Customer' or 'Order' entity in e-commerce module. But why should we artificially limit the use of the Profile Entity when it costs us nothing to open it up for creative, unforeseeable uses?

Contacts provided by this module *are* customers in Drupal Commerce. That's the plan we've been discussing with Ryan.

> Someone could easily make a taxonomy_profile module that allows us to generically reusing the profiles without needing to care whether we're dealing with a user or not.

Just use an entity reference field.

> Why would providing the means to efficiently handle Profiles in a generic way prevent it from being a candidate for core? I'm guessing the performance impact of a name--type--id unique index versus a simpler name--id index is negligible, but maybe I'm wrong. Is performance your concern, or is it something else I'm not seeing?

See the long discussion about profile on FieldAPI in core. Basically, core does not want clutter it does not provide.

matt2000’s picture

>Contacts provided by this module *are* customers in Drupal Commerce.

Good to hear, I didn't know that had been decided.

I still think a generic approach to profile relationships is better, but not important enough to hinder an easy adoption by core.

joachim’s picture

> Good to hear, I didn't know that had been decided.

Not decided as such, but if profile2 + profile_contacts are ready pretty soon, then DrupalCommerce will use them.

Hence the need to get some coding done!

joachim’s picture

Title: extension modules: profile contacts » extension modules: profile_anonymous

Better module name.

And we're now thinking of building this on top of a relationship API module, so you could relate them to anything :)

that0n3guy’s picture

subscribe

joachim’s picture

Ah. This is now called Party, and I really need to upload the code I have so far, as I have zippo time to work on it at the moment.

that0n3guy’s picture

Through it up on github when you get a chance. I'd like to mess with this.

joachim’s picture

Done: https://github.com/joachim-n/party

It's very rough code, and there are lots of TODOs in the comments and bits that only produce test output (eg the party admin page says 'yay' ;)

As I say, I have no free time at all for the next few weeks, so feel free to fork it on github and mess around as much as you like! :D I should probably create a project page here so we have an issue queue too.

that0n3guy’s picture

Thanks Joachim. This will really be my first look at D7 coding. The whole entity thing is very interesting and I need to do some more reading on it. I'm used to the whole node stuff from D6 :).

that0n3guy’s picture

Ok, so after looking at this I'm confused. Party is its own entity. I thought party was just going to use profile2's entities and just create a UI for creating, editing, updating, viewing profile_types.

I can already create profile_types of "contact" or "organization", I just cant create "content" of those types as there is no UI besides when using it with a user. Why recreate this functionality with a whole new entity?

joachim’s picture

> Party is its own entity. I thought party was just going to use profile2's entities and just create a UI for creating, editing, updating, viewing profile_types.

It does use p2 entities.
But what binds together a collection of p2 entities into one user is the user object, and its user ID.

If you have no user, then you have no user ID. Hence the p2 entities have a 0 user ID, and you need something else to bind them. This is the party entity, which is pretty much empty apart from that (you can field it if you really want to, but I don't see why you would).

that0n3guy’s picture

I gotcha. I was thinking I would only have a singular profile per party (ie non-user). Your saying if I have multiple profiles that go with the same non-user party, that there is no way to associate the two.

I still don't really see that as a problem though. Couldn't we:

- add an anonuid column to the {profile} table. We would fill this w/ a partyid so that different profiles can still be associated w/ each other just like they would w/ uid. Then when the uid is filled, anonid is basically ignored. I understand you might not want this because they are trying to get profile2 into d8core, but it seems like a very simple solution.
- add our own partyid column in the {party} table. This would match the profile2 pid to the partyid allowing us to do that same thing as above.

Both of those still seem simpler than using our own entity that is basically doing exactly the same thing as profile2.

Is there anything wrong w/ doing either of those ways?

p.s. I started messing w/ some code, and doing a party module w/ out its own entity would be very similar to the profile2_page.module (I just copied most of that module). Instead of having the page be based on uid, its based on pid (ie: profile-contact/6... the 6 is pid not uid). Also don't have certain menu items unless uid !=null.

joachim’s picture

> - add an anonuid column to the {profile} table.

I did suggest profile2 do this, but since profile2 is a candidate for D8 core, it can't really go adding table columns it doesn't itself use. But yes, that *would* be the nice simple solution :/

> - add our own partyid column in the {party} table. This would match the profile2 pid to the partyid allowing us to do that same thing as above.

I don't follow you... the {party} table has a partyID. Somewhat confusingly, it's called 'pid', but that is partyID not profileID. This may cause confusion, and I did agonize over the name... Now would be a good time to change it painlessly!

joachim’s picture

Oh, there doesn't yet seem to be a table to store the partyID - profileID connection :/

I think I was waiting to see what relationship module would do :)

that0n3guy’s picture

Yeah, I was thinking we create a profileid column in the party db so that pid (partyid) can match up with a pid(profileid).... then no need for another entity.

Also, what relationship module are you talking about?

joachim’s picture

> Yeah, I was thinking we create a profileid column in the party db so that pid (partyid) can match up with a pid(profileid).... then no need for another entity.

Hmmyeah but they might as well be entities because then we get a whole host of things for free, such as admin UI and so on.

This is the module: http://drupal.org/project/relation

johnv’s picture

I am testing Profile2, after using core profile and Content Profile in D6.
At the moment it is not possible to create Profiles that are not attached to a user, like I did with Content Profile. Hence this issue..
May I suggest some changes to this module, which
- keep this module lean for core D8;
- let this module be the basis for Profile Anonymous.
I think most of it also recaps above discussion.
In Profile2:
- change fields profile-uid to profile-entity_id + profile-entity_type (an entity reference), so you can relate to 'any entity' (Orders, Universities, Terms, etc.)
In Profile Anonymous:
- Add a flag 'anonymous profiles possible' to the profile type. Setting this flag opens a UI, so you can:
-- create profiles via profile2/add/myprofile; the table 'profile' will only have fields profile-pid and profile-type set;
-- set the owner of the profile, setting the entity reference field in table 'profile'.

I'm no developer, but i am happy to test. In the meantime, I won't be using this module, but create my own content type 'profile'.

johnv’s picture

BTW, is this not the same as porting Content Profile to D7?
see #560324: Content profile: Create upgrade path to profile2 and port to Drupal 7

joachim’s picture

Not really -- content profile on D7 is about making nodes that wrap around profiles for existing users.

I did make a start on code for this module -- calling it party.module rather than profile_anonymous. It's still pretty rough and probably the APIs it uses have changed since I wrote it. But if there are people interested in taking it further I'll put up what I have so far :)

Shadlington’s picture

Subbing... Any progress on this?

joachim’s picture

Turns out my code for party.module is on github.

Feel free to grab it and start a project here with it as a starting point. It needs LOTS of work! :D