Skip to content

Instantly share code, notes, and snippets.

@yjeroen
Created January 7, 2012 14:33
Show Gist options
  • Save yjeroen/1574900 to your computer and use it in GitHub Desktop.
Save yjeroen/1574900 to your computer and use it in GitHub Desktop.
class foo extends CActiveRecord
class User extends foo
class Post extends foo
userController User Post
========== === ===
{
function actionThatAddsUserAndPosts
{
$userModel = new User;
$userModel->save()
{
$relatedToUser = new Post
$relatedToUser->save()
{
stuff
}
stuff
}
stuff
}
}
@yjeroen
Copy link
Author

yjeroen commented Jan 7, 2012

[15:23] <tom[]> yjeroen: so the scenario we are worried about is...
[15:23] <tom[]> controller calls foo::save()
[15:24] <tom[]> foo::save() calls foo::save() ?
[15:24] yes, foo::save() calls relatedSave() (in my case), relatedSave() can call save() again in some cases to save a related model
[15:25] == csalvato [~csalvato@c-98-202-67-16.hsd1.ut.comcast.net] has quit [.net .split]
[15:25] == Sil4nc4 [raelter@bluestar.aelter.be] has quit [
.net *.split]
[15:25] foo::save() need to use transactions internally, but it should not be affected if a transaction is already started in the controller
[15:25] == csalvato [~csalvato@c-98-202-67-16.hsd1.ut.comcast.net] has joined #yii
[15:25] == Sil4nc4 [raelter@bluestar.aelter.be] has joined #yii
[15:25] == rookie84 [779a2641@gateway/web/freenode/session] has joined #yii
[15:25] <tom[]> in oop, are we allowed to say "call" or do we have to say "invoke"?
[15:26] pff, teach me
[15:26] == rookie84 [779a2641@gateway/web/freenode/session] has quit [Changing host]
[15:26] == rookie84 [779a2641@gateway/web/freenode/ip.119.154.38.65] has joined #yii
[15:26] hi tom, yjeroen
[15:26] I have no idea whats the right usage/wording
[15:27] hi rookie
[15:29] tom[], correct me if Im wrong.. If I think about it: I think you call it "calling a method" if you call it outside its class, and invoking if you call a method inside its own class?
[15:30] I have no idea on the precise right terminology
[15:30] <tom[]> yjeroen: https://gist.github.com/1574882
[15:30] <tom[]> i remember when people were inventing oop and the struggle they had to find terminology
[15:31] <tom[]> so can we use that diagram as a model? does it suffice?
[15:31] how old are you tom[], if i may ask?
[15:31] <tom[]> me 47
[15:31] in your diagram, are foo, bar and CAR instances of a class, or different classes?
[15:31] <tom[]> and my mother taught me to program computers
[15:32] <tom[]> yjeroen: sure
[15:32] hmm then your probably 27 :p
[15:32] sure, which? :P
[15:33] <tom[]> lets say for now that the are both instances of Baz
[15:34] <tom[]> my mother was a peofessional programmer in the 1960s
[15:35] ill change it around and make the classname foo, so its the same as in the other code discussion
[15:35] ill fork your github
[15:35] <tom[]> no need
[15:35] <tom[]> it's justa diagram
[15:36] <tom[]> whiteboard
[15:36] !api Yii::setPathOfAlias
[15:36] Yii::setPathOfAlias() Create a path alias. http://www.yiiframework.com/doc/api/1.1/YiiBase#setPathOfAlias-detail
[15:36] <tom[]> blacknoard
[15:37] <tom[]> rookie84: and my fatehr taught me to build computers with this kit: http://www.nascomhomepage.com/
[15:37] Can path be relative? Getting bullshit that the file can't be found
[15:37] tom[]: how are you doing?
[15:37] I am currently migrating the 1.1.9 documentation
[15:38] <tom[]> swell!
[15:38] <tom[]> you?
[15:38] and I am going to migrate the return value the signature and the source link of the methodsw
[15:39] <tom[]> brilliant!
[15:39] tom[]: was she a designer or weaver?
[15:40] <tom[]> it involved both back then
[15:40] tom[] thats great ! :)
[15:40] <tom[]> to edit a punhed paper tape involved sticky tape and a small hand-held hole punch
[15:41] http://www.youtube.com/watch?v=P12r8DKHsak
[15:41] <tom[]> the day the tape reader was upgraded from a mechanical device to an optical one caused trouble because my mother had been using transparent sticky tape.
[15:42] tom[]: mom is still alive?
[15:42] <tom[]> sadly not.
[15:42] Since when is 255, 255, 255 black?
[15:42] sorry to hear that
[15:43] <tom[]> yeah. lymphoma. too young
[15:44] tom[], I think the diagram would be like this: https://gist.github.com/1574900
[15:44] <tom[]> great
[15:45] yjeroen: WOW ! thanks :) I managed to fix it:) both submitting the form and showing a success message! :) yey
[15:46] Sampa: great! :)
[15:46] <tom[]> we have to allow for either User or Post to either A: return false on detection of validation error or B: throw an exception?
[15:46] tom[], i forgot to add the parent::save()'s
[15:46] Is there something like Yii 2 in the works?
[15:46] <tom[]> !faq yii2
[15:46] People here know nothing about the status of Yii 2, its features, release schedule or degree of backwards compatibility. But they have confidence in one thing: the uncertainty in when Yii 2 will be ready for production use is big. They do not recommend you wait for it. Use the current version of 1.1.
[15:47] !faq yii1.2
[15:47] Something i do not know about.
[15:47] Ah, bot fail
[15:47] tom[], if either User or Posts doesnt validate, then the User needs to return false to the controller (with all val errors)
[15:47] but
[15:47] <tom[]> there's some info here:http://www.yiiframework.com/download/ and here: http://www.yiiframework.com/forum/index.php?/forum/42-design-discussions-for-yii-20/
[15:48] if a transaction is started outside the foo::save (ie in the controller), then User needs to rethrow the exception
[15:49] <tom[]> hold on
[15:49] <tom[]> we haven't got any exceptions yet
[15:49] <tom[]> one step at a time
[15:50] ok
[15:50] want me to add other stuff? or you want to go first?
[15:50] <tom[]> let's focus on Post::save
[15:50] <tom[]> sqy it detects that an exception IS active
[15:50] <tom[]> say

