Wednesday 29 April 2009 4:52:49 am
Hello everyone, first of all congratulations on the great software! I'm writing this post, to verify if what I am doing is the proper way of doing things, since I'm quite new to the open-source CMS systems, and ezpublish in particular. eZ Publish is 4.0.0 and the Forum is SMF http://www.simplemachines.org/
The goal is to have the same user/password for ezpublish and the forum application. Registrations are to be made only through ezpublish, and the user must be created on the forum automatically.
The site already has users, so I needed a way to 'export' them to the forum, and since the passwords are hashed, and SMF uses different algorithms for password hashing, I decided to export the user 'on-demand'. When the user log-ins to ezpublish, and enters his login/password information, I use them to create the new user in SMF. So, after reading through the documentations of both ezpublush and SMF, the ezpedia and searching this forum, i came up with the following:
1) Disable registration in the forum
2) "Intercept" user logins in ezpublish, and on successful login, create users in SMF (if they don't exist) 3) When user changes his password in ezpublish, update it in the forum and vice-versa.
<b>Part 1:</b> disabling registrations is quite simple, the forum supports this feature.
<b>Part 2</b>, the "intercept".
I created a login_handler, and used the code for the <i>loginUser()</i> method, from <i>eZUser</i> class.
only added few lines in it:
- to verify if user exists in the SMF's database and create it, if not
- log-in the user in SMF (all operations for SMF, are made using its API)
But to make this work, I need to make my login handler 'the default', so what i did was, to 'reset' the <i>LoginHandler</i> array in <i>site.ini.append.php</i>:
[UserSettings]
LoginHandler[]
LoginHandler[]=myloginhandler
Which works, until you click something in the admin interface, that changes the ini file (toggle debuging output for example), when you do that, when ezpublish regenerates the ini file, it does not save the part where I reset the handlers array, and so my handler is never called... Because of this, I guess it is not how its suppose to be done?
<b>Part 3</b>
- User edits his password.
following this: http://serwatka.net/en/blog/ez_publish_3_8_new_custom_edit_handler
I created a custom edit handler, but I needed the password the user entered, so I guessed that this information is only available in the <i>fetchInput()</i> method, which unfortunately is not discussed in that blog post.
By using the <i>eZDebug::writeDebug()</i> I came to the following: it will be simpler to just paste what i did:
function fetchInput( $http, &$module, &$class, $object, &$version, $contentObjectAttributes, $editVersion, $editLanguage, $fromLanguage )
{
$isValid=true; //flag to check if the user input is valid
$objId=0; // will hold the object ID of the 'ezuser' datatype
// only when Publishing class User
if($class->attribute('id')==4 AND $module->isCurrentAction('Publish'))
{
// iterate through all submitted attributes to check if all data is correct
// is this the proper way, or there is a single flag saying if all data is valid?
foreach($contentObjectAttributes AS $obj)
{
if($obj->hasValidationError())
{
$isValid=false;
break; // it's enough to have only 1 invalid attribute, to invalidate all input
}
if($obj->attribute("data_type_string")=="ezuser")
{
// this is needed to get the user and passwords from the POST
$objId = $obj->attribute('id');
}
}
// update the forum database, only if data is valid
if($isValid)
{
// saw this check from
// kernel/classes/datatypes/ezuser/ezusertype.php
// only instead of ContentObjectAttribute, there is a variable $base
// which here is not available.
if($http->hasPostVariable( "ContentObjectAttribute_data_user_login_" . $objId ) )
{
$login=$http->postVariable(
"ContentObjectAttribute_data_user_login_" . $objId );
$password=$http->postVariable(
"ContentObjectAttribute_data_user_password_" . $objId );
$passwordConfirm=$http->postVariable(
"ContentObjectAttribute_data_user_password_confirm_" . $objId );
$email=$http->postVariable(
"ContentObjectAttribute_data_user_email_" . $objId );
// here I include the forum's API file, and update the password
// ...
}
}
}
}
This works like a charm, the only thing, I'm not sure here, is about the iteration over the <i>$contentObjectAttributes</i> to check if they are all valid.
But... this handler is only called when user edits his profile, from the <i>content</i> module. The user module also provides it's own 2 interfaces that change passwords
<i>/user/password</i> and <i>/user/forgotpassword</i>
I will keep it short, here because this post is already too long...
What i did is, copied the user module from the kernel, into my extension, and edited the files for those views, then I used "URL wildcard translation", to make the <i>user/password/*</i> point to <i>myuser/password/{1}</i>. I also needed to set the correct permissions for the "password" function of my module. And that I think is all I need to keep the password information in sync with SMF, when changed from eZ Publish. Because of the problems with the order in which the login_handlers are called, I wonder if I should also 'override' the <i>/user/login</i> view, instead of using login_handler, for what I'm trying to do? Now comes the other part, updating passwords in eZ Publish, when changed from SMF. Creating and editing users in SMF within eZ Publish was quite easy, because their API is a single .php file, that you include and then call the functions.
How do I use the eZ Publish API now? The forum and eZ Publish installations are on the same server. Phew, that was longer than I expected, hope it makes sense... and thanks to anyone that read it :)
|