Position 1-1 Player of club => These should shows in an option List, but only Player of the club and not all!
If I select it in this function then, if I create a new position then the club id is not available as a field of the RF. On Update it functions!
function getPositionOptions () {
$RF =& $this->get('RF');
$id = $RF->getId('id'); => Hiere the object $RF is not available!
}
Has anyone a solution?
Thanks
Rainer Buhl
henk
2006-01-16 18:43:42
Hi Buhl,
I guess your problems are caused by the assumption of phpPeanuts that relationships are 1-n. This comes from the relational database model: If you normalize your data you will not have those 1-1 relationships. For this reason 1-1 relationships are rare, and to keep phpPeanuts simple it does not have defaults to support them. However, if you want to have 1-1 relationships anyway, you should be able to add specific code to make it work.
There are several ways to implement a 1-1 relationship, so to help you with this i need to know more detail about what you are trying to do. So let me check out if i fully understand you data model. Please correct me if i am wrong:
1. a Club has m players, a Player has only 1 club.
2. an RF has m positions, a Position has only 1 rF.
3. a Club has 1 rF and an RF has 1 club
4. a Position has 1 player and a Player has 1 club
Now here are some questions:
A. Is RF something you need in your database or is it just something that is to be in the user interface?
B. If RF needs to be in your database, are you sure there can only be one for each club? Or can/will there be another RF next year or so, for the same club?
C. If RF-Club is really 1-1, why did'nt you put the RF data into the Club table? (You can have two different presentations of the same object in the user interface if that is what you want)
D. If you do need two tables 1-1 related, where is the foreign key for the relationship: in RF or in Club? Or do you have two foreign keys, one at each side? (you need only one, but having two might help to make phpPeanuts do what you want it to do)
E, F, G and H: Same questions for Position and Player.
If you feel that answering these questions is a waste of your time, you can choose to send my your code, maybe i can read the details from there and infer what you want. The email adress is on the Contact page.
Greetings,
Henk Verhoeven.
Buhl
2006-01-17 07:04:39
Hello Henk,
thank you very much for your answer and your help.
The problem is easy to undestood:
A RF is there for every season and club, but it is not important for this problem.
I will guarantee that the user can choose for a RF position only a valid player of the players list of the club!
phpPeanuts support an option list for this requirement. But in this case not all players in the database should be can choose, but only the players of the club.
In the function "getPositionOptions ()" of the PntDBObject "RF position" I could select only the players of the club that are refer over the RF (Club->RF->RF position, Club->players). But this selection does not function when I am in insert modus (create a new RF position). In this case the the foreign key of RF in RF position is not available in the function "getPositionOptions ()" but in the user interface the RF is known an selected in the list! That is the problem. I solve this problem that I keep the RF id in the forwardRequest() of the siteobject and use it in the function "getPositionOptions ()" as key. But this solution in my opinion is not the final solution.
>>In this case the the foreign key of RF in RF position is not available in the function "getPositionOptions ()" but in the user interface the RF is known an selected in the list! <<
You are right, this is not nice. I will look into a generic solution for this limitation some time later.
For the moment i guess you best make a class <Type>EditDetalsPage as a subclass of ObjectEditDetailsPage and override the getRequestedObject method like this:
function &getRequestedObject() {
$obj =& $this->getRequestedObject();
if (isSet($this->requestData['mmbId'])
$obj->set('mmbId', $this->requestData['mmbId'] );
return $obj;
}
(<Type> needs to be replaced by the proper class name. With php5 you can omit the & signs and add public qualifier)
This gets the mmbId form value the user interface is using (i don't think it uses the pntContext) and sets it to the object that is edited.
NB becuase i do not really understand your data model the names of the properties may have to be different, but i guess you can figure those out youself.
Success,
Henk Verhoeven.
Buhl
2006-01-18 04:36:53
thank you very much, it functions very well and I understand much more about the framework. I have made only this little change.
function &getRequestedObject() {
// $mmb =& $this->getRequestedObject();
$mmb =& parent::getRequestedObject();
I need to make one remark: normally data from the request first needs to go through stripslashes, then through the [url=http://www.phppeanuts.org/site/index.php?pntType=HcodeClass&id=StringConverter]StringConverter[/url] to be converted to the proper datatype. Because mmbId is (i guess) an integer, you can bypass this, but if you want to get other datatypes from the request, you will probably have to add these extra steps.
Greetings,
Henk Verhoeven.
henk
2006-01-18 11:47:23
I also have been thinking about a generic solution (If you are not interested please ignore this message). There is a problem with that. What you are trying to do in generic terms is supply initial values to the new object. I could adapt the framework code to put initial values for all properties from the request on the object, including the steps for the stripslashes and the conversion from Strings. It would be OK to skip the [url=http://www.phppeanuts.org/site/index.php?pntType=Pagina&id=175]validation[/url] that is normally applied to user data because the data is supplied programmatically, errors that may be caused by bad values will be programming errors anyway.
The problem occurs when the user edits the new object and saves it with unaccpetable values. The same request parameters are then used to supply the values edited by the user to the [url=http://www.phppeanuts.org/site/index.php?pntType=HcodeClass&id=ObjectSaveAction]SaveAction[/url], and rejected by stringconversion, validation or an overridden [url=http://www.phppeanuts.org/site/index_php/HcodeMethod/pnt.db.PntDbObject::getSaveErrorMessages/getSaveErrorMessages.html]getSaveErrorMessages [/url] method. If if the framework puts inital values on the object there may be application code that relies on these values. If the framework uses the rejected values instead, user input may cause arbitrary runtime errors. If it doesn't, other errors may result from the missing initial values.
Conclusion: In case of rejection of user input the the original initial values must be supplied to the object that is shown in the page that comes after the rejection. Thus the originial initial values must be obtained at this stage, but currently there is no reliable way to do that (they are stored by the [url=http://www.phppeanuts.org/site/index.php?pntType=Pagina&id=180]Context Scouting[/url] mechanism, but not forever and i can not be sure about which footprint is the right one). I think the EditDetailsForm will have to get an extra parameter to supply these initial values to the SaveAction.
Of course this can be done, but it is not really simple. I think it makes sense that when the framework was developed this feature was not yet included. I will put it on the list as a nice thing to add in future. In the mean time specific solutions in the applications seem simple enough so it will nog have a very high priority. (If anyone disagrees please reply).
Greetings,
Henk Verhoeven.
matthijs
2006-06-10 12:19:12
> I could adapt the framework
> code to put initial values for all properties from the request
> on the object, including the steps for the stripslashes and the
> conversion from Strings. It would be OK to skip the
> validation that is normally applied to user data because the data is
> supplied programmatically, errors that may be caused by bad
> values will be programming errors anyway.
If you take the initial values from the request, should they not be checked anyway, since the user could also put these values in the request? Or will the values be put in the request programmatically internally?
> In the mean time specific
> solutions in the applications seem simple enough so it will nog
> have a very high priority. (If anyone disagrees please reply).
I'll see soon enough when I need this feature, can't really see the big picture yet right now.
Matthijs
henk
2006-06-12 11:54:49
Matthijs,
Generally, invalid data can cause problems for application code, but is not considered a security risk. (SQL injection and Email header injection should be prevented by the queryHandler and the email handler, buffer overflows should be prevented when at the place where the buffer is encapsulated).
With some request data the framework does extra checks, in particular the data from parameters that is used for including classes is checked by the PntRequestHandler::tryUseClass method.
However, it may be a good idea to have the framework protect application code from end users manipulating the request in general, and in an earlier stage. This could make life easyer for application developers. OTOH that would be of little use if the application developer does not handle his custom parameters the same way... I guess it's a good idea anyway, i will put it on the to do list.
What i have done for this particular purpose is to adapt PntObjectSaveAction pass the formtexts (sort of smart value holders fort request parameters) explicitly to the methods that process them. This makes it a lot easyer for the application developer to manipulate the order in which parameters are processed: He may override handleRequest, pass a first batch of formtexts to convertAndValidateFormValues, pass them to commitFormValues. If he then passes a second batch to convertAndValidateFormValues, the first batch of values will already have been validated and set on the object, so that both validation and derivation can use these values. This explicit passing will be included in next phpPeanuts version.
Thanks for the usefull reaction,
Henk Verhoeven
Add a Reply
Loading form, please wait
The website will not send you an e-mail when a reply is added to this topic
I have the follow entity relationship:
club 1-n player
club 1-1 registration Form for a saison (RF)
RF 1-n Position
Position 1-1 Player of club => These should shows in an option List, but only Player of the club and not all!
If I select it in this function then, if I create a new position then the club id is not available as a field of the RF. On Update it functions!
function getPositionOptions () {
$RF =& $this->get('RF');
$id = $RF->getId('id'); => Hiere the object $RF is not available!
}
Has anyone a solution?
Thanks
Rainer Buhl
I guess your problems are caused by the assumption of phpPeanuts that relationships are 1-n. This comes from the relational database model: If you normalize your data you will not have those 1-1 relationships. For this reason 1-1 relationships are rare, and to keep phpPeanuts simple it does not have defaults to support them. However, if you want to have 1-1 relationships anyway, you should be able to add specific code to make it work.
There are several ways to implement a 1-1 relationship, so to help you with this i need to know more detail about what you are trying to do. So let me check out if i fully understand you data model. Please correct me if i am wrong:
1. a Club has m players, a Player has only 1 club.
2. an RF has m positions, a Position has only 1 rF.
3. a Club has 1 rF and an RF has 1 club
4. a Position has 1 player and a Player has 1 club
Now here are some questions:
A. Is RF something you need in your database or is it just something that is to be in the user interface?
B. If RF needs to be in your database, are you sure there can only be one for each club? Or can/will there be another RF next year or so, for the same club?
C. If RF-Club is really 1-1, why did'nt you put the RF data into the Club table? (You can have two different presentations of the same object in the user interface if that is what you want)
D. If you do need two tables 1-1 related, where is the foreign key for the relationship: in RF or in Club? Or do you have two foreign keys, one at each side? (you need only one, but having two might help to make phpPeanuts do what you want it to do)
E, F, G and H: Same questions for Position and Player.
If you feel that answering these questions is a waste of your time, you can choose to send my your code, maybe i can read the details from there and infer what you want. The email adress is on the Contact page.
Greetings,
Henk Verhoeven.
thank you very much for your answer and your help.
The problem is easy to undestood:
A RF is there for every season and club, but it is not important for this problem.
I will guarantee that the user can choose for a RF position only a valid player of the players list of the club!
phpPeanuts support an option list for this requirement. But in this case not all players in the database should be can choose, but only the players of the club.
In the function "getPositionOptions ()" of the PntDBObject "RF position" I could select only the players of the club that are refer over the RF (Club->RF->RF position, Club->players). But this selection does not function when I am in insert modus (create a new RF position). In this case the the foreign key of RF in RF position is not available in the function "getPositionOptions ()" but in the user interface the RF is known an selected in the list! That is the problem. I solve this problem that I keep the RF id in the forwardRequest() of the siteobject and use it in the function "getPositionOptions ()" as key. But this solution in my opinion is not the final solution.
regards,
Rainer Buhl
Note: Mmb == RF ("Mmb" is german language)
class Site extends PntSite {
...
function setMmbId($id) {
$this->$mmbId = $id;
}
function getMmbId() {
return $this->$mmbId;
}
function forwardRequest(&$requestData, $information=null) {
if ( isset($requestData[pntContext])
&& substr_count ($requestData[pntContext] , 'Mmb*' ) == 1 ) { $teststring = $requestData[pntContext];
$id = intval (substr($teststring, strpos ($teststring , 'Mmb') + 4 ) ); $this->setMmbId($id);
}
parent::forwardRequest(&$requestData, $information);
}
}
You are right, this is not nice. I will look into a generic solution for this limitation some time later.
For the moment i guess you best make a class <Type>EditDetalsPage as a subclass of ObjectEditDetailsPage and override the getRequestedObject method like this:
function &getRequestedObject() {
$obj =& $this->getRequestedObject();
if (isSet($this->requestData['mmbId'])
$obj->set('mmbId', $this->requestData['mmbId'] );
return $obj;
}
(<Type> needs to be replaced by the proper class name. With php5 you can omit the & signs and add public qualifier)
This gets the mmbId form value the user interface is using (i don't think it uses the pntContext) and sets it to the object that is edited.
NB becuase i do not really understand your data model the names of the properties may have to be different, but i guess you can figure those out youself.
Success,
Henk Verhoeven.
function &getRequestedObject() {
// $mmb =& $this->getRequestedObject();
$mmb =& parent::getRequestedObject();
if ( isSet($this->requestData['mmbId']) ) {
$mmb->set('mmbId', $this->requestData['mmbId'] );
}
return $mmb;
}
Greetings,
Rainer Buhl
I need to make one remark: normally data from the request first needs to go through stripslashes, then through the [url=http://www.phppeanuts.org/site/index.php?pntType=HcodeClass&id=StringConverter]StringConverter[/url] to be converted to the proper datatype. Because mmbId is (i guess) an integer, you can bypass this, but if you want to get other datatypes from the request, you will probably have to add these extra steps.
Greetings,
Henk Verhoeven.
The problem occurs when the user edits the new object and saves it with unaccpetable values. The same request parameters are then used to supply the values edited by the user to the [url=http://www.phppeanuts.org/site/index.php?pntType=HcodeClass&id=ObjectSaveAction]SaveAction[/url], and rejected by stringconversion, validation or an overridden [url=http://www.phppeanuts.org/site/index_php/HcodeMethod/pnt.db.PntDbObject::getSaveErrorMessages/getSaveErrorMessages.html]getSaveErrorMessages [/url] method. If if the framework puts inital values on the object there may be application code that relies on these values. If the framework uses the rejected values instead, user input may cause arbitrary runtime errors. If it doesn't, other errors may result from the missing initial values.
Conclusion: In case of rejection of user input the the original initial values must be supplied to the object that is shown in the page that comes after the rejection. Thus the originial initial values must be obtained at this stage, but currently there is no reliable way to do that (they are stored by the [url=http://www.phppeanuts.org/site/index.php?pntType=Pagina&id=180]Context Scouting[/url] mechanism, but not forever and i can not be sure about which footprint is the right one). I think the EditDetailsForm will have to get an extra parameter to supply these initial values to the SaveAction.
Of course this can be done, but it is not really simple. I think it makes sense that when the framework was developed this feature was not yet included. I will put it on the list as a nice thing to add in future. In the mean time specific solutions in the applications seem simple enough so it will nog have a very high priority. (If anyone disagrees please reply).
Greetings,
Henk Verhoeven.
> code to put initial values for all properties from the request
> on the object, including the steps for the stripslashes and the
> conversion from Strings. It would be OK to skip the
> validation that is normally applied to user data because the data is
> supplied programmatically, errors that may be caused by bad
> values will be programming errors anyway.
If you take the initial values from the request, should they not be checked anyway, since the user could also put these values in the request? Or will the values be put in the request programmatically internally?
> In the mean time specific
> solutions in the applications seem simple enough so it will nog
> have a very high priority. (If anyone disagrees please reply).
I'll see soon enough when I need this feature, can't really see the big picture yet right now.
Matthijs
Generally, invalid data can cause problems for application code, but is not considered a security risk. (SQL injection and Email header injection should be prevented by the queryHandler and the email handler, buffer overflows should be prevented when at the place where the buffer is encapsulated).
With some request data the framework does extra checks, in particular the data from parameters that is used for including classes is checked by the PntRequestHandler::tryUseClass method.
However, it may be a good idea to have the framework protect application code from end users manipulating the request in general, and in an earlier stage. This could make life easyer for application developers. OTOH that would be of little use if the application developer does not handle his custom parameters the same way... I guess it's a good idea anyway, i will put it on the to do list.
What i have done for this particular purpose is to adapt PntObjectSaveAction pass the formtexts (sort of smart value holders fort request parameters) explicitly to the methods that process them. This makes it a lot easyer for the application developer to manipulate the order in which parameters are processed: He may override handleRequest, pass a first batch of formtexts to convertAndValidateFormValues, pass them to commitFormValues. If he then passes a second batch to convertAndValidateFormValues, the first batch of values will already have been validated and set on the object, so that both validation and derivation can use these values. This explicit passing will be included in next phpPeanuts version.
Thanks for the usefull reaction,
Henk Verhoeven