This is cool. I think your TimeClock example is essentially the pattern used
for the web2py Mail, Auth, and Crud classes. It might be useful to include a
section in the book about this pattern (or at least a web2py slice).
Anthony
On Monday, February 28, 2011 11:14:04 AM UTC-5, Ross Peoples wrote:
> I've always read that if you needed to centralize your logic, that you
> should use modules instead of trying to do it in a model or trying to wire
> up one controller to another. I used global settings as an example, as you
> might need access to these settings in every controller, and duplicating the
> code in every controller goes against the Python and we2py's DRY
> (don't repeat yourself) principal. So this is why modules were created.
>
> Granted, the GlobalSettings object I demonstrated is a very basic object
> that doesn't require you to instantiate it because it's all static. However,
> if you want to use more sophisticated objects, then the static class method
> may not work well. So there's another way to do this that I've been playing
> with.
>
> I am replacing a legacy application that is sort of like an ERP. The
> application keeps track of when employees clock in and clock out. Then, at
> the end of the week they print out their time cards. So, I wrote a TimeClock
> class in the same 'core.py' file described above. The big difference here is
> that the TimeClock object will have several functions, and I don't want to
> have to pass db, cache, and everything else for every function call, so I
> wrote it like this:
>
> class TimeClock:
> def __init__(self, environment, db):
> self.env = Storage(environment)
> self.request = self.env.request
> self.response = self.env.response
> self.cache = self.env.cache
> self.db = db
>
> def is_employee_clocked_in(self, employee):
> db = self.db
> timeclock_entry = db((db.timeclock.employee==employee) &
> (db.timeclock.endtime==None)).select().first()
> if timeclock_entry is None:
> return False
> else:
> return True
>
> Now, in my 'z_import_modules.py', I would add this (assuming I already did
> a local_import on core.py):
>
> timeclock = core.TimeClock(globals(), db)
>
> Then in any controller, if I want to check if an employee is clocked in:
>
> employee = auth.user
> if timeclock.is_employee_clocked_in(employee):
> print '%s is clocked in' % (employee.first_name)
> else:
> print '%s is not clocked in' % (employee.first_name)
>
> So with modules, you can make static classes for simple objects, like
> global settings that just load and save settings, or you can make complex
> objects that you instantiate in either the 'z_import_modules.py' file, or if
> you don't plan on using the module in every controller, then you could just
> remove the line we added in 'z_import_modules.py' to instantiate the
> 'timeclock' object, and use that line in whatever controller action we want.
>
> Hope this helps. So far this method seems to work really well. Oh, and to
> help you avoid some frustration in developing your modules, when you call
> local_import, you may also want to add reload=True to it. Without this, you
> would have to restart the web2py server every time you made a change to the
> module. Once you put your app into production, you would want to remove
> reload=True, as you don't want web2py to reload the module for every page
> load on a production server. So for testing, use this line:
>
> core = local_import('core', reload=True)
>
> And when you go into production, just remove 'reload=True'.
>