source: main/waeup.kofa/trunk/src/waeup/kofa/doctests/certcourse.txt @ 13610

Last change on this file since 13610 was 12966, checked in by Henrik Bettermann, 9 years ago

Fix typos.

File size: 6.7 KB
RevLine 
[12920]1.. _removecertificatecourses:
[4488]2
[12920]3Persistence of Certificate Courses
4==================================
[4488]5
[12920]6If a certificate course requires a certain course and this is course
7is deleted, also the referring certificate course is deleted.
8
9We setup a data structure that reflects typical usage. It looks like
10this::
11
12    Department-Instance
13    |
14    +---> courses
15    |        |
16    |        +--------------------> Course-Instance
17    |                                        ^
18    +---> certificates                       |
19             |                               |
20             +-----> Certificate-Instance    |
21                        |                    |
22                        +------> Certificate-Course
23
24The Certifcate Course here refers to a Course instance.
25
26In Python we build such a structure like this (from top to bottom):
27
28    >>> from zope.component import createObject
29    >>> mydept = createObject('waeup.Department')
30
31In real world use this data will be stored in a ZODB. We setup our own
32litte ZODB backend (which is easy!):
33
34    >>> from ZODB import FileStorage, DB
35    >>> dbpath = 'tinyData.fs'
36    >>> class TinyZODB(object):
37    ...   def __init__(self, path=dbpath):
38    ...     self.storage = FileStorage.FileStorage(path)
39    ...     self.db = DB(self.storage)
40    ...     self.connection = self.db.open()
41    ...     self.dbroot = self.connection.root()
42    ...   def close(self):
43    ...     self.connection.close()
44    ...     self.db.close()
45    ...     self.storage.close()
46
47Now we can use this ZODB as backend database and store our data
48structure:
49
50    >>> import transaction
51    >>> db = TinyZODB()
52    >>> dbroot = db.dbroot
53    >>> dbroot['mydept'] = mydept
54    >>> mycourse = createObject('waeup.Course')
55    >>> mycourse.code = 'MYCOURSE'
56    >>> mydept.courses.addCourse(mycourse)
57    >>> mycert = createObject('waeup.Certificate')
58    >>> mycert.code = 'MYCERT'
59    >>> mydept.certificates.addCertificate(mycert)
60    >>> mycert.addCertCourse(mycourse)
61
62    >>> transaction.commit()
63
64The data is now stored in the ZODB. We can close the DB, reopen it
65later and the data will still be there:
66
67    >>> db.close()
68    >>> newdb = TinyZODB()
69    >>> newdbroot = newdb.dbroot
70    >>> list(newdbroot)
71    ['mydept']
72
73The certificate course we stored in the certificate is indeed a
74referrer of the course, not a copy of it:
75
76    >>> course = newdbroot['mydept'].courses['MYCOURSE']
77    >>> certcourse = newdbroot['mydept'].certificates['MYCERT']['MYCOURSE_100']
78    >>> certcourse.course is course
79    True
80
81So, we can be sure that modifications to the course are immediately
82reflected in the certcourse.
83
84We can also be sure, that when removing courses or referrers of them,
[6737]85other data will be handled in a way we expect. That is,
[4488]86
[5978]87* when we remove a course, we want all referrers to it be removed as
[4488]88  well
89
[5978]90* when we remove a referrer of a course, nothing else should be
91  touched but only this very referrer.
[4488]92
93
[5978]94As correct deletion of referrer needs support of catalogs (we lookup
95catalogs to find referrers), we need a fully blown ZODB here,
[7811]96including an instance of :class:`waeup.kofa.app.University`, as this is our
[4488]97`ISite` object where the catalogs are stored.
98
99We create a complete university tree, starting with a
[12966]100:class:`University` instance and going down to courses, certificates
[4488]101and course certificates:
102
[7811]103    >>> from waeup.kofa.app import University
[4488]104    >>> root = getRootFolder()
105    >>> root['app'] = University()
106
107We have to set the site, to enable proper working of catalogs and
108`IObjectRemoved` handlers:
109
110    >>> from zope.app.component.hooks import setSite
111    >>> setSite(root['app'])
112
113    >>> from zope.component import createObject
114    >>> faculty = createObject('waeup.Faculty')
115    >>> faculty.code = 'FAC'
[4749]116    >>> root['app']['faculties'].addFaculty(faculty)
117    >>> fac = root['app']['faculties']['FAC']
[4488]118
119    >>> dept = createObject('waeup.Department')
120    >>> dept.code = 'DEPT'
[4749]121    >>> root['app']['faculties']['FAC'].addDepartment(dept)
[4488]122
123    >>> course = createObject('waeup.Course')
124    >>> course.code = 'CRS1'
125    >>> fac['DEPT'].courses.addCourse(course)
126
127Now let's add another department, which will also hold a course:
128
129    >>> dept2 = createObject('waeup.Department')
130    >>> dept2.code = 'DEPT2'
[4749]131    >>> root['app']['faculties']['FAC'].addDepartment(dept2)
[4488]132
133    >>> course = createObject('waeup.Course')
134    >>> course.code = 'CRS2'
135    >>> fac['DEPT2'].courses.addCourse(course)
136
[5978]137Finally, we add a certificate with referrers (certificate courses) to
[4488]138the created courses:
139
140    >>> cert = createObject('waeup.Certificate')
141    >>> cert.code = 'CERT'
142    >>> fac['DEPT'].certificates.addCertificate(cert)
143
[8920]144    >>> fac['DEPT'].certificates['CERT'].addCertCourse(
[4488]145    ...   fac['DEPT'].courses['CRS1'])
146
[8920]147    >>> fac['DEPT'].certificates['CERT'].addCertCourse(
[4488]148    ...   fac['DEPT2'].courses['CRS2'])
149
150We add the latter course again, but this time for the second level:
151
[8920]152    >>> fac['DEPT'].certificates['CERT'].addCertCourse(
[4488]153    ...   fac['DEPT2'].courses['CRS2'], level=200)
154
[5978]155So, we have three referrers in our certificate of two different
[4488]156courses stored somewhere in the application:
157
158    >>> list(fac['DEPT'].certificates['CERT'])
159    [u'CRS1_100', u'CRS2_100', u'CRS2_200']
160
[5978]161Both, the courses themselves and the referrers of them, are the same
[4488]162(not only equal):
163
[4749]164    >>> a = root['app']['faculties']['FAC']['DEPT']
[4488]165    >>> b1 = a.courses['CRS1']
166    >>> b2 = a.certificates['CERT']['CRS1_100'].course
167    >>> b1 is b2
168    True
169
[5978]170If we remove the course, also the select item in the certificate course
[4488]171will be gone:
172
173    >>> list(a.certificates['CERT'])
174    [u'CRS1_100', u'CRS2_100', u'CRS2_200']
175
176    >>> list(a.courses)
177    [u'CRS1']
178
[4749]179    >>> del root['app']['faculties']['FAC']['DEPT'].courses['CRS1']
[4488]180    >>> list(a.certificates['CERT'])
181    [u'CRS2_100', u'CRS2_200']
182
183    >>> list(a.courses)
184    []
185
[5978]186If we remove a referrer of a course, this will not touch the course
187nor other referrers:
[4488]188
189    >>> del fac['DEPT'].certificates['CERT']['CRS2_200']
190    >>> list(a.certificates['CERT'])
191    [u'CRS2_100']
192
193    >>> list(fac['DEPT2'].courses)
194    [u'CRS2']
[9828]195
196If a single course is registered for several levels in a single
197certificate, this will not block things if the course is removed
198(regression test):
199
200We add the same course as a reference for level 200 and level 300:
201
202    >>> fac['DEPT'].certificates['CERT'].addCertCourse(
203    ...   fac['DEPT2'].courses['CRS2'], level=200)
204    >>> fac['DEPT'].certificates['CERT'].addCertCourse(
205    ...   fac['DEPT2'].courses['CRS2'], level=300)
206
207Deleting the course (thus also the refererrers) will work:
208
209    >>> del root['app']['faculties']['FAC']['DEPT2'].courses['CRS2']
210
211Now all references are gone:
212
213    >>> list(a.certificates['CERT'])
214    []
215
216and also the course itself vanished:
217
218    >>> list(fac['DEPT2'].courses)
219    []
[12920]220
221
Note: See TracBrowser for help on using the repository browser.