I’m aware I’m quite late in posting this, but hopefully it can help someone else out.
I’ve come across this problem before, and managed to come up with a solution, although my situation was a bit more complicated. I wanted users to be able to create or edit single-entry items, like you, except each item was to be paired with an already-existing entry. Basically, I wanted users to be able to enter hotel reservation information for company events, and be able to come back and edit or view their information after it was saved. A user could have reservation information for any number of company events, but for each event there should only be one reservation entry per user. My solution involved an outer template embedding an inner template and passing in the {url_title} variable, with the inner template set to execute PHP on input.
In your solution, though, you only need one entry for each user, period, so you only need one template, set to run PHP on input. This solution relies on a consistent naming scheme for each profile entry’s URL title. For example, ‘profile-USER_ID’, where USER_ID is the member ID number of the current user.
Note: the rather convoluted solution that follows would not be necessary if SafeCracker allowed a failed url_title lookup to degrade gracefully into a ‘create’ form. If so, you could just use this:
{exp:safecracker channel="member-profiles" url_title="profile-{member_id}" return="member-profiles/index"}
If the profile with the given URL title exists, it would become an edit form for the record; if not, it would become a create form. Unfortunately, if no record with the given URL title exists, SafeCracker shows an error message.
Here’s my code, altered to reflect your situation:
<?php
$profile_url_title = 'profile-' . $this->EE->session->userdata['member_id'];
$profile_exists = $this->EE->db->query('
SELECT
url_title
FROM
exp_channel_titles
WHERE
url_title = "' . $this->EE->db->escape_str($profile_url_title) . '"
')->num_rows() != 0;
?>
<?php if ($profile_exists) { ?>
{exp:safecracker channel="member-profiles" url_title="<?=$profile_url_title ?>" return="member-profiles/index" include_jquery="no"}
<?php } else { ?>
{exp:safecracker channel="member-profiles" return="member-profiles/index" include_jquery="no"}
<?php } ?>
{exp:member:custom_profile_data}
<input type='hidden' name='title' id='title' value='Profile for {first_name} {last_name}'></input>
<input type='hidden' name='url_title' id='url_title' value='profile-{member_id}'></input>
{/exp:member:custom_profile_data}
// Profile form…
{/exp:safecracker}
Because the template is set to execute PHP on Input, the results of the database query can be used to alter the SafeCracker form tag appropriately. Note that you should take care to prevent users from being able to directly view profile information, as simply changing the URL title or entry ID in the address bar would allow them to look at any member’s profile. Note that the “return=” parameter on the SafeCracker form does not use “ENTRY_ID”, it returns to /index, which I presume would be the template containing the above code; that’s up to the developer, of course.
If you’d rather shie away from raw database queries, you could use an outer template which would embed the template above.
Outer template:
{exp:channel:entries channel="member-profiles" url_title="profile-{member_id}"}
{if no_results}
{embed="member-profiles/.profile-form" profile_exists="no"}
{if:else}
{embed="member-profiles/.profile-form" profile_exists="yes"}
{/if}
{/exp:channel:entries}
In the inner template (member-profiles/.profile-form), just replace the database query with this:
$profile_exists = ("{embed:profile_exists}" == "yes");
The magic that makes this work is the fact that {embed} variables are parsed before Input-PHP is.
If you’d rather avoid PHP altogether, you could create two embeddable profile form templates, one for creating a record and one for updating.
Outer template:
{exp:channel:entries channel="member-profiles" url_title="profile-{member_id}"}
{if no_results}
{embed="member-profiles/.create-form"}
{if:else}
{embed="member-profiles/.update-form"}
{/if}
{/exp:channel:entries}
Create template: (member-profiles/.create-form)
{exp:safecracker channel="member-profiles" return="member-profiles/index" include_jquery="no"}
{exp:member:custom_profile_data}
<input type='hidden' name='title' id='title' value='Profile for {first_name} {last_name}'></input>
<input type='hidden' name='url_title' id='url_title' value='profile-{member_id}'></input>
{/exp:member:custom_profile_data}
// Profile form…
{/exp:safecracker}
Update template: (member-profiles/.update-form)
{exp:safecracker channel="member-profiles" url_title="profile-{member_id}" return="member-profiles/index" include_jquery="no"}
{exp:member:custom_profile_data}
<input type='hidden' name='title' id='title' value='Profile for {first_name} {last_name}'></input>
<input type='hidden' name='url_title' id='url_title' value='profile-{member_id}'></input>
{/exp:member:custom_profile_data}
// Profile form…
{/exp:safecracker}
None of the above solutions were actually tested by me, since my situation was different, but they should work.