source: main/waeup.kofa/branches/henrik-transcript-workflow/src/waeup/kofa/doctests/certcourse.txt @ 17238

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

Fix typos.

File size: 6.7 KB
Line 
1.. _removecertificatecourses:
2
3Persistence of Certificate Courses
4==================================
5
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,
85other data will be handled in a way we expect. That is,
86
87* when we remove a course, we want all referrers to it be removed as
88  well
89
90* when we remove a referrer of a course, nothing else should be
91  touched but only this very referrer.
92
93
94As correct deletion of referrer needs support of catalogs (we lookup
95catalogs to find referrers), we need a fully blown ZODB here,
96including an instance of :class:`waeup.kofa.app.University`, as this is our
97`ISite` object where the catalogs are stored.
98
99We create a complete university tree, starting with a
100:class:`University` instance and going down to courses, certificates
101and course certificates:
102
103    >>> from waeup.kofa.app import University
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'
116    >>> root['app']['faculties'].addFaculty(faculty)
117    >>> fac = root['app']['faculties']['FAC']
118
119    >>> dept = createObject('waeup.Department')
120    >>> dept.code = 'DEPT'
121    >>> root['app']['faculties']['FAC'].addDepartment(dept)
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'
131    >>> root['app']['faculties']['FAC'].addDepartment(dept2)
132
133    >>> course = createObject('waeup.Course')
134    >>> course.code = 'CRS2'
135    >>> fac['DEPT2'].courses.addCourse(course)
136
137Finally, we add a certificate with referrers (certificate courses) to
138the created courses:
139
140    >>> cert = createObject('waeup.Certificate')
141    >>> cert.code = 'CERT'
142    >>> fac['DEPT'].certificates.addCertificate(cert)
143
144    >>> fac['DEPT'].certificates['CERT'].addCertCourse(
145    ...   fac['DEPT'].courses['CRS1'])
146
147    >>> fac['DEPT'].certificates['CERT'].addCertCourse(
148    ...   fac['DEPT2'].courses['CRS2'])
149
150We add the latter course again, but this time for the second level:
151
152    >>> fac['DEPT'].certificates['CERT'].addCertCourse(
153    ...   fac['DEPT2'].courses['CRS2'], level=200)
154
155So, we have three referrers in our certificate of two different
156courses stored somewhere in the application:
157
158    >>> list(fac['DEPT'].certificates['CERT'])
159    [u'CRS1_100', u'CRS2_100', u'CRS2_200']
160
161Both, the courses themselves and the referrers of them, are the same
162(not only equal):
163
164    >>> a = root['app']['faculties']['FAC']['DEPT']
165    >>> b1 = a.courses['CRS1']
166    >>> b2 = a.certificates['CERT']['CRS1_100'].course
167    >>> b1 is b2
168    True
169
170If we remove the course, also the select item in the certificate course
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
179    >>> del root['app']['faculties']['FAC']['DEPT'].courses['CRS1']
180    >>> list(a.certificates['CERT'])
181    [u'CRS2_100', u'CRS2_200']
182
183    >>> list(a.courses)
184    []
185
186If we remove a referrer of a course, this will not touch the course
187nor other referrers:
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']
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    []
220
221
Note: See TracBrowser for help on using the repository browser.