[15:51] an exception or a validation error?
[15:51] <tom[]> nonsense
[15:51] <tom[]> saw Post::save() detects that a transaction is already active
[15:51] <tom[]> *say
[15:51] <tom[]> damn my triping
[15:52] Post::save WILL detect that the transaction is active, because User::save started it
[15:52] == adlersd_ [~adlersd@189.29.69.203] has joined #yii
[15:53] <tom[]> if that is known to always be the case then there is no need for detection logic
[15:53] sure it is, because the save code is inside foo, not inside Post
[15:54] <tom[]> three outcomes: 1 happy. 2: validation error but Post::save knows it hasn't touched the DB state and 3: an exception is thown while it touches the DB
[15:55] yes thats true
[15:55] == adlersd [~adlersd@189.29.69.203] has quit [Ping timeout: 248 seconds]
[15:55] <tom[]> [that's not a need for detection logic. that's cruft leftover from the design.]
[15:56] <tom[]> [but no matter]
[15:56] <tom[]> [makes no difference for now]
[15:56] [ok]
[15:57] <tom[]> take 3 first
[15:57] <tom[]> an exception comes up from CAR in Post's try{}
[15:57] <tom[]> it's catch re-throws it
[15:57] <tom[]> right?
[15:58] whats CAR?
[15:58] <tom[]> CActiveRecord
[15:58] ah yes
[15:58] i thought the one that drives
[15:58] == freeayu [~quassel@115.172.207.134] has quit [Ping timeout: 240 seconds]
[15:59] i agree it should rethrow
[15:59] <tom[]> it has no sensible alternative
[16:00] But only in case #3 should it rethrow
[16:00] <tom[]> this is happening inside User::save()'s try{}
[16:01] <tom[]> and when this exception is caught by User's catch there are two possible cases, either Post owns a transaction or it does not.
[16:01] yes
[16:02] i dont understand what you mean by that last part
[16:02] <tom[]> Post throw an exception
[16:02] <tom[]> so we are now in User's catch
[16:02] <tom[]> OK?
[16:02] yes
[16:03] <tom[]> and User may or may not have begin a transaction
[16:03] yes
[16:04] <tom[]> if it did, it rolls it back. otherwise it must re-throw
[16:05] clear
[16:06] <tom[]> so we have covered the design in so far as handling exceptions that must lead to rollback
[16:06] That was all of case 3 right?
[16:06] <tom[]> yes
[16:06] so now case 2, rollback if any model isnt validated
[16:06] <tom[]> hold on
[16:06] <tom[]> summarize
[16:06] <tom[]> we have a simple nesting
[16:07] <tom[]> we could recurs this nesting as far as the stack is deep
[16:07] Yes, this would be the simple if($transaction) rollback else rethrow
[16:07] <tom[]> and all we need is local method variables and the connection's transaction state variables
[16:08] agreed
[16:08] <tom[]> good. i think we can now also say that case 1 is covered
[16:08] you mean case 3? case 1 was the happy case
[16:08] <tom[]> "also"
[16:09] What VCS do you guys use?
[16:09] oh also
[16:09] yes oc :)
[16:10] <tom[]> now about validation errors. inside a try{} somewhere in the chain of calls something detects a validation error and decides it cannot proceed. it hasn't touched the DB so it returns false insteaad of throwing anything
[16:11] yes, but because we call multiple saves, it still needs a rollback
[16:11] <tom[]> what it?
[16:11] <tom[]> you move too fast for me
[16:11] ah sorry
[16:11] lets save CAR::save in Post doesnt validate
[16:12] then Post isnt saved
[16:12] <tom[]> if Post returns false, it is saying that as far as Post is concerned, there is no need for a rollback
[16:12] but User is, because that validated true
[16:12] <tom[]> it is then up to User to decide if it knows if a rollback is needed
[16:13] so User needs to rollback if Post:save is false
[16:13] <tom[]> think generally:
[16:14] <tom[]> we would prefer to find a design pattern, not just a design
[16:15] == xwurf [b2bed15a@gateway/web/freenode/ip.178.190.209.90] has quit [Quit: Page closed]
[16:15] <tom[]> if, when user receives the false return from Post it has touched the DB state, it must throw. if not, it should return false
[16:15] <tom[]> u=>U
[16:16] huh? If Post returns false, then it wouldnt have touched the DB state right?
[16:17] <tom[]> if Post returned false that Post is saying that it did not touch the DB
[16:17] it = Post
[16:17] yea
[16:17] <tom[]> but in general, in the caller of Post, at that point, that caller may or may not have touched the DB
[16:18] <tom[]> in this scenario the caller is User
[16:18] yes
[16:18] <tom[]> in your diagram User has not touched the DB before calling Post::save()
[16:19] <tom[]> but that's just one of the two cases
[16:19] <tom[]> in general, User shoudl return false if it hasn't touched the DB and should throw if it has
[16:20] The fact that Post->getErrors need to be send to User as well, do you want to include that now or later?
[16:20] <tom[]> once you have said OK
[16:21] ok, i agree on that as well
[16:21] <tom[]> swell
[16:22] <tom[]> so in regard to all the flow control we have discussed so far, User is the same as Post
[16:22] <tom[]> they are instances of the same thing
[16:22] yes
[16:22] <tom[]> i still don't see any call for state other than method-locals
[16:23] <tom[]> as far as passing validation errors up is concerned...
[16:23] <tom[]> imagine that we didn't need any transactional logic. that none of that was important to the application
[16:23] <tom[]> hypothetically
[16:24] what do you mean by transactional logic
[16:24] <tom[]> what would imagine that transactions didn't exist
[16:24] <tom[]> that you had never heard of them
[16:24] oh , yes
[16:24] <tom[]> becuase they weren't invented
[16:25] Then User could be saved, while Post would not. Or the other way around
[16:25] <tom[]> now, how would User pass validation error messages from Post up to contrller?
[16:25] <tom[]> forget about that stuff
[16:25] <tom[]> forget about databases for a moment
[16:26] <tom[]> how would User pass validation error messages from Post up to controller?
[16:26] The controller looks for errors in the User model.
[16:27] <tom[]> and would find Post validation errors in it?
[16:27] so the errors in the User model must also include the list of errors of the Post model
[16:27] yes
[16:27] <tom[]> does User need to do anything to achive this?
[16:27] <tom[]> or does Yii handle it?
[16:28] yii handles the part that the view displays the errors of the User model (because its userController)
[16:29] What I do now is:
[16:30] if(!Post->save()) $this->addError($post->errors())
[16:30] == erez_ [2e791f53@gateway/web/freenode/ip.46.121.31.83] has quit [Ping timeout: 258 seconds]
[16:31] if(!$post->save()) $this->addError($post->errors())
[16:32] <tom[]> if(!$post->save()) { $this->addError($post->errors()); return false; }
[16:32] Ok, agreed
[16:33] <tom[]> hot diggity
[16:33] <tom[]> we got ourselves a design pattern!
[16:33] <tom[]> ditch the behavior
[16:33] And I see where my thoughts went the wrong way!
[16:33] wait
[16:33] hmm
[16:33] <tom[]> oh no
[16:34] <tom[]> it's the "no, wait..:
[16:34] There is a complication
[16:36] the 'stuff' that saves the related model, also does $command->delete's
[16:36] so it always touches the db
[16:36] If I create a Main.php in the models would that just work?
[16:37] <tom[]> that's a simplification, not a complication
[16:37] enlighten me :)
[16:37] <tom[]> it's a special case of the pattern
[16:37] <tom[]> it means one of the instances of the pattern doesn't need to bother with the decision between validation error and DB exception
[16:38] you sure?
[16:38] lets take this case
[16:38] <tom[]> think not in terms of save and update etc
[16:38] Both User and Post arent validated
[16:39] as far as we talked about, there is no rollback
[16:39] <tom[]> think just in terms

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment