@@ -49,27 +49,27 @@ discard block |
||
49 | 49 | |
50 | 50 | $controller = new SimpleController; |
51 | 51 | $controller |
52 | - ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL) |
|
53 | - ->addInlineJavascript('autocomplete();') |
|
54 | - ->restrictAccess(Auth::isMember($WT_TREE)); |
|
52 | + ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL) |
|
53 | + ->addInlineJavascript('autocomplete();') |
|
54 | + ->restrictAccess(Auth::isMember($WT_TREE)); |
|
55 | 55 | |
56 | 56 | $disp = true; |
57 | 57 | $media = Media::getInstance($pid, $WT_TREE); |
58 | 58 | if ($media) { |
59 | - $disp = $media->canShow(); |
|
59 | + $disp = $media->canShow(); |
|
60 | 60 | } |
61 | 61 | if ($action == 'update' || $action == 'create') { |
62 | - if ($linktoid) { |
|
63 | - $disp = GedcomRecord::getInstance($linktoid, $WT_TREE)->canShow(); |
|
64 | - } |
|
62 | + if ($linktoid) { |
|
63 | + $disp = GedcomRecord::getInstance($linktoid, $WT_TREE)->canShow(); |
|
64 | + } |
|
65 | 65 | } |
66 | 66 | |
67 | 67 | if (!Auth::isEditor($WT_TREE) || !$disp) { |
68 | - $controller |
|
69 | - ->pageHeader() |
|
70 | - ->addInlineJavascript('closePopupAndReloadParent();'); |
|
68 | + $controller |
|
69 | + ->pageHeader() |
|
70 | + ->addInlineJavascript('closePopupAndReloadParent();'); |
|
71 | 71 | |
72 | - return; |
|
72 | + return; |
|
73 | 73 | } |
74 | 74 | |
75 | 75 | // There is a lot of common code in the create and update cases… |
@@ -77,337 +77,337 @@ discard block |
||
77 | 77 | |
78 | 78 | switch ($action) { |
79 | 79 | case 'create': // Save the information from the “showcreateform” action |
80 | - $controller->setPageTitle(I18N::translate('Create a media object')); |
|
81 | - |
|
82 | - // Validate the media folder |
|
83 | - $folderName = str_replace('\\', '/', $folder); |
|
84 | - $folderName = trim($folderName, '/'); |
|
85 | - if ($folderName == '.') { |
|
86 | - $folderName = ''; |
|
87 | - } |
|
88 | - if ($folderName) { |
|
89 | - $folderName .= '/'; |
|
90 | - // Not allowed to use “../” |
|
91 | - if (strpos('/' . $folderName, '/../') !== false) { |
|
92 | - FlashMessages::addMessage('Folder names are not allowed to include “../”'); |
|
93 | - break; |
|
94 | - } |
|
95 | - } |
|
96 | - |
|
97 | - // Make sure the media folder exists |
|
98 | - if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY)) { |
|
99 | - if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY)) { |
|
100 | - FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY))); |
|
101 | - } else { |
|
102 | - FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'danger'); |
|
103 | - break; |
|
104 | - } |
|
105 | - } |
|
106 | - |
|
107 | - // Managers can create new media paths (subfolders). Users must use existing folders. |
|
108 | - if ($folderName && !is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) { |
|
109 | - if (Auth::isManager($WT_TREE)) { |
|
110 | - if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) { |
|
111 | - FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName))); |
|
112 | - } else { |
|
113 | - FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)), 'danger'); |
|
114 | - break; |
|
115 | - } |
|
116 | - } else { |
|
117 | - // Regular users should not have seen this option - so no need for an error message. |
|
118 | - break; |
|
119 | - } |
|
120 | - } |
|
121 | - |
|
122 | - // The media folder exists. Now create a thumbnail folder to match it. |
|
123 | - if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) { |
|
124 | - if (!File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) { |
|
125 | - FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)), 'danger'); |
|
126 | - break; |
|
127 | - } |
|
128 | - } |
|
129 | - |
|
130 | - // A thumbnail file with no main image? |
|
131 | - if (!empty($_FILES['thumbnail']['name']) && empty($_FILES['mediafile']['name'])) { |
|
132 | - // Assume the user used the wrong field, and treat this as a main image |
|
133 | - $_FILES['mediafile'] = $_FILES['thumbnail']; |
|
134 | - unset($_FILES['thumbnail']); |
|
135 | - } |
|
136 | - |
|
137 | - // Thumbnail files must contain images. |
|
138 | - if (!empty($_FILES['thumbnail']['name']) && !preg_match('/^image/', $_FILES['thumbnail']['type'])) { |
|
139 | - FlashMessages::addMessage(I18N::translate('Thumbnail files must contain images.')); |
|
140 | - break; |
|
141 | - } |
|
142 | - |
|
143 | - // User-specified filename? |
|
144 | - if ($tag[0] == 'FILE' && $text[0]) { |
|
145 | - $filename = $text[0]; |
|
146 | - } |
|
147 | - // Use the name of the uploaded file? |
|
148 | - // If no filename specified, use the name of the uploaded file? |
|
149 | - if (!$filename && !empty($_FILES['mediafile']['name'])) { |
|
150 | - $filename = $_FILES['mediafile']['name']; |
|
151 | - } |
|
152 | - |
|
153 | - // Validate the media path and filename |
|
154 | - if (preg_match('/^https?:\/\//i', $text[0], $match)) { |
|
155 | - // External media needs no further validation |
|
156 | - $fileName = $filename; |
|
157 | - $folderName = ''; |
|
158 | - unset($_FILES['mediafile'], $_FILES['thumbnail']); |
|
159 | - } elseif (preg_match('/([\/\\\\<>])/', $filename, $match)) { |
|
160 | - // Local media files cannot contain certain special characters |
|
161 | - FlashMessages::addMessage(I18N::translate('Filenames are not allowed to contain the character “%s”.', $match[1])); |
|
162 | - break; |
|
163 | - } elseif (preg_match('/(\.(php|pl|cgi|bash|sh|bat|exe|com|htm|html|shtml))$/i', $filename, $match)) { |
|
164 | - // Do not allow obvious script files. |
|
165 | - FlashMessages::addMessage(I18N::translate('Filenames are not allowed to have the extension “%s”.', $match[1])); |
|
166 | - break; |
|
167 | - } elseif (!$filename) { |
|
168 | - FlashMessages::addMessage(I18N::translate('No media file was provided.')); |
|
169 | - break; |
|
170 | - } else { |
|
171 | - $fileName = $filename; |
|
172 | - } |
|
173 | - |
|
174 | - // Now copy the file to the correct location. |
|
175 | - if (!empty($_FILES['mediafile']['name'])) { |
|
176 | - $serverFileName = WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName . $fileName; |
|
177 | - if (file_exists($serverFileName)) { |
|
178 | - FlashMessages::addMessage(I18N::translate('The file %s already exists. Use another filename.', $folderName . $fileName)); |
|
179 | - break; |
|
180 | - } |
|
181 | - if (move_uploaded_file($_FILES['mediafile']['tmp_name'], $serverFileName)) { |
|
182 | - Log::addMediaLog('Media file ' . $serverFileName . ' uploaded'); |
|
183 | - } else { |
|
184 | - FlashMessages::addMessage( |
|
185 | - I18N::translate('There was an error uploading your file.') . |
|
186 | - '<br>' . |
|
187 | - Functions::fileUploadErrorText($_FILES['mediafile']['error']) |
|
188 | - ); |
|
189 | - break; |
|
190 | - } |
|
191 | - |
|
192 | - // Now copy the (optional) thumbnail |
|
193 | - if (!empty($_FILES['thumbnail']['name']) && preg_match('/^image\/(png|gif|jpeg)/', $_FILES['thumbnail']['type'], $match)) { |
|
194 | - // Thumbnails have either |
|
195 | - // (a) the same filename as the main image |
|
196 | - // (b) the same filename as the main image - but with a .png extension |
|
197 | - if ($match[1] == 'png' && !preg_match('/\.(png)$/i', $fileName)) { |
|
198 | - $thumbFile = preg_replace('/\.[a-z0-9]{3,5}$/', '.png', $fileName); |
|
199 | - } else { |
|
200 | - $thumbFile = $fileName; |
|
201 | - } |
|
202 | - $serverFileName = WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName . $thumbFile; |
|
203 | - if (move_uploaded_file($_FILES['thumbnail']['tmp_name'], $serverFileName)) { |
|
204 | - Log::addMediaLog('Thumbnail file ' . $serverFileName . ' uploaded'); |
|
205 | - } |
|
206 | - } |
|
207 | - } |
|
208 | - |
|
209 | - $controller->pageHeader(); |
|
210 | - // Build the gedcom record |
|
211 | - $newged = "0 @new@ OBJE"; |
|
212 | - if ($tag[0] == 'FILE') { |
|
213 | - // The admin has an edit field to change the filename |
|
214 | - $text[0] = $folderName . $fileName; |
|
215 | - } else { |
|
216 | - // Users keep the original filename |
|
217 | - $newged .= "\n1 FILE " . $folderName . $fileName; |
|
218 | - } |
|
219 | - |
|
220 | - $newged = FunctionsEdit::handleUpdates($newged); |
|
221 | - |
|
222 | - $new_media = $WT_TREE->createRecord($newged); |
|
223 | - if ($linktoid) { |
|
224 | - $record = GedcomRecord::getInstance($linktoid, $WT_TREE); |
|
225 | - $record->createFact('1 OBJE @' . $new_media->getXref() . '@', true); |
|
226 | - Log::addEditLog('Media ID ' . $new_media->getXref() . " successfully added to $linktoid."); |
|
227 | - $controller->addInlineJavascript('closePopupAndReloadParent();'); |
|
228 | - } else { |
|
229 | - Log::addEditLog('Media ID ' . $new_media->getXref() . ' successfully added.'); |
|
230 | - $controller->addInlineJavascript('openerpasteid("' . $new_media->getXref() . '");'); |
|
231 | - } |
|
232 | - echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>'; |
|
233 | - |
|
234 | - return; |
|
80 | + $controller->setPageTitle(I18N::translate('Create a media object')); |
|
81 | + |
|
82 | + // Validate the media folder |
|
83 | + $folderName = str_replace('\\', '/', $folder); |
|
84 | + $folderName = trim($folderName, '/'); |
|
85 | + if ($folderName == '.') { |
|
86 | + $folderName = ''; |
|
87 | + } |
|
88 | + if ($folderName) { |
|
89 | + $folderName .= '/'; |
|
90 | + // Not allowed to use “../” |
|
91 | + if (strpos('/' . $folderName, '/../') !== false) { |
|
92 | + FlashMessages::addMessage('Folder names are not allowed to include “../”'); |
|
93 | + break; |
|
94 | + } |
|
95 | + } |
|
96 | + |
|
97 | + // Make sure the media folder exists |
|
98 | + if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY)) { |
|
99 | + if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY)) { |
|
100 | + FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY))); |
|
101 | + } else { |
|
102 | + FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'danger'); |
|
103 | + break; |
|
104 | + } |
|
105 | + } |
|
106 | + |
|
107 | + // Managers can create new media paths (subfolders). Users must use existing folders. |
|
108 | + if ($folderName && !is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) { |
|
109 | + if (Auth::isManager($WT_TREE)) { |
|
110 | + if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) { |
|
111 | + FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName))); |
|
112 | + } else { |
|
113 | + FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)), 'danger'); |
|
114 | + break; |
|
115 | + } |
|
116 | + } else { |
|
117 | + // Regular users should not have seen this option - so no need for an error message. |
|
118 | + break; |
|
119 | + } |
|
120 | + } |
|
121 | + |
|
122 | + // The media folder exists. Now create a thumbnail folder to match it. |
|
123 | + if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) { |
|
124 | + if (!File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) { |
|
125 | + FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)), 'danger'); |
|
126 | + break; |
|
127 | + } |
|
128 | + } |
|
129 | + |
|
130 | + // A thumbnail file with no main image? |
|
131 | + if (!empty($_FILES['thumbnail']['name']) && empty($_FILES['mediafile']['name'])) { |
|
132 | + // Assume the user used the wrong field, and treat this as a main image |
|
133 | + $_FILES['mediafile'] = $_FILES['thumbnail']; |
|
134 | + unset($_FILES['thumbnail']); |
|
135 | + } |
|
136 | + |
|
137 | + // Thumbnail files must contain images. |
|
138 | + if (!empty($_FILES['thumbnail']['name']) && !preg_match('/^image/', $_FILES['thumbnail']['type'])) { |
|
139 | + FlashMessages::addMessage(I18N::translate('Thumbnail files must contain images.')); |
|
140 | + break; |
|
141 | + } |
|
142 | + |
|
143 | + // User-specified filename? |
|
144 | + if ($tag[0] == 'FILE' && $text[0]) { |
|
145 | + $filename = $text[0]; |
|
146 | + } |
|
147 | + // Use the name of the uploaded file? |
|
148 | + // If no filename specified, use the name of the uploaded file? |
|
149 | + if (!$filename && !empty($_FILES['mediafile']['name'])) { |
|
150 | + $filename = $_FILES['mediafile']['name']; |
|
151 | + } |
|
152 | + |
|
153 | + // Validate the media path and filename |
|
154 | + if (preg_match('/^https?:\/\//i', $text[0], $match)) { |
|
155 | + // External media needs no further validation |
|
156 | + $fileName = $filename; |
|
157 | + $folderName = ''; |
|
158 | + unset($_FILES['mediafile'], $_FILES['thumbnail']); |
|
159 | + } elseif (preg_match('/([\/\\\\<>])/', $filename, $match)) { |
|
160 | + // Local media files cannot contain certain special characters |
|
161 | + FlashMessages::addMessage(I18N::translate('Filenames are not allowed to contain the character “%s”.', $match[1])); |
|
162 | + break; |
|
163 | + } elseif (preg_match('/(\.(php|pl|cgi|bash|sh|bat|exe|com|htm|html|shtml))$/i', $filename, $match)) { |
|
164 | + // Do not allow obvious script files. |
|
165 | + FlashMessages::addMessage(I18N::translate('Filenames are not allowed to have the extension “%s”.', $match[1])); |
|
166 | + break; |
|
167 | + } elseif (!$filename) { |
|
168 | + FlashMessages::addMessage(I18N::translate('No media file was provided.')); |
|
169 | + break; |
|
170 | + } else { |
|
171 | + $fileName = $filename; |
|
172 | + } |
|
173 | + |
|
174 | + // Now copy the file to the correct location. |
|
175 | + if (!empty($_FILES['mediafile']['name'])) { |
|
176 | + $serverFileName = WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName . $fileName; |
|
177 | + if (file_exists($serverFileName)) { |
|
178 | + FlashMessages::addMessage(I18N::translate('The file %s already exists. Use another filename.', $folderName . $fileName)); |
|
179 | + break; |
|
180 | + } |
|
181 | + if (move_uploaded_file($_FILES['mediafile']['tmp_name'], $serverFileName)) { |
|
182 | + Log::addMediaLog('Media file ' . $serverFileName . ' uploaded'); |
|
183 | + } else { |
|
184 | + FlashMessages::addMessage( |
|
185 | + I18N::translate('There was an error uploading your file.') . |
|
186 | + '<br>' . |
|
187 | + Functions::fileUploadErrorText($_FILES['mediafile']['error']) |
|
188 | + ); |
|
189 | + break; |
|
190 | + } |
|
191 | + |
|
192 | + // Now copy the (optional) thumbnail |
|
193 | + if (!empty($_FILES['thumbnail']['name']) && preg_match('/^image\/(png|gif|jpeg)/', $_FILES['thumbnail']['type'], $match)) { |
|
194 | + // Thumbnails have either |
|
195 | + // (a) the same filename as the main image |
|
196 | + // (b) the same filename as the main image - but with a .png extension |
|
197 | + if ($match[1] == 'png' && !preg_match('/\.(png)$/i', $fileName)) { |
|
198 | + $thumbFile = preg_replace('/\.[a-z0-9]{3,5}$/', '.png', $fileName); |
|
199 | + } else { |
|
200 | + $thumbFile = $fileName; |
|
201 | + } |
|
202 | + $serverFileName = WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName . $thumbFile; |
|
203 | + if (move_uploaded_file($_FILES['thumbnail']['tmp_name'], $serverFileName)) { |
|
204 | + Log::addMediaLog('Thumbnail file ' . $serverFileName . ' uploaded'); |
|
205 | + } |
|
206 | + } |
|
207 | + } |
|
208 | + |
|
209 | + $controller->pageHeader(); |
|
210 | + // Build the gedcom record |
|
211 | + $newged = "0 @new@ OBJE"; |
|
212 | + if ($tag[0] == 'FILE') { |
|
213 | + // The admin has an edit field to change the filename |
|
214 | + $text[0] = $folderName . $fileName; |
|
215 | + } else { |
|
216 | + // Users keep the original filename |
|
217 | + $newged .= "\n1 FILE " . $folderName . $fileName; |
|
218 | + } |
|
219 | + |
|
220 | + $newged = FunctionsEdit::handleUpdates($newged); |
|
221 | + |
|
222 | + $new_media = $WT_TREE->createRecord($newged); |
|
223 | + if ($linktoid) { |
|
224 | + $record = GedcomRecord::getInstance($linktoid, $WT_TREE); |
|
225 | + $record->createFact('1 OBJE @' . $new_media->getXref() . '@', true); |
|
226 | + Log::addEditLog('Media ID ' . $new_media->getXref() . " successfully added to $linktoid."); |
|
227 | + $controller->addInlineJavascript('closePopupAndReloadParent();'); |
|
228 | + } else { |
|
229 | + Log::addEditLog('Media ID ' . $new_media->getXref() . ' successfully added.'); |
|
230 | + $controller->addInlineJavascript('openerpasteid("' . $new_media->getXref() . '");'); |
|
231 | + } |
|
232 | + echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>'; |
|
233 | + |
|
234 | + return; |
|
235 | 235 | |
236 | 236 | case 'update': // Save the information from the “editmedia” action |
237 | - $controller->setPageTitle(I18N::translate('Edit the media object')); |
|
238 | - |
|
239 | - // Validate the media folder |
|
240 | - $folderName = str_replace('\\', '/', $folder); |
|
241 | - $folderName = trim($folderName, '/'); |
|
242 | - if ($folderName == '.') { |
|
243 | - $folderName = ''; |
|
244 | - } |
|
245 | - if ($folderName) { |
|
246 | - $folderName .= '/'; |
|
247 | - // Not allowed to use “../” |
|
248 | - if (strpos('/' . $folderName, '/../') !== false) { |
|
249 | - FlashMessages::addMessage('Folder names are not allowed to include “../”'); |
|
250 | - break; |
|
251 | - } |
|
252 | - } |
|
253 | - |
|
254 | - // Make sure the media folder exists |
|
255 | - if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY)) { |
|
256 | - if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY)) { |
|
257 | - FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY))); |
|
258 | - } else { |
|
259 | - FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'danger'); |
|
260 | - break; |
|
261 | - } |
|
262 | - } |
|
263 | - |
|
264 | - // Managers can create new media paths (subfolders). Users must use existing folders. |
|
265 | - if ($folderName && !is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) { |
|
266 | - if (Auth::isManager($WT_TREE)) { |
|
267 | - if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) { |
|
268 | - FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName))); |
|
269 | - } else { |
|
270 | - FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)), 'danger'); |
|
271 | - break; |
|
272 | - } |
|
273 | - } else { |
|
274 | - // Regular users should not have seen this option - so no need for an error message. |
|
275 | - break; |
|
276 | - } |
|
277 | - } |
|
278 | - |
|
279 | - // The media folder exists. Now create a thumbnail folder to match it. |
|
280 | - if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) { |
|
281 | - if (!File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) { |
|
282 | - FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)), 'danger'); |
|
283 | - break; |
|
284 | - } |
|
285 | - } |
|
286 | - |
|
287 | - // Validate the media path and filename |
|
288 | - if (preg_match('/^https?:\/\//i', $filename, $match)) { |
|
289 | - // External media needs no further validation |
|
290 | - $fileName = $filename; |
|
291 | - $folderName = ''; |
|
292 | - unset($_FILES['mediafile'], $_FILES['thumbnail']); |
|
293 | - } elseif (preg_match('/([\/\\\\<>])/', $filename, $match)) { |
|
294 | - // Local media files cannot contain certain special characters |
|
295 | - FlashMessages::addMessage(I18N::translate('Filenames are not allowed to contain the character “%s”.', $match[1])); |
|
296 | - break; |
|
297 | - } elseif (preg_match('/(\.(php|pl|cgi|bash|sh|bat|exe|com|htm|html|shtml))$/i', $filename, $match)) { |
|
298 | - // Do not allow obvious script files. |
|
299 | - FlashMessages::addMessage(I18N::translate('Filenames are not allowed to have the extension “%s”.', $match[1])); |
|
300 | - break; |
|
301 | - } elseif (!$filename) { |
|
302 | - FlashMessages::addMessage(I18N::translate('No media file was provided.')); |
|
303 | - break; |
|
304 | - } else { |
|
305 | - $fileName = $filename; |
|
306 | - } |
|
307 | - |
|
308 | - $oldFilename = $media->getFilename(); |
|
309 | - $newFilename = $folderName . $fileName; |
|
310 | - |
|
311 | - // Cannot rename local to external or vice-versa |
|
312 | - if (Functions::isFileExternal($oldFilename) != Functions::isFileExternal($filename)) { |
|
313 | - FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
314 | - break; |
|
315 | - } |
|
316 | - |
|
317 | - $messages = false; |
|
318 | - $move_file = false; |
|
319 | - |
|
320 | - // Move files on disk (if we can) to reflect the change to the GEDCOM data |
|
321 | - if (!$media->isExternal()) { |
|
322 | - $oldServerFile = $media->getServerFilename('main'); |
|
323 | - $oldServerThumb = $media->getServerFilename('thumb'); |
|
324 | - |
|
325 | - $newmedia = new Media("xxx", "0 @xxx@ OBJE\n1 FILE " . $newFilename, null, $WT_TREE); |
|
326 | - $newServerFile = $newmedia->getServerFilename('main'); |
|
327 | - $newServerThumb = $newmedia->getServerFilename('thumb'); |
|
328 | - |
|
329 | - // We could be either renaming an existing file, or updating a record (with no valid file) to point to a new file |
|
330 | - if ($oldServerFile !== $newServerFile) { |
|
331 | - //-- check if the file is used in more than one gedcom |
|
332 | - //-- do not allow it to be moved or renamed if it is |
|
333 | - if (!$media->isExternal() && FunctionsDb::isMediaUsedInOtherTree($media->getFilename(), $WT_TREE->getTreeId())) { |
|
334 | - FlashMessages::addMessage(I18N::translate('This file is linked to another family tree on this server. It cannot be deleted, moved, or renamed until these links have been removed.')); |
|
335 | - break; |
|
336 | - } |
|
337 | - |
|
338 | - $move_file = true; |
|
339 | - if (!file_exists($newServerFile) || md5_file($oldServerFile) === md5_file($newServerFile)) { |
|
340 | - try { |
|
341 | - rename($oldServerFile, $newServerFile); |
|
342 | - FlashMessages::addMessage(I18N::translate('The media file %1$s has been renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
343 | - } catch (\ErrorException $ex) { |
|
344 | - FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
345 | - } |
|
346 | - $messages = true; |
|
347 | - } |
|
348 | - if (!file_exists($newServerFile)) { |
|
349 | - FlashMessages::addMessage(I18N::translate('The media file %s does not exist.', Html::filename($newFilename))); |
|
350 | - $messages = true; |
|
351 | - } |
|
352 | - } |
|
353 | - if ($oldServerThumb != $newServerThumb) { |
|
354 | - $move_file = true; |
|
355 | - if (!file_exists($newServerThumb) || md5_file($oldServerFile) == md5_file($newServerThumb)) { |
|
356 | - try { |
|
357 | - rename($oldServerThumb, $newServerThumb); |
|
358 | - FlashMessages::addMessage(I18N::translate('The thumbnail file %1$s has been renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
359 | - } catch (\ErrorException $ex) { |
|
360 | - FlashMessages::addMessage(I18N::translate('The thumbnail file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
361 | - } |
|
362 | - $messages = true; |
|
363 | - } |
|
364 | - if (!file_exists($newServerThumb)) { |
|
365 | - FlashMessages::addMessage(I18N::translate('The thumbnail file %s does not exist.', Html::filename($newFilename))); |
|
366 | - $messages = true; |
|
367 | - } |
|
368 | - } |
|
369 | - } |
|
370 | - |
|
371 | - // Insert the 1 FILE xxx record into the arrays used by function FunctionsEdit::handle_updatesges() |
|
372 | - $glevels = array_merge(array('1'), $glevels); |
|
373 | - $tag = array_merge(array('FILE'), $tag); |
|
374 | - $islink = array_merge(array(0), $islink); |
|
375 | - $text = array_merge(array($newFilename), $text); |
|
376 | - |
|
377 | - $record = GedcomRecord::getInstance($pid, $WT_TREE); |
|
378 | - $newrec = "0 @$pid@ OBJE\n"; |
|
379 | - $newrec = FunctionsEdit::handleUpdates($newrec); |
|
380 | - $record->updateRecord($newrec, $update_CHAN); |
|
381 | - |
|
382 | - if ($move_file) { |
|
383 | - // We've moved a file. Therefore we must approve the change, as rejecting |
|
384 | - // the change will create broken references. |
|
385 | - FunctionsImport::acceptAllChanges($record->getXref(), $record->getTree()->getTreeId()); |
|
386 | - } |
|
387 | - |
|
388 | - if ($pid && $linktoid) { |
|
389 | - $record = GedcomRecord::getInstance($linktoid, $WT_TREE); |
|
390 | - $record->createFact('1 OBJE @' . $pid . '@', true); |
|
391 | - Log::addEditLog('Media ID ' . $pid . " successfully added to $linktoid."); |
|
392 | - } |
|
393 | - $controller->pageHeader(); |
|
394 | - if ($messages) { |
|
395 | - echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>'; |
|
396 | - } else { |
|
397 | - $controller->addInlineJavascript('closePopupAndReloadParent();'); |
|
398 | - } |
|
399 | - |
|
400 | - return; |
|
237 | + $controller->setPageTitle(I18N::translate('Edit the media object')); |
|
238 | + |
|
239 | + // Validate the media folder |
|
240 | + $folderName = str_replace('\\', '/', $folder); |
|
241 | + $folderName = trim($folderName, '/'); |
|
242 | + if ($folderName == '.') { |
|
243 | + $folderName = ''; |
|
244 | + } |
|
245 | + if ($folderName) { |
|
246 | + $folderName .= '/'; |
|
247 | + // Not allowed to use “../” |
|
248 | + if (strpos('/' . $folderName, '/../') !== false) { |
|
249 | + FlashMessages::addMessage('Folder names are not allowed to include “../”'); |
|
250 | + break; |
|
251 | + } |
|
252 | + } |
|
253 | + |
|
254 | + // Make sure the media folder exists |
|
255 | + if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY)) { |
|
256 | + if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY)) { |
|
257 | + FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY))); |
|
258 | + } else { |
|
259 | + FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY)), 'danger'); |
|
260 | + break; |
|
261 | + } |
|
262 | + } |
|
263 | + |
|
264 | + // Managers can create new media paths (subfolders). Users must use existing folders. |
|
265 | + if ($folderName && !is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) { |
|
266 | + if (Auth::isManager($WT_TREE)) { |
|
267 | + if (File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)) { |
|
268 | + FlashMessages::addMessage(I18N::translate('The folder %s has been created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName))); |
|
269 | + } else { |
|
270 | + FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . $folderName)), 'danger'); |
|
271 | + break; |
|
272 | + } |
|
273 | + } else { |
|
274 | + // Regular users should not have seen this option - so no need for an error message. |
|
275 | + break; |
|
276 | + } |
|
277 | + } |
|
278 | + |
|
279 | + // The media folder exists. Now create a thumbnail folder to match it. |
|
280 | + if (!is_dir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) { |
|
281 | + if (!File::mkdir(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)) { |
|
282 | + FlashMessages::addMessage(I18N::translate('The folder %s does not exist, and it could not be created.', Html::filename(WT_DATA_DIR . $MEDIA_DIRECTORY . 'thumbs/' . $folderName)), 'danger'); |
|
283 | + break; |
|
284 | + } |
|
285 | + } |
|
286 | + |
|
287 | + // Validate the media path and filename |
|
288 | + if (preg_match('/^https?:\/\//i', $filename, $match)) { |
|
289 | + // External media needs no further validation |
|
290 | + $fileName = $filename; |
|
291 | + $folderName = ''; |
|
292 | + unset($_FILES['mediafile'], $_FILES['thumbnail']); |
|
293 | + } elseif (preg_match('/([\/\\\\<>])/', $filename, $match)) { |
|
294 | + // Local media files cannot contain certain special characters |
|
295 | + FlashMessages::addMessage(I18N::translate('Filenames are not allowed to contain the character “%s”.', $match[1])); |
|
296 | + break; |
|
297 | + } elseif (preg_match('/(\.(php|pl|cgi|bash|sh|bat|exe|com|htm|html|shtml))$/i', $filename, $match)) { |
|
298 | + // Do not allow obvious script files. |
|
299 | + FlashMessages::addMessage(I18N::translate('Filenames are not allowed to have the extension “%s”.', $match[1])); |
|
300 | + break; |
|
301 | + } elseif (!$filename) { |
|
302 | + FlashMessages::addMessage(I18N::translate('No media file was provided.')); |
|
303 | + break; |
|
304 | + } else { |
|
305 | + $fileName = $filename; |
|
306 | + } |
|
307 | + |
|
308 | + $oldFilename = $media->getFilename(); |
|
309 | + $newFilename = $folderName . $fileName; |
|
310 | + |
|
311 | + // Cannot rename local to external or vice-versa |
|
312 | + if (Functions::isFileExternal($oldFilename) != Functions::isFileExternal($filename)) { |
|
313 | + FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
314 | + break; |
|
315 | + } |
|
316 | + |
|
317 | + $messages = false; |
|
318 | + $move_file = false; |
|
319 | + |
|
320 | + // Move files on disk (if we can) to reflect the change to the GEDCOM data |
|
321 | + if (!$media->isExternal()) { |
|
322 | + $oldServerFile = $media->getServerFilename('main'); |
|
323 | + $oldServerThumb = $media->getServerFilename('thumb'); |
|
324 | + |
|
325 | + $newmedia = new Media("xxx", "0 @xxx@ OBJE\n1 FILE " . $newFilename, null, $WT_TREE); |
|
326 | + $newServerFile = $newmedia->getServerFilename('main'); |
|
327 | + $newServerThumb = $newmedia->getServerFilename('thumb'); |
|
328 | + |
|
329 | + // We could be either renaming an existing file, or updating a record (with no valid file) to point to a new file |
|
330 | + if ($oldServerFile !== $newServerFile) { |
|
331 | + //-- check if the file is used in more than one gedcom |
|
332 | + //-- do not allow it to be moved or renamed if it is |
|
333 | + if (!$media->isExternal() && FunctionsDb::isMediaUsedInOtherTree($media->getFilename(), $WT_TREE->getTreeId())) { |
|
334 | + FlashMessages::addMessage(I18N::translate('This file is linked to another family tree on this server. It cannot be deleted, moved, or renamed until these links have been removed.')); |
|
335 | + break; |
|
336 | + } |
|
337 | + |
|
338 | + $move_file = true; |
|
339 | + if (!file_exists($newServerFile) || md5_file($oldServerFile) === md5_file($newServerFile)) { |
|
340 | + try { |
|
341 | + rename($oldServerFile, $newServerFile); |
|
342 | + FlashMessages::addMessage(I18N::translate('The media file %1$s has been renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
343 | + } catch (\ErrorException $ex) { |
|
344 | + FlashMessages::addMessage(I18N::translate('The media file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
345 | + } |
|
346 | + $messages = true; |
|
347 | + } |
|
348 | + if (!file_exists($newServerFile)) { |
|
349 | + FlashMessages::addMessage(I18N::translate('The media file %s does not exist.', Html::filename($newFilename))); |
|
350 | + $messages = true; |
|
351 | + } |
|
352 | + } |
|
353 | + if ($oldServerThumb != $newServerThumb) { |
|
354 | + $move_file = true; |
|
355 | + if (!file_exists($newServerThumb) || md5_file($oldServerFile) == md5_file($newServerThumb)) { |
|
356 | + try { |
|
357 | + rename($oldServerThumb, $newServerThumb); |
|
358 | + FlashMessages::addMessage(I18N::translate('The thumbnail file %1$s has been renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
359 | + } catch (\ErrorException $ex) { |
|
360 | + FlashMessages::addMessage(I18N::translate('The thumbnail file %1$s could not be renamed to %2$s.', Html::filename($oldFilename), Html::filename($newFilename))); |
|
361 | + } |
|
362 | + $messages = true; |
|
363 | + } |
|
364 | + if (!file_exists($newServerThumb)) { |
|
365 | + FlashMessages::addMessage(I18N::translate('The thumbnail file %s does not exist.', Html::filename($newFilename))); |
|
366 | + $messages = true; |
|
367 | + } |
|
368 | + } |
|
369 | + } |
|
370 | + |
|
371 | + // Insert the 1 FILE xxx record into the arrays used by function FunctionsEdit::handle_updatesges() |
|
372 | + $glevels = array_merge(array('1'), $glevels); |
|
373 | + $tag = array_merge(array('FILE'), $tag); |
|
374 | + $islink = array_merge(array(0), $islink); |
|
375 | + $text = array_merge(array($newFilename), $text); |
|
376 | + |
|
377 | + $record = GedcomRecord::getInstance($pid, $WT_TREE); |
|
378 | + $newrec = "0 @$pid@ OBJE\n"; |
|
379 | + $newrec = FunctionsEdit::handleUpdates($newrec); |
|
380 | + $record->updateRecord($newrec, $update_CHAN); |
|
381 | + |
|
382 | + if ($move_file) { |
|
383 | + // We've moved a file. Therefore we must approve the change, as rejecting |
|
384 | + // the change will create broken references. |
|
385 | + FunctionsImport::acceptAllChanges($record->getXref(), $record->getTree()->getTreeId()); |
|
386 | + } |
|
387 | + |
|
388 | + if ($pid && $linktoid) { |
|
389 | + $record = GedcomRecord::getInstance($linktoid, $WT_TREE); |
|
390 | + $record->createFact('1 OBJE @' . $pid . '@', true); |
|
391 | + Log::addEditLog('Media ID ' . $pid . " successfully added to $linktoid."); |
|
392 | + } |
|
393 | + $controller->pageHeader(); |
|
394 | + if ($messages) { |
|
395 | + echo '<button onclick="closePopupAndReloadParent();">', I18N::translate('close'), '</button>'; |
|
396 | + } else { |
|
397 | + $controller->addInlineJavascript('closePopupAndReloadParent();'); |
|
398 | + } |
|
399 | + |
|
400 | + return; |
|
401 | 401 | case 'showmediaform': |
402 | - $controller->setPageTitle(I18N::translate('Create a media object')); |
|
403 | - $action = 'create'; |
|
404 | - break; |
|
402 | + $controller->setPageTitle(I18N::translate('Create a media object')); |
|
403 | + $action = 'create'; |
|
404 | + break; |
|
405 | 405 | case 'editmedia': |
406 | - $controller->setPageTitle(I18N::translate('Edit the media object')); |
|
407 | - $action = 'update'; |
|
408 | - break; |
|
406 | + $controller->setPageTitle(I18N::translate('Edit the media object')); |
|
407 | + $action = 'update'; |
|
408 | + break; |
|
409 | 409 | default: |
410 | - throw new \Exception('Bad $action (' . $action . ') in addmedia.php'); |
|
410 | + throw new \Exception('Bad $action (' . $action . ') in addmedia.php'); |
|
411 | 411 | } |
412 | 412 | |
413 | 413 | $controller->pageHeader(); |
@@ -418,140 +418,140 @@ discard block |
||
418 | 418 | echo '<input type="hidden" name="ged" value="', $WT_TREE->getNameHtml(), '">'; |
419 | 419 | echo '<input type="hidden" name="pid" value="', $pid, '">'; |
420 | 420 | if ($linktoid) { |
421 | - echo '<input type="hidden" name="linktoid" value="', $linktoid, '">'; |
|
421 | + echo '<input type="hidden" name="linktoid" value="', $linktoid, '">'; |
|
422 | 422 | } |
423 | 423 | echo '<table class="facts_table">'; |
424 | 424 | echo '<tr><td class="topbottombar" colspan="2">'; |
425 | 425 | echo $controller->getPageTitle(), FunctionsPrint::helpLink('OBJE'); |
426 | 426 | echo '</td></tr>'; |
427 | 427 | if (!$linktoid && $action == 'create') { |
428 | - echo '<tr><td class="descriptionbox wrap width25">'; |
|
429 | - echo I18N::translate('Enter an individual, family, or source ID'); |
|
430 | - echo '</td><td class="optionbox wrap"><input type="text" data-autocomplete-type="IFS" name="linktoid" id="linktoid" size="6" value="">'; |
|
431 | - echo ' ', FunctionsPrint::printFindIndividualLink('linktoid'); |
|
432 | - echo ' ', FunctionsPrint::printFindFamilyLink('linktoid'); |
|
433 | - echo ' ', FunctionsPrint::printFindSourceLink('linktoid'); |
|
434 | - echo '<p class="small text-muted">', I18N::translate('Enter or search for the ID of the individual, family, or source to which this media object should be linked.'), '</p></td></tr>'; |
|
428 | + echo '<tr><td class="descriptionbox wrap width25">'; |
|
429 | + echo I18N::translate('Enter an individual, family, or source ID'); |
|
430 | + echo '</td><td class="optionbox wrap"><input type="text" data-autocomplete-type="IFS" name="linktoid" id="linktoid" size="6" value="">'; |
|
431 | + echo ' ', FunctionsPrint::printFindIndividualLink('linktoid'); |
|
432 | + echo ' ', FunctionsPrint::printFindFamilyLink('linktoid'); |
|
433 | + echo ' ', FunctionsPrint::printFindSourceLink('linktoid'); |
|
434 | + echo '<p class="small text-muted">', I18N::translate('Enter or search for the ID of the individual, family, or source to which this media object should be linked.'), '</p></td></tr>'; |
|
435 | 435 | } |
436 | 436 | |
437 | 437 | if ($media) { |
438 | - $gedrec = $media->getGedcom(); |
|
438 | + $gedrec = $media->getGedcom(); |
|
439 | 439 | } else { |
440 | - $gedrec = ''; |
|
440 | + $gedrec = ''; |
|
441 | 441 | } |
442 | 442 | |
443 | 443 | // 1 FILE |
444 | 444 | if (preg_match('/\n\d (FILE.*)/', $gedrec, $match)) { |
445 | - $gedfile = $match[1]; |
|
445 | + $gedfile = $match[1]; |
|
446 | 446 | } elseif ($filename) { |
447 | - $gedfile = 'FILE ' . $filename; |
|
447 | + $gedfile = 'FILE ' . $filename; |
|
448 | 448 | } else { |
449 | - $gedfile = 'FILE'; |
|
449 | + $gedfile = 'FILE'; |
|
450 | 450 | } |
451 | 451 | |
452 | 452 | if ($gedfile == 'FILE') { |
453 | - // Box for user to choose to upload file from local computer |
|
454 | - echo '<tr><td class="descriptionbox wrap width25">'; |
|
455 | - echo I18N::translate('Media file to upload') . '</td><td class="optionbox wrap"><input type="file" name="mediafile" onchange="updateFormat(this.value);" size="40"></td></tr>'; |
|
456 | - // Check for thumbnail generation support |
|
457 | - if (Auth::isManager($WT_TREE)) { |
|
458 | - echo '<tr><td class="descriptionbox wrap width25">'; |
|
459 | - echo I18N::translate('Thumbnail to upload') . '</td><td class="optionbox wrap"><input type="file" name="thumbnail" size="40">'; |
|
460 | - echo '<p class="small text-muted">', I18N::translate('Choose the thumbnail image that you want to upload. Although thumbnails can be generated automatically for images, you may wish to generate your own thumbnail, especially for other media types. For example, you can provide a still image from a video, or a photograph of the individual who made an audio recording.'), '</p>'; |
|
461 | - echo '</td></tr>'; |
|
462 | - } |
|
453 | + // Box for user to choose to upload file from local computer |
|
454 | + echo '<tr><td class="descriptionbox wrap width25">'; |
|
455 | + echo I18N::translate('Media file to upload') . '</td><td class="optionbox wrap"><input type="file" name="mediafile" onchange="updateFormat(this.value);" size="40"></td></tr>'; |
|
456 | + // Check for thumbnail generation support |
|
457 | + if (Auth::isManager($WT_TREE)) { |
|
458 | + echo '<tr><td class="descriptionbox wrap width25">'; |
|
459 | + echo I18N::translate('Thumbnail to upload') . '</td><td class="optionbox wrap"><input type="file" name="thumbnail" size="40">'; |
|
460 | + echo '<p class="small text-muted">', I18N::translate('Choose the thumbnail image that you want to upload. Although thumbnails can be generated automatically for images, you may wish to generate your own thumbnail, especially for other media types. For example, you can provide a still image from a video, or a photograph of the individual who made an audio recording.'), '</p>'; |
|
461 | + echo '</td></tr>'; |
|
462 | + } |
|
463 | 463 | } |
464 | 464 | |
465 | 465 | // Filename on server |
466 | 466 | $isExternal = Functions::isFileExternal($gedfile); |
467 | 467 | if ($gedfile == 'FILE') { |
468 | - if (Auth::isManager($WT_TREE)) { |
|
469 | - FunctionsEdit::addSimpleTag( |
|
470 | - "1 $gedfile", |
|
471 | - '', |
|
472 | - I18N::translate('Filename on server'), |
|
473 | - '<p class="small text-muted">' . I18N::translate('Do not change to keep original filename.') . '<br>' . I18N::translate('You may enter a URL, beginning with “http://”.') . '</p>' |
|
474 | - ); |
|
475 | - } |
|
476 | - $folder = ''; |
|
468 | + if (Auth::isManager($WT_TREE)) { |
|
469 | + FunctionsEdit::addSimpleTag( |
|
470 | + "1 $gedfile", |
|
471 | + '', |
|
472 | + I18N::translate('Filename on server'), |
|
473 | + '<p class="small text-muted">' . I18N::translate('Do not change to keep original filename.') . '<br>' . I18N::translate('You may enter a URL, beginning with “http://”.') . '</p>' |
|
474 | + ); |
|
475 | + } |
|
476 | + $folder = ''; |
|
477 | 477 | } else { |
478 | - if ($isExternal) { |
|
479 | - $fileName = substr($gedfile, 5); |
|
480 | - $folder = ''; |
|
481 | - } else { |
|
482 | - $tmp = substr($gedfile, 5); |
|
483 | - $fileName = basename($tmp); |
|
484 | - $folder = dirname($tmp); |
|
485 | - if ($folder === '.') { |
|
486 | - $folder = ''; |
|
487 | - } |
|
488 | - } |
|
489 | - |
|
490 | - echo '<tr>'; |
|
491 | - echo '<td class="descriptionbox wrap width25">'; |
|
492 | - echo I18N::translate('Filename on server'); |
|
493 | - echo '</td>'; |
|
494 | - echo '<td class="optionbox wrap wrap">'; |
|
495 | - if (Auth::isManager($WT_TREE)) { |
|
496 | - echo '<input name="filename" type="text" value="' . Filter::escapeHtml($fileName) . '" size="40"'; |
|
497 | - if ($isExternal) { |
|
498 | - echo '>'; |
|
499 | - } else { |
|
500 | - echo '><p class="small text-muted">' . I18N::translate('Do not change to keep original filename.') . '</p>'; |
|
501 | - } |
|
502 | - } else { |
|
503 | - echo $fileName; |
|
504 | - echo '<input name="filename" type="hidden" value="' . Filter::escapeHtml($fileName) . '" size="40">'; |
|
505 | - } |
|
506 | - echo '</td>'; |
|
507 | - echo '</tr>'; |
|
478 | + if ($isExternal) { |
|
479 | + $fileName = substr($gedfile, 5); |
|
480 | + $folder = ''; |
|
481 | + } else { |
|
482 | + $tmp = substr($gedfile, 5); |
|
483 | + $fileName = basename($tmp); |
|
484 | + $folder = dirname($tmp); |
|
485 | + if ($folder === '.') { |
|
486 | + $folder = ''; |
|
487 | + } |
|
488 | + } |
|
489 | + |
|
490 | + echo '<tr>'; |
|
491 | + echo '<td class="descriptionbox wrap width25">'; |
|
492 | + echo I18N::translate('Filename on server'); |
|
493 | + echo '</td>'; |
|
494 | + echo '<td class="optionbox wrap wrap">'; |
|
495 | + if (Auth::isManager($WT_TREE)) { |
|
496 | + echo '<input name="filename" type="text" value="' . Filter::escapeHtml($fileName) . '" size="40"'; |
|
497 | + if ($isExternal) { |
|
498 | + echo '>'; |
|
499 | + } else { |
|
500 | + echo '><p class="small text-muted">' . I18N::translate('Do not change to keep original filename.') . '</p>'; |
|
501 | + } |
|
502 | + } else { |
|
503 | + echo $fileName; |
|
504 | + echo '<input name="filename" type="hidden" value="' . Filter::escapeHtml($fileName) . '" size="40">'; |
|
505 | + } |
|
506 | + echo '</td>'; |
|
507 | + echo '</tr>'; |
|
508 | 508 | } |
509 | 509 | |
510 | 510 | // Box for user to choose the folder to store the image |
511 | 511 | if (!$isExternal) { |
512 | - echo '<tr><td class="descriptionbox wrap width25">'; |
|
513 | - echo I18N::translate('Folder name on server'), '</td><td class="optionbox wrap">'; |
|
514 | - //-- don’t let regular users change the location of media items |
|
515 | - if ($action !== 'update' || Auth::isManager($WT_TREE)) { |
|
516 | - $mediaFolders = QueryMedia::folderList(); |
|
517 | - echo '<select name="folder_list" onchange="document.newmedia.folder.value=this.options[this.selectedIndex].value;">'; |
|
518 | - echo '<option '; |
|
519 | - if ($folder == '') { |
|
520 | - echo 'selected'; |
|
521 | - } |
|
522 | - echo ' value=""> ', I18N::translate('Choose: '), ' </option>'; |
|
523 | - if (Auth::isAdmin()) { |
|
524 | - echo '<option value="other" disabled>', I18N::translate('Other folder… please type in'), "</option>"; |
|
525 | - } |
|
526 | - foreach ($mediaFolders as $f) { |
|
527 | - echo '<option value="', $f, '" '; |
|
528 | - if ($folder == $f) { |
|
529 | - echo 'selected'; |
|
530 | - } |
|
531 | - echo '>', $f, "</option>"; |
|
532 | - } |
|
533 | - echo '</select>'; |
|
534 | - } else { |
|
535 | - echo $folder; |
|
536 | - } |
|
537 | - if (Auth::isAdmin()) { |
|
538 | - echo '<br><input type="text" name="folder" size="40" value="', $folder, '">'; |
|
539 | - if ($gedfile === 'FILE') { |
|
540 | - echo '<p class="small text-muted">', I18N::translate('This entry is ignored if you have entered a URL into the filename field.'), '</p>'; |
|
541 | - } |
|
542 | - } else { |
|
543 | - echo '<input name="folder" type="hidden" value="', Filter::escapeHtml($folder), '">'; |
|
544 | - } |
|
545 | - echo '<p class="small text-muted">', I18N::translate('If you have a large number of media files, you can organize them into folders and subfolders.'), '</p>'; echo '</td></tr>'; |
|
512 | + echo '<tr><td class="descriptionbox wrap width25">'; |
|
513 | + echo I18N::translate('Folder name on server'), '</td><td class="optionbox wrap">'; |
|
514 | + //-- don’t let regular users change the location of media items |
|
515 | + if ($action !== 'update' || Auth::isManager($WT_TREE)) { |
|
516 | + $mediaFolders = QueryMedia::folderList(); |
|
517 | + echo '<select name="folder_list" onchange="document.newmedia.folder.value=this.options[this.selectedIndex].value;">'; |
|
518 | + echo '<option '; |
|
519 | + if ($folder == '') { |
|
520 | + echo 'selected'; |
|
521 | + } |
|
522 | + echo ' value=""> ', I18N::translate('Choose: '), ' </option>'; |
|
523 | + if (Auth::isAdmin()) { |
|
524 | + echo '<option value="other" disabled>', I18N::translate('Other folder… please type in'), "</option>"; |
|
525 | + } |
|
526 | + foreach ($mediaFolders as $f) { |
|
527 | + echo '<option value="', $f, '" '; |
|
528 | + if ($folder == $f) { |
|
529 | + echo 'selected'; |
|
530 | + } |
|
531 | + echo '>', $f, "</option>"; |
|
532 | + } |
|
533 | + echo '</select>'; |
|
534 | + } else { |
|
535 | + echo $folder; |
|
536 | + } |
|
537 | + if (Auth::isAdmin()) { |
|
538 | + echo '<br><input type="text" name="folder" size="40" value="', $folder, '">'; |
|
539 | + if ($gedfile === 'FILE') { |
|
540 | + echo '<p class="small text-muted">', I18N::translate('This entry is ignored if you have entered a URL into the filename field.'), '</p>'; |
|
541 | + } |
|
542 | + } else { |
|
543 | + echo '<input name="folder" type="hidden" value="', Filter::escapeHtml($folder), '">'; |
|
544 | + } |
|
545 | + echo '<p class="small text-muted">', I18N::translate('If you have a large number of media files, you can organize them into folders and subfolders.'), '</p>'; echo '</td></tr>'; |
|
546 | 546 | } else { |
547 | - echo '<input name="folder" type="hidden" value="">'; |
|
547 | + echo '<input name="folder" type="hidden" value="">'; |
|
548 | 548 | } |
549 | 549 | |
550 | 550 | // 1 FILE / 2 FORM |
551 | 551 | if (preg_match('/\n(2 FORM .*)/', $gedrec, $match)) { |
552 | - $gedform = $match[1]; |
|
552 | + $gedform = $match[1]; |
|
553 | 553 | } else { |
554 | - $gedform = '2 FORM'; |
|
554 | + $gedform = '2 FORM'; |
|
555 | 555 | } |
556 | 556 | $formid = FunctionsEdit::addSimpleTag($gedform); |
557 | 557 | |
@@ -573,45 +573,45 @@ discard block |
||
573 | 573 | |
574 | 574 | // 1 FILE / 2 FORM / 3 TYPE |
575 | 575 | if (preg_match('/\n(3 TYPE .*)/', $gedrec, $match)) { |
576 | - $gedtype = $match[1]; |
|
576 | + $gedtype = $match[1]; |
|
577 | 577 | } else { |
578 | - $gedtype = '3 TYPE photo'; // default to ‘Photo’ |
|
578 | + $gedtype = '3 TYPE photo'; // default to ‘Photo’ |
|
579 | 579 | } |
580 | 580 | FunctionsEdit::addSimpleTag($gedtype); |
581 | 581 | |
582 | 582 | // 1 FILE / 2 TITL |
583 | 583 | if (preg_match('/\n(2 TITL .*)/', $gedrec, $match)) { |
584 | - $gedtitl = $match[1]; |
|
584 | + $gedtitl = $match[1]; |
|
585 | 585 | } else { |
586 | - $gedtitl = '2 TITL'; |
|
586 | + $gedtitl = '2 TITL'; |
|
587 | 587 | } |
588 | 588 | FunctionsEdit::addSimpleTag($gedtitl); |
589 | 589 | |
590 | 590 | // 1 FILE / 2 TITL / 3 _HEB |
591 | 591 | if (strstr($WT_TREE->getPreference('ADVANCED_NAME_FACTS'), '_HEB') !== false) { |
592 | - if (preg_match('/\n(3 _HEB .*)/', $gedrec, $match)) { |
|
593 | - $gedtitl = $match[1]; |
|
594 | - } else { |
|
595 | - $gedtitl = '3 _HEB'; |
|
596 | - } |
|
597 | - FunctionsEdit::addSimpleTag($gedtitl); |
|
592 | + if (preg_match('/\n(3 _HEB .*)/', $gedrec, $match)) { |
|
593 | + $gedtitl = $match[1]; |
|
594 | + } else { |
|
595 | + $gedtitl = '3 _HEB'; |
|
596 | + } |
|
597 | + FunctionsEdit::addSimpleTag($gedtitl); |
|
598 | 598 | } |
599 | 599 | |
600 | 600 | // 1 FILE / 2 TITL / 3 ROMN |
601 | 601 | if (strstr($WT_TREE->getPreference('ADVANCED_NAME_FACTS'), 'ROMN') !== false) { |
602 | - if (preg_match('/\n(3 ROMN .*)/', $gedrec, $match)) { |
|
603 | - $gedtitl = $match[1]; |
|
604 | - } else { |
|
605 | - $gedtitl = '3 ROMN'; |
|
606 | - } |
|
607 | - FunctionsEdit::addSimpleTag($gedtitl); |
|
602 | + if (preg_match('/\n(3 ROMN .*)/', $gedrec, $match)) { |
|
603 | + $gedtitl = $match[1]; |
|
604 | + } else { |
|
605 | + $gedtitl = '3 ROMN'; |
|
606 | + } |
|
607 | + FunctionsEdit::addSimpleTag($gedtitl); |
|
608 | 608 | } |
609 | 609 | |
610 | 610 | // 1 _PRIM |
611 | 611 | if (preg_match('/\n(1 _PRIM .*)/', $gedrec, $match)) { |
612 | - $gedprim = $match[1]; |
|
612 | + $gedprim = $match[1]; |
|
613 | 613 | } else { |
614 | - $gedprim = '1 _PRIM'; |
|
614 | + $gedprim = '1 _PRIM'; |
|
615 | 615 | } |
616 | 616 | FunctionsEdit::addSimpleTag($gedprim); |
617 | 617 | |
@@ -623,87 +623,87 @@ discard block |
||
623 | 623 | $sourceDATE = ''; |
624 | 624 | $sourceQUAY = ''; |
625 | 625 | if (!empty($gedrec)) { |
626 | - preg_match_all('/\n(1 (?!FILE|FORM|TYPE|TITL|_PRIM|_THUM|CHAN|DATA).*(\n[2-9] .*)*)/', $gedrec, $matches); |
|
627 | - foreach ($matches[1] as $subrec) { |
|
628 | - $pieces = explode("\n", $subrec); |
|
629 | - foreach ($pieces as $piece) { |
|
630 | - $ft = preg_match("/(\d) (\w+)(.*)/", $piece, $match); |
|
631 | - if ($ft == 0) { |
|
632 | - continue; |
|
633 | - } |
|
634 | - $subLevel = $match[1]; |
|
635 | - $fact = trim($match[2]); |
|
636 | - $event = trim($match[3]); |
|
637 | - if ($fact === 'NOTE' || $fact === 'TEXT') { |
|
638 | - $event .= Functions::getCont($subLevel + 1, $subrec); |
|
639 | - } |
|
640 | - if ($sourceSOUR !== '' && $subLevel <= $sourceLevel) { |
|
641 | - // Get rid of all saved Source data |
|
642 | - FunctionsEdit::addSimpleTag($sourceLevel . ' SOUR ' . $sourceSOUR); |
|
643 | - FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' PAGE ' . $sourcePAGE); |
|
644 | - FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' TEXT ' . $sourceTEXT); |
|
645 | - FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' DATE ' . $sourceDATE, '', GedcomTag::getLabel('DATA:DATE')); |
|
646 | - FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' QUAY ' . $sourceQUAY); |
|
647 | - $sourceSOUR = ''; |
|
648 | - } |
|
649 | - |
|
650 | - if ($fact === 'SOUR') { |
|
651 | - $sourceLevel = $subLevel; |
|
652 | - $sourceSOUR = $event; |
|
653 | - $sourcePAGE = ''; |
|
654 | - $sourceTEXT = ''; |
|
655 | - $sourceDATE = ''; |
|
656 | - $sourceQUAY = ''; |
|
657 | - continue; |
|
658 | - } |
|
659 | - |
|
660 | - // Save all incoming data about this source reference |
|
661 | - if ($sourceSOUR !== '') { |
|
662 | - if ($fact === 'PAGE') { |
|
663 | - $sourcePAGE = $event; |
|
664 | - continue; |
|
665 | - } |
|
666 | - if ($fact === 'TEXT') { |
|
667 | - $sourceTEXT = $event; |
|
668 | - continue; |
|
669 | - } |
|
670 | - if ($fact === 'DATE') { |
|
671 | - $sourceDATE = $event; |
|
672 | - continue; |
|
673 | - } |
|
674 | - if ($fact === 'QUAY') { |
|
675 | - $sourceQUAY = $event; |
|
676 | - continue; |
|
677 | - } |
|
678 | - continue; |
|
679 | - } |
|
680 | - |
|
681 | - // Output anything that isn’t part of a source reference |
|
682 | - if (!empty($fact) && $fact !== 'CONC' && $fact !== 'CONT' && $fact !== 'DATA') { |
|
683 | - FunctionsEdit::addSimpleTag($subLevel . ' ' . $fact . ' ' . $event); |
|
684 | - } |
|
685 | - } |
|
686 | - } |
|
687 | - |
|
688 | - if ($sourceSOUR !== '') { |
|
689 | - // Get rid of all saved Source data |
|
690 | - FunctionsEdit::addSimpleTag($sourceLevel . ' SOUR ' . $sourceSOUR); |
|
691 | - FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' PAGE ' . $sourcePAGE); |
|
692 | - FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' TEXT ' . $sourceTEXT); |
|
693 | - FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' DATE ' . $sourceDATE, '', GedcomTag::getLabel('DATA:DATE')); |
|
694 | - FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' QUAY ' . $sourceQUAY); |
|
695 | - } |
|
626 | + preg_match_all('/\n(1 (?!FILE|FORM|TYPE|TITL|_PRIM|_THUM|CHAN|DATA).*(\n[2-9] .*)*)/', $gedrec, $matches); |
|
627 | + foreach ($matches[1] as $subrec) { |
|
628 | + $pieces = explode("\n", $subrec); |
|
629 | + foreach ($pieces as $piece) { |
|
630 | + $ft = preg_match("/(\d) (\w+)(.*)/", $piece, $match); |
|
631 | + if ($ft == 0) { |
|
632 | + continue; |
|
633 | + } |
|
634 | + $subLevel = $match[1]; |
|
635 | + $fact = trim($match[2]); |
|
636 | + $event = trim($match[3]); |
|
637 | + if ($fact === 'NOTE' || $fact === 'TEXT') { |
|
638 | + $event .= Functions::getCont($subLevel + 1, $subrec); |
|
639 | + } |
|
640 | + if ($sourceSOUR !== '' && $subLevel <= $sourceLevel) { |
|
641 | + // Get rid of all saved Source data |
|
642 | + FunctionsEdit::addSimpleTag($sourceLevel . ' SOUR ' . $sourceSOUR); |
|
643 | + FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' PAGE ' . $sourcePAGE); |
|
644 | + FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' TEXT ' . $sourceTEXT); |
|
645 | + FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' DATE ' . $sourceDATE, '', GedcomTag::getLabel('DATA:DATE')); |
|
646 | + FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' QUAY ' . $sourceQUAY); |
|
647 | + $sourceSOUR = ''; |
|
648 | + } |
|
649 | + |
|
650 | + if ($fact === 'SOUR') { |
|
651 | + $sourceLevel = $subLevel; |
|
652 | + $sourceSOUR = $event; |
|
653 | + $sourcePAGE = ''; |
|
654 | + $sourceTEXT = ''; |
|
655 | + $sourceDATE = ''; |
|
656 | + $sourceQUAY = ''; |
|
657 | + continue; |
|
658 | + } |
|
659 | + |
|
660 | + // Save all incoming data about this source reference |
|
661 | + if ($sourceSOUR !== '') { |
|
662 | + if ($fact === 'PAGE') { |
|
663 | + $sourcePAGE = $event; |
|
664 | + continue; |
|
665 | + } |
|
666 | + if ($fact === 'TEXT') { |
|
667 | + $sourceTEXT = $event; |
|
668 | + continue; |
|
669 | + } |
|
670 | + if ($fact === 'DATE') { |
|
671 | + $sourceDATE = $event; |
|
672 | + continue; |
|
673 | + } |
|
674 | + if ($fact === 'QUAY') { |
|
675 | + $sourceQUAY = $event; |
|
676 | + continue; |
|
677 | + } |
|
678 | + continue; |
|
679 | + } |
|
680 | + |
|
681 | + // Output anything that isn’t part of a source reference |
|
682 | + if (!empty($fact) && $fact !== 'CONC' && $fact !== 'CONT' && $fact !== 'DATA') { |
|
683 | + FunctionsEdit::addSimpleTag($subLevel . ' ' . $fact . ' ' . $event); |
|
684 | + } |
|
685 | + } |
|
686 | + } |
|
687 | + |
|
688 | + if ($sourceSOUR !== '') { |
|
689 | + // Get rid of all saved Source data |
|
690 | + FunctionsEdit::addSimpleTag($sourceLevel . ' SOUR ' . $sourceSOUR); |
|
691 | + FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' PAGE ' . $sourcePAGE); |
|
692 | + FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' TEXT ' . $sourceTEXT); |
|
693 | + FunctionsEdit::addSimpleTag(($sourceLevel + 2) . ' DATE ' . $sourceDATE, '', GedcomTag::getLabel('DATA:DATE')); |
|
694 | + FunctionsEdit::addSimpleTag(($sourceLevel + 1) . ' QUAY ' . $sourceQUAY); |
|
695 | + } |
|
696 | 696 | } |
697 | 697 | if (Auth::isAdmin() && $action === 'update') { |
698 | - echo '<tr><td class="descriptionbox wrap width25">'; |
|
699 | - echo GedcomTag::getLabel('CHAN'), '</td><td class="optionbox wrap">'; |
|
700 | - if ($NO_UPDATE_CHAN) { |
|
701 | - echo '<input type="checkbox" checked name="preserve_last_changed">'; |
|
702 | - } else { |
|
703 | - echo '<input type="checkbox" name="preserve_last_changed">'; |
|
704 | - } |
|
705 | - echo I18N::translate('Keep the existing “last change” information'), '<br>'; |
|
706 | - echo '</td></tr>'; |
|
698 | + echo '<tr><td class="descriptionbox wrap width25">'; |
|
699 | + echo GedcomTag::getLabel('CHAN'), '</td><td class="optionbox wrap">'; |
|
700 | + if ($NO_UPDATE_CHAN) { |
|
701 | + echo '<input type="checkbox" checked name="preserve_last_changed">'; |
|
702 | + } else { |
|
703 | + echo '<input type="checkbox" name="preserve_last_changed">'; |
|
704 | + } |
|
705 | + echo I18N::translate('Keep the existing “last change” information'), '<br>'; |
|
706 | + echo '</td></tr>'; |
|
707 | 707 | } |
708 | 708 | echo '</table>'; |
709 | 709 | FunctionsEdit::printAddLayer('SOUR', 1); |
@@ -31,9 +31,9 @@ discard block |
||
31 | 31 | |
32 | 32 | // Need to be logged in |
33 | 33 | if (!Auth::check()) { |
34 | - header('Location: ' . WT_BASE_URL); |
|
34 | + header('Location: ' . WT_BASE_URL); |
|
35 | 35 | |
36 | - return; |
|
36 | + return; |
|
37 | 37 | } |
38 | 38 | |
39 | 39 | // Extract form variables |
@@ -52,66 +52,66 @@ discard block |
||
52 | 52 | |
53 | 53 | // Respond to form action |
54 | 54 | if ($form_action && Filter::checkCsrf()) { |
55 | - switch ($form_action) { |
|
56 | - case 'update': |
|
57 | - if ($form_username !== Auth::user()->getUserName() && User::findByUserName($form_username)) { |
|
58 | - FlashMessages::addMessage(I18N::translate('Duplicate username. A user with that username already exists. Please choose another username.')); |
|
59 | - } elseif ($form_email !== Auth::user()->getEmail() && User::findByEmail($form_email)) { |
|
60 | - FlashMessages::addMessage(I18N::translate('Duplicate email address. A user with that email already exists.')); |
|
61 | - } else { |
|
62 | - // Change username |
|
63 | - if ($form_username !== Auth::user()->getUserName()) { |
|
64 | - Log::addAuthenticationLog('User ' . Auth::user()->getUserName() . ' renamed to ' . $form_username); |
|
65 | - Auth::user()->setUserName($form_username); |
|
66 | - } |
|
67 | - |
|
68 | - // Change password |
|
69 | - if ($form_pass1 && $form_pass1 === $form_pass2) { |
|
70 | - Auth::user()->setPassword($form_pass1); |
|
71 | - } |
|
72 | - |
|
73 | - // Change other settings |
|
74 | - Auth::user() |
|
75 | - ->setRealName($form_realname) |
|
76 | - ->setEmail($form_email) |
|
77 | - ->setPreference('language', $form_language) |
|
78 | - ->setPreference('TIMEZONE', $form_timezone) |
|
79 | - ->setPreference('contactmethod', $form_contact_method) |
|
80 | - ->setPreference('visibleonline', $form_visible_online ? '1' : '0'); |
|
81 | - |
|
82 | - if ($form_theme === null) { |
|
83 | - Auth::user()->deletePreference('theme'); |
|
84 | - } else { |
|
85 | - Auth::user()->setPreference('theme', $form_theme); |
|
86 | - } |
|
87 | - |
|
88 | - $WT_TREE->setUserPreference(Auth::user(), 'rootid', $form_rootid); |
|
89 | - } |
|
90 | - break; |
|
91 | - |
|
92 | - case 'delete': |
|
93 | - // An administrator can only be deleted by another administrator |
|
94 | - if (!Auth::user()->getPreference('canadmin')) { |
|
95 | - // Keep a reference to the currently logged in user because after logging out this user, |
|
96 | - // a call to Auth::user() will not return this user anymore |
|
97 | - $currentUser = Auth::user(); |
|
98 | - Auth::logout(); |
|
99 | - $currentUser->delete(); |
|
100 | - } |
|
101 | - break; |
|
102 | - } |
|
103 | - |
|
104 | - header('Location: ' . WT_BASE_URL . WT_SCRIPT_NAME); |
|
105 | - |
|
106 | - return; |
|
55 | + switch ($form_action) { |
|
56 | + case 'update': |
|
57 | + if ($form_username !== Auth::user()->getUserName() && User::findByUserName($form_username)) { |
|
58 | + FlashMessages::addMessage(I18N::translate('Duplicate username. A user with that username already exists. Please choose another username.')); |
|
59 | + } elseif ($form_email !== Auth::user()->getEmail() && User::findByEmail($form_email)) { |
|
60 | + FlashMessages::addMessage(I18N::translate('Duplicate email address. A user with that email already exists.')); |
|
61 | + } else { |
|
62 | + // Change username |
|
63 | + if ($form_username !== Auth::user()->getUserName()) { |
|
64 | + Log::addAuthenticationLog('User ' . Auth::user()->getUserName() . ' renamed to ' . $form_username); |
|
65 | + Auth::user()->setUserName($form_username); |
|
66 | + } |
|
67 | + |
|
68 | + // Change password |
|
69 | + if ($form_pass1 && $form_pass1 === $form_pass2) { |
|
70 | + Auth::user()->setPassword($form_pass1); |
|
71 | + } |
|
72 | + |
|
73 | + // Change other settings |
|
74 | + Auth::user() |
|
75 | + ->setRealName($form_realname) |
|
76 | + ->setEmail($form_email) |
|
77 | + ->setPreference('language', $form_language) |
|
78 | + ->setPreference('TIMEZONE', $form_timezone) |
|
79 | + ->setPreference('contactmethod', $form_contact_method) |
|
80 | + ->setPreference('visibleonline', $form_visible_online ? '1' : '0'); |
|
81 | + |
|
82 | + if ($form_theme === null) { |
|
83 | + Auth::user()->deletePreference('theme'); |
|
84 | + } else { |
|
85 | + Auth::user()->setPreference('theme', $form_theme); |
|
86 | + } |
|
87 | + |
|
88 | + $WT_TREE->setUserPreference(Auth::user(), 'rootid', $form_rootid); |
|
89 | + } |
|
90 | + break; |
|
91 | + |
|
92 | + case 'delete': |
|
93 | + // An administrator can only be deleted by another administrator |
|
94 | + if (!Auth::user()->getPreference('canadmin')) { |
|
95 | + // Keep a reference to the currently logged in user because after logging out this user, |
|
96 | + // a call to Auth::user() will not return this user anymore |
|
97 | + $currentUser = Auth::user(); |
|
98 | + Auth::logout(); |
|
99 | + $currentUser->delete(); |
|
100 | + } |
|
101 | + break; |
|
102 | + } |
|
103 | + |
|
104 | + header('Location: ' . WT_BASE_URL . WT_SCRIPT_NAME); |
|
105 | + |
|
106 | + return; |
|
107 | 107 | } |
108 | 108 | |
109 | 109 | $controller = new PageController; |
110 | 110 | $controller |
111 | - ->setPageTitle(I18N::translate('My account')) |
|
112 | - ->pageHeader() |
|
113 | - ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL) |
|
114 | - ->addInlineJavascript('autocomplete();'); |
|
111 | + ->setPageTitle(I18N::translate('My account')) |
|
112 | + ->pageHeader() |
|
113 | + ->addExternalJavascript(WT_AUTOCOMPLETE_JS_URL) |
|
114 | + ->addInlineJavascript('autocomplete();'); |
|
115 | 115 | |
116 | 116 | $my_individual_record = Individual::getInstance($WT_TREE->getUserPreference(Auth::user(), 'gedcomid'), $WT_TREE); |
117 | 117 | $default_individual = Individual::getInstance($WT_TREE->getUserPreference(Auth::user(), 'rootid'), $WT_TREE); |
@@ -19,401 +19,401 @@ |
||
19 | 19 | * A GEDCOM family (FAM) object. |
20 | 20 | */ |
21 | 21 | class Family extends GedcomRecord { |
22 | - const RECORD_TYPE = 'FAM'; |
|
23 | - const URL_PREFIX = 'family.php?famid='; |
|
24 | - |
|
25 | - /** @var Individual|null The husband (or first spouse for same-sex couples) */ |
|
26 | - private $husb; |
|
27 | - |
|
28 | - /** @var Individual|null The wife (or second spouse for same-sex couples) */ |
|
29 | - private $wife; |
|
30 | - |
|
31 | - /** |
|
32 | - * Create a GedcomRecord object from raw GEDCOM data. |
|
33 | - * |
|
34 | - * @param string $xref |
|
35 | - * @param string $gedcom an empty string for new/pending records |
|
36 | - * @param string|null $pending null for a record with no pending edits, |
|
37 | - * empty string for records with pending deletions |
|
38 | - * @param Tree $tree |
|
39 | - */ |
|
40 | - public function __construct($xref, $gedcom, $pending, $tree) { |
|
41 | - parent::__construct($xref, $gedcom, $pending, $tree); |
|
42 | - |
|
43 | - // Fetch family members |
|
44 | - if (preg_match_all('/^1 (?:HUSB|WIFE|CHIL) @(.+)@/m', $gedcom . $pending, $match)) { |
|
45 | - Individual::load($tree, $match[1]); |
|
46 | - } |
|
47 | - |
|
48 | - if (preg_match('/^1 HUSB @(.+)@/m', $gedcom . $pending, $match)) { |
|
49 | - $this->husb = Individual::getInstance($match[1], $tree); |
|
50 | - } |
|
51 | - if (preg_match('/^1 WIFE @(.+)@/m', $gedcom . $pending, $match)) { |
|
52 | - $this->wife = Individual::getInstance($match[1], $tree); |
|
53 | - } |
|
54 | - |
|
55 | - // Make sure husb/wife are the right way round. |
|
56 | - if ($this->husb && $this->husb->getSex() === 'F' || $this->wife && $this->wife->getSex() === 'M') { |
|
57 | - list($this->husb, $this->wife) = array($this->wife, $this->husb); |
|
58 | - } |
|
59 | - } |
|
60 | - |
|
61 | - /** |
|
62 | - * Generate a private version of this record |
|
63 | - * |
|
64 | - * @param int $access_level |
|
65 | - * |
|
66 | - * @return string |
|
67 | - */ |
|
68 | - protected function createPrivateGedcomRecord($access_level) { |
|
69 | - $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); |
|
70 | - |
|
71 | - $rec = '0 @' . $this->xref . '@ FAM'; |
|
72 | - // Just show the 1 CHIL/HUSB/WIFE tag, not any subtags, which may contain private data |
|
73 | - preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @(' . WT_REGEX_XREF . ')@/', $this->gedcom, $matches, PREG_SET_ORDER); |
|
74 | - foreach ($matches as $match) { |
|
75 | - $rela = Individual::getInstance($match[1], $this->tree); |
|
76 | - if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canShow($access_level))) { |
|
77 | - $rec .= $match[0]; |
|
78 | - } |
|
79 | - } |
|
80 | - |
|
81 | - return $rec; |
|
82 | - } |
|
83 | - |
|
84 | - /** |
|
85 | - * Fetch data from the database |
|
86 | - * |
|
87 | - * @param string $xref |
|
88 | - * @param int $tree_id |
|
89 | - * |
|
90 | - * @return null|string |
|
91 | - */ |
|
92 | - protected static function fetchGedcomRecord($xref, $tree_id) { |
|
93 | - return Database::prepare( |
|
94 | - "SELECT f_gedcom FROM `##families` WHERE f_id = :xref AND f_file = :tree_id" |
|
95 | - )->execute(array( |
|
96 | - 'xref' => $xref, |
|
97 | - 'tree_id' => $tree_id, |
|
98 | - ))->fetchOne(); |
|
99 | - } |
|
100 | - |
|
101 | - /** |
|
102 | - * Get the male (or first female) partner of the family |
|
103 | - * |
|
104 | - * @param $access_level int|null |
|
105 | - * |
|
106 | - * @return Individual|null |
|
107 | - */ |
|
108 | - public function getHusband($access_level = null) { |
|
109 | - $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); |
|
110 | - |
|
111 | - if ($this->husb && ($SHOW_PRIVATE_RELATIONSHIPS || $this->husb->canShowName($access_level))) { |
|
112 | - return $this->husb; |
|
113 | - } else { |
|
114 | - return null; |
|
115 | - } |
|
116 | - } |
|
117 | - |
|
118 | - /** |
|
119 | - * Get the female (or second male) partner of the family |
|
120 | - * |
|
121 | - * @param $access_level int|null |
|
122 | - * |
|
123 | - * @return Individual|null |
|
124 | - */ |
|
125 | - public function getWife($access_level = null) { |
|
126 | - $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); |
|
127 | - |
|
128 | - if ($this->wife && ($SHOW_PRIVATE_RELATIONSHIPS || $this->wife->canShowName($access_level))) { |
|
129 | - return $this->wife; |
|
130 | - } else { |
|
131 | - return null; |
|
132 | - } |
|
133 | - } |
|
134 | - |
|
135 | - /** |
|
136 | - * Each object type may have its own special rules, and re-implement this function. |
|
137 | - * |
|
138 | - * @param int $access_level |
|
139 | - * |
|
140 | - * @return bool |
|
141 | - */ |
|
142 | - protected function canShowByType($access_level) { |
|
143 | - // Hide a family if any member is private |
|
144 | - preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @(' . WT_REGEX_XREF . ')@/', $this->gedcom, $matches); |
|
145 | - foreach ($matches[1] as $match) { |
|
146 | - $person = Individual::getInstance($match, $this->tree); |
|
147 | - if ($person && !$person->canShow($access_level)) { |
|
148 | - return false; |
|
149 | - } |
|
150 | - } |
|
151 | - |
|
152 | - return true; |
|
153 | - } |
|
154 | - |
|
155 | - /** |
|
156 | - * Can the name of this record be shown? |
|
157 | - * |
|
158 | - * @param int|null $access_level |
|
159 | - * |
|
160 | - * @return bool |
|
161 | - */ |
|
162 | - public function canShowName($access_level = null) { |
|
163 | - // We can always see the name (Husband-name + Wife-name), however, |
|
164 | - // the name will often be "private + private" |
|
165 | - return true; |
|
166 | - } |
|
167 | - |
|
168 | - /** |
|
169 | - * Find the spouse of a person. |
|
170 | - * |
|
171 | - * @param Individual $person |
|
172 | - * @param int|null $access_level |
|
173 | - * |
|
174 | - * @return Individual|null |
|
175 | - */ |
|
176 | - public function getSpouse(Individual $person, $access_level = null) { |
|
177 | - if ($person === $this->wife) { |
|
178 | - return $this->getHusband($access_level); |
|
179 | - } else { |
|
180 | - return $this->getWife($access_level); |
|
181 | - } |
|
182 | - } |
|
183 | - |
|
184 | - /** |
|
185 | - * Get the (zero, one or two) spouses from this family. |
|
186 | - * |
|
187 | - * @param int|null $access_level |
|
188 | - * |
|
189 | - * @return Individual[] |
|
190 | - */ |
|
191 | - public function getSpouses($access_level = null) { |
|
192 | - return array_filter(array( |
|
193 | - $this->getHusband($access_level), |
|
194 | - $this->getWife($access_level), |
|
195 | - )); |
|
196 | - } |
|
197 | - |
|
198 | - /** |
|
199 | - * Get a list of this family’s children. |
|
200 | - * |
|
201 | - * @param int|null $access_level |
|
202 | - * |
|
203 | - * @return Individual[] |
|
204 | - */ |
|
205 | - public function getChildren($access_level = null) { |
|
206 | - if ($access_level === null) { |
|
207 | - $access_level = Auth::accessLevel($this->tree); |
|
208 | - } |
|
209 | - |
|
210 | - $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); |
|
211 | - |
|
212 | - $children = array(); |
|
213 | - foreach ($this->getFacts('CHIL', false, $access_level, $SHOW_PRIVATE_RELATIONSHIPS) as $fact) { |
|
214 | - $child = $fact->getTarget(); |
|
215 | - if ($child && ($SHOW_PRIVATE_RELATIONSHIPS || $child->canShowName($access_level))) { |
|
216 | - $children[] = $child; |
|
217 | - } |
|
218 | - } |
|
219 | - |
|
220 | - return $children; |
|
221 | - } |
|
222 | - |
|
223 | - /** |
|
224 | - * Static helper function to sort an array of families by marriage date |
|
225 | - * |
|
226 | - * @param Family $x |
|
227 | - * @param Family $y |
|
228 | - * |
|
229 | - * @return int |
|
230 | - */ |
|
231 | - public static function compareMarrDate(Family $x, Family $y) { |
|
232 | - return Date::compare($x->getMarriageDate(), $y->getMarriageDate()); |
|
233 | - } |
|
234 | - |
|
235 | - /** |
|
236 | - * Number of children - for the individual list |
|
237 | - * |
|
238 | - * @return int |
|
239 | - */ |
|
240 | - public function getNumberOfChildren() { |
|
241 | - $nchi = count($this->getChildren()); |
|
242 | - foreach ($this->getFacts('NCHI') as $fact) { |
|
243 | - $nchi = max($nchi, (int) $fact->getValue()); |
|
244 | - } |
|
245 | - |
|
246 | - return $nchi; |
|
247 | - } |
|
248 | - |
|
249 | - /** |
|
250 | - * get the marriage event |
|
251 | - * |
|
252 | - * @return Fact |
|
253 | - */ |
|
254 | - public function getMarriage() { |
|
255 | - return $this->getFirstFact('MARR'); |
|
256 | - } |
|
257 | - |
|
258 | - /** |
|
259 | - * Get marriage date |
|
260 | - * |
|
261 | - * @return Date |
|
262 | - */ |
|
263 | - public function getMarriageDate() { |
|
264 | - $marriage = $this->getMarriage(); |
|
265 | - if ($marriage) { |
|
266 | - return $marriage->getDate(); |
|
267 | - } else { |
|
268 | - return new Date(''); |
|
269 | - } |
|
270 | - } |
|
271 | - |
|
272 | - /** |
|
273 | - * Get the marriage year - displayed on lists of families |
|
274 | - * |
|
275 | - * @return int |
|
276 | - */ |
|
277 | - public function getMarriageYear() { |
|
278 | - return $this->getMarriageDate()->minimumDate()->y; |
|
279 | - } |
|
280 | - |
|
281 | - /** |
|
282 | - * Get the type for this marriage |
|
283 | - * |
|
284 | - * @return string|null |
|
285 | - */ |
|
286 | - public function getMarriageType() { |
|
287 | - $marriage = $this->getMarriage(); |
|
288 | - if ($marriage) { |
|
289 | - return $marriage->getAttribute('TYPE'); |
|
290 | - } else { |
|
291 | - return null; |
|
292 | - } |
|
293 | - } |
|
294 | - |
|
295 | - /** |
|
296 | - * Get the marriage place |
|
297 | - * |
|
298 | - * @return Place |
|
299 | - */ |
|
300 | - public function getMarriagePlace() { |
|
301 | - $marriage = $this->getMarriage(); |
|
302 | - |
|
303 | - return $marriage->getPlace(); |
|
304 | - } |
|
305 | - |
|
306 | - /** |
|
307 | - * Get a list of all marriage dates - for the family lists. |
|
308 | - * |
|
309 | - * @return Date[] |
|
310 | - */ |
|
311 | - public function getAllMarriageDates() { |
|
312 | - foreach (explode('|', WT_EVENTS_MARR) as $event) { |
|
313 | - if ($array = $this->getAllEventDates($event)) { |
|
314 | - return $array; |
|
315 | - } |
|
316 | - } |
|
317 | - |
|
318 | - return array(); |
|
319 | - } |
|
320 | - |
|
321 | - /** |
|
322 | - * Get a list of all marriage places - for the family lists. |
|
323 | - * |
|
324 | - * @return string[] |
|
325 | - */ |
|
326 | - public function getAllMarriagePlaces() { |
|
327 | - foreach (explode('|', WT_EVENTS_MARR) as $event) { |
|
328 | - if ($array = $this->getAllEventPlaces($event)) { |
|
329 | - return $array; |
|
330 | - } |
|
331 | - } |
|
332 | - |
|
333 | - return array(); |
|
334 | - } |
|
335 | - |
|
336 | - /** |
|
337 | - * Derived classes should redefine this function, otherwise the object will have no name |
|
338 | - * |
|
339 | - * @return string[][] |
|
340 | - */ |
|
341 | - public function getAllNames() { |
|
342 | - if (is_null($this->_getAllNames)) { |
|
343 | - // Check the script used by each name, so we can match cyrillic with cyrillic, greek with greek, etc. |
|
344 | - $husb_names = array(); |
|
345 | - if ($this->husb) { |
|
346 | - $husb_names = array_filter($this->husb->getAllNames(), function(array $x) { return $x['type'] !== '_MARNM'; } ); |
|
347 | - } |
|
348 | - // If the individual only has married names, create a dummy birth name. |
|
349 | - if (empty($husb_names)) { |
|
350 | - $husb_names[] = array( |
|
351 | - 'type' => 'BIRT', |
|
352 | - 'sort' => '@N.N.', |
|
353 | - 'full' => I18N::translateContext('Unknown given name', '…') . ' ' . I18N::translateContext('Unknown surname', '…'), |
|
354 | - ); |
|
355 | - } |
|
356 | - foreach ($husb_names as $n => $husb_name) { |
|
357 | - $husb_names[$n]['script'] = I18N::textScript($husb_name['full']); |
|
358 | - } |
|
359 | - |
|
360 | - $wife_names = array(); |
|
361 | - if ($this->wife) { |
|
362 | - $wife_names = array_filter($this->wife->getAllNames(), function(array $x) { return $x['type'] !== '_MARNM'; } ); |
|
363 | - } |
|
364 | - // If the individual only has married names, create a dummy birth name. |
|
365 | - if (empty($wife_names)) { |
|
366 | - $wife_names[] = array( |
|
367 | - 'type' => 'BIRT', |
|
368 | - 'sort' => '@N.N.', |
|
369 | - 'full' => I18N::translateContext('Unknown given name', '…') . ' ' . I18N::translateContext('Unknown surname', '…'), |
|
370 | - ); |
|
371 | - } |
|
372 | - foreach ($wife_names as $n => $wife_name) { |
|
373 | - $wife_names[$n]['script'] = I18N::textScript($wife_name['full']); |
|
374 | - } |
|
375 | - |
|
376 | - // Add the matched names first |
|
377 | - foreach ($husb_names as $husb_name) { |
|
378 | - foreach ($wife_names as $wife_name) { |
|
379 | - if ($husb_name['script'] == $wife_name['script']) { |
|
380 | - $this->_getAllNames[] = array( |
|
381 | - 'type' => $husb_name['type'], |
|
382 | - 'sort' => $husb_name['sort'] . ' + ' . $wife_name['sort'], |
|
383 | - 'full' => $husb_name['full'] . ' + ' . $wife_name['full'], |
|
384 | - // No need for a fullNN entry - we do not currently store FAM names in the database |
|
385 | - ); |
|
386 | - } |
|
387 | - } |
|
388 | - } |
|
389 | - |
|
390 | - // Add the unmatched names second (there may be no matched names) |
|
391 | - foreach ($husb_names as $husb_name) { |
|
392 | - foreach ($wife_names as $wife_name) { |
|
393 | - if ($husb_name['script'] != $wife_name['script']) { |
|
394 | - $this->_getAllNames[] = array( |
|
395 | - 'type' => $husb_name['type'], |
|
396 | - 'sort' => $husb_name['sort'] . ' + ' . $wife_name['sort'], |
|
397 | - 'full' => $husb_name['full'] . ' + ' . $wife_name['full'], |
|
398 | - // No need for a fullNN entry - we do not currently store FAM names in the database |
|
399 | - ); |
|
400 | - } |
|
401 | - } |
|
402 | - } |
|
403 | - } |
|
404 | - |
|
405 | - return $this->_getAllNames; |
|
406 | - } |
|
407 | - |
|
408 | - /** |
|
409 | - * This function should be redefined in derived classes to show any major |
|
410 | - * identifying characteristics of this record. |
|
411 | - * |
|
412 | - * @return string |
|
413 | - */ |
|
414 | - public function formatListDetails() { |
|
415 | - return |
|
416 | - $this->formatFirstMajorFact(WT_EVENTS_MARR, 1) . |
|
417 | - $this->formatFirstMajorFact(WT_EVENTS_DIV, 1); |
|
418 | - } |
|
22 | + const RECORD_TYPE = 'FAM'; |
|
23 | + const URL_PREFIX = 'family.php?famid='; |
|
24 | + |
|
25 | + /** @var Individual|null The husband (or first spouse for same-sex couples) */ |
|
26 | + private $husb; |
|
27 | + |
|
28 | + /** @var Individual|null The wife (or second spouse for same-sex couples) */ |
|
29 | + private $wife; |
|
30 | + |
|
31 | + /** |
|
32 | + * Create a GedcomRecord object from raw GEDCOM data. |
|
33 | + * |
|
34 | + * @param string $xref |
|
35 | + * @param string $gedcom an empty string for new/pending records |
|
36 | + * @param string|null $pending null for a record with no pending edits, |
|
37 | + * empty string for records with pending deletions |
|
38 | + * @param Tree $tree |
|
39 | + */ |
|
40 | + public function __construct($xref, $gedcom, $pending, $tree) { |
|
41 | + parent::__construct($xref, $gedcom, $pending, $tree); |
|
42 | + |
|
43 | + // Fetch family members |
|
44 | + if (preg_match_all('/^1 (?:HUSB|WIFE|CHIL) @(.+)@/m', $gedcom . $pending, $match)) { |
|
45 | + Individual::load($tree, $match[1]); |
|
46 | + } |
|
47 | + |
|
48 | + if (preg_match('/^1 HUSB @(.+)@/m', $gedcom . $pending, $match)) { |
|
49 | + $this->husb = Individual::getInstance($match[1], $tree); |
|
50 | + } |
|
51 | + if (preg_match('/^1 WIFE @(.+)@/m', $gedcom . $pending, $match)) { |
|
52 | + $this->wife = Individual::getInstance($match[1], $tree); |
|
53 | + } |
|
54 | + |
|
55 | + // Make sure husb/wife are the right way round. |
|
56 | + if ($this->husb && $this->husb->getSex() === 'F' || $this->wife && $this->wife->getSex() === 'M') { |
|
57 | + list($this->husb, $this->wife) = array($this->wife, $this->husb); |
|
58 | + } |
|
59 | + } |
|
60 | + |
|
61 | + /** |
|
62 | + * Generate a private version of this record |
|
63 | + * |
|
64 | + * @param int $access_level |
|
65 | + * |
|
66 | + * @return string |
|
67 | + */ |
|
68 | + protected function createPrivateGedcomRecord($access_level) { |
|
69 | + $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); |
|
70 | + |
|
71 | + $rec = '0 @' . $this->xref . '@ FAM'; |
|
72 | + // Just show the 1 CHIL/HUSB/WIFE tag, not any subtags, which may contain private data |
|
73 | + preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @(' . WT_REGEX_XREF . ')@/', $this->gedcom, $matches, PREG_SET_ORDER); |
|
74 | + foreach ($matches as $match) { |
|
75 | + $rela = Individual::getInstance($match[1], $this->tree); |
|
76 | + if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canShow($access_level))) { |
|
77 | + $rec .= $match[0]; |
|
78 | + } |
|
79 | + } |
|
80 | + |
|
81 | + return $rec; |
|
82 | + } |
|
83 | + |
|
84 | + /** |
|
85 | + * Fetch data from the database |
|
86 | + * |
|
87 | + * @param string $xref |
|
88 | + * @param int $tree_id |
|
89 | + * |
|
90 | + * @return null|string |
|
91 | + */ |
|
92 | + protected static function fetchGedcomRecord($xref, $tree_id) { |
|
93 | + return Database::prepare( |
|
94 | + "SELECT f_gedcom FROM `##families` WHERE f_id = :xref AND f_file = :tree_id" |
|
95 | + )->execute(array( |
|
96 | + 'xref' => $xref, |
|
97 | + 'tree_id' => $tree_id, |
|
98 | + ))->fetchOne(); |
|
99 | + } |
|
100 | + |
|
101 | + /** |
|
102 | + * Get the male (or first female) partner of the family |
|
103 | + * |
|
104 | + * @param $access_level int|null |
|
105 | + * |
|
106 | + * @return Individual|null |
|
107 | + */ |
|
108 | + public function getHusband($access_level = null) { |
|
109 | + $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); |
|
110 | + |
|
111 | + if ($this->husb && ($SHOW_PRIVATE_RELATIONSHIPS || $this->husb->canShowName($access_level))) { |
|
112 | + return $this->husb; |
|
113 | + } else { |
|
114 | + return null; |
|
115 | + } |
|
116 | + } |
|
117 | + |
|
118 | + /** |
|
119 | + * Get the female (or second male) partner of the family |
|
120 | + * |
|
121 | + * @param $access_level int|null |
|
122 | + * |
|
123 | + * @return Individual|null |
|
124 | + */ |
|
125 | + public function getWife($access_level = null) { |
|
126 | + $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); |
|
127 | + |
|
128 | + if ($this->wife && ($SHOW_PRIVATE_RELATIONSHIPS || $this->wife->canShowName($access_level))) { |
|
129 | + return $this->wife; |
|
130 | + } else { |
|
131 | + return null; |
|
132 | + } |
|
133 | + } |
|
134 | + |
|
135 | + /** |
|
136 | + * Each object type may have its own special rules, and re-implement this function. |
|
137 | + * |
|
138 | + * @param int $access_level |
|
139 | + * |
|
140 | + * @return bool |
|
141 | + */ |
|
142 | + protected function canShowByType($access_level) { |
|
143 | + // Hide a family if any member is private |
|
144 | + preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @(' . WT_REGEX_XREF . ')@/', $this->gedcom, $matches); |
|
145 | + foreach ($matches[1] as $match) { |
|
146 | + $person = Individual::getInstance($match, $this->tree); |
|
147 | + if ($person && !$person->canShow($access_level)) { |
|
148 | + return false; |
|
149 | + } |
|
150 | + } |
|
151 | + |
|
152 | + return true; |
|
153 | + } |
|
154 | + |
|
155 | + /** |
|
156 | + * Can the name of this record be shown? |
|
157 | + * |
|
158 | + * @param int|null $access_level |
|
159 | + * |
|
160 | + * @return bool |
|
161 | + */ |
|
162 | + public function canShowName($access_level = null) { |
|
163 | + // We can always see the name (Husband-name + Wife-name), however, |
|
164 | + // the name will often be "private + private" |
|
165 | + return true; |
|
166 | + } |
|
167 | + |
|
168 | + /** |
|
169 | + * Find the spouse of a person. |
|
170 | + * |
|
171 | + * @param Individual $person |
|
172 | + * @param int|null $access_level |
|
173 | + * |
|
174 | + * @return Individual|null |
|
175 | + */ |
|
176 | + public function getSpouse(Individual $person, $access_level = null) { |
|
177 | + if ($person === $this->wife) { |
|
178 | + return $this->getHusband($access_level); |
|
179 | + } else { |
|
180 | + return $this->getWife($access_level); |
|
181 | + } |
|
182 | + } |
|
183 | + |
|
184 | + /** |
|
185 | + * Get the (zero, one or two) spouses from this family. |
|
186 | + * |
|
187 | + * @param int|null $access_level |
|
188 | + * |
|
189 | + * @return Individual[] |
|
190 | + */ |
|
191 | + public function getSpouses($access_level = null) { |
|
192 | + return array_filter(array( |
|
193 | + $this->getHusband($access_level), |
|
194 | + $this->getWife($access_level), |
|
195 | + )); |
|
196 | + } |
|
197 | + |
|
198 | + /** |
|
199 | + * Get a list of this family’s children. |
|
200 | + * |
|
201 | + * @param int|null $access_level |
|
202 | + * |
|
203 | + * @return Individual[] |
|
204 | + */ |
|
205 | + public function getChildren($access_level = null) { |
|
206 | + if ($access_level === null) { |
|
207 | + $access_level = Auth::accessLevel($this->tree); |
|
208 | + } |
|
209 | + |
|
210 | + $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); |
|
211 | + |
|
212 | + $children = array(); |
|
213 | + foreach ($this->getFacts('CHIL', false, $access_level, $SHOW_PRIVATE_RELATIONSHIPS) as $fact) { |
|
214 | + $child = $fact->getTarget(); |
|
215 | + if ($child && ($SHOW_PRIVATE_RELATIONSHIPS || $child->canShowName($access_level))) { |
|
216 | + $children[] = $child; |
|
217 | + } |
|
218 | + } |
|
219 | + |
|
220 | + return $children; |
|
221 | + } |
|
222 | + |
|
223 | + /** |
|
224 | + * Static helper function to sort an array of families by marriage date |
|
225 | + * |
|
226 | + * @param Family $x |
|
227 | + * @param Family $y |
|
228 | + * |
|
229 | + * @return int |
|
230 | + */ |
|
231 | + public static function compareMarrDate(Family $x, Family $y) { |
|
232 | + return Date::compare($x->getMarriageDate(), $y->getMarriageDate()); |
|
233 | + } |
|
234 | + |
|
235 | + /** |
|
236 | + * Number of children - for the individual list |
|
237 | + * |
|
238 | + * @return int |
|
239 | + */ |
|
240 | + public function getNumberOfChildren() { |
|
241 | + $nchi = count($this->getChildren()); |
|
242 | + foreach ($this->getFacts('NCHI') as $fact) { |
|
243 | + $nchi = max($nchi, (int) $fact->getValue()); |
|
244 | + } |
|
245 | + |
|
246 | + return $nchi; |
|
247 | + } |
|
248 | + |
|
249 | + /** |
|
250 | + * get the marriage event |
|
251 | + * |
|
252 | + * @return Fact |
|
253 | + */ |
|
254 | + public function getMarriage() { |
|
255 | + return $this->getFirstFact('MARR'); |
|
256 | + } |
|
257 | + |
|
258 | + /** |
|
259 | + * Get marriage date |
|
260 | + * |
|
261 | + * @return Date |
|
262 | + */ |
|
263 | + public function getMarriageDate() { |
|
264 | + $marriage = $this->getMarriage(); |
|
265 | + if ($marriage) { |
|
266 | + return $marriage->getDate(); |
|
267 | + } else { |
|
268 | + return new Date(''); |
|
269 | + } |
|
270 | + } |
|
271 | + |
|
272 | + /** |
|
273 | + * Get the marriage year - displayed on lists of families |
|
274 | + * |
|
275 | + * @return int |
|
276 | + */ |
|
277 | + public function getMarriageYear() { |
|
278 | + return $this->getMarriageDate()->minimumDate()->y; |
|
279 | + } |
|
280 | + |
|
281 | + /** |
|
282 | + * Get the type for this marriage |
|
283 | + * |
|
284 | + * @return string|null |
|
285 | + */ |
|
286 | + public function getMarriageType() { |
|
287 | + $marriage = $this->getMarriage(); |
|
288 | + if ($marriage) { |
|
289 | + return $marriage->getAttribute('TYPE'); |
|
290 | + } else { |
|
291 | + return null; |
|
292 | + } |
|
293 | + } |
|
294 | + |
|
295 | + /** |
|
296 | + * Get the marriage place |
|
297 | + * |
|
298 | + * @return Place |
|
299 | + */ |
|
300 | + public function getMarriagePlace() { |
|
301 | + $marriage = $this->getMarriage(); |
|
302 | + |
|
303 | + return $marriage->getPlace(); |
|
304 | + } |
|
305 | + |
|
306 | + /** |
|
307 | + * Get a list of all marriage dates - for the family lists. |
|
308 | + * |
|
309 | + * @return Date[] |
|
310 | + */ |
|
311 | + public function getAllMarriageDates() { |
|
312 | + foreach (explode('|', WT_EVENTS_MARR) as $event) { |
|
313 | + if ($array = $this->getAllEventDates($event)) { |
|
314 | + return $array; |
|
315 | + } |
|
316 | + } |
|
317 | + |
|
318 | + return array(); |
|
319 | + } |
|
320 | + |
|
321 | + /** |
|
322 | + * Get a list of all marriage places - for the family lists. |
|
323 | + * |
|
324 | + * @return string[] |
|
325 | + */ |
|
326 | + public function getAllMarriagePlaces() { |
|
327 | + foreach (explode('|', WT_EVENTS_MARR) as $event) { |
|
328 | + if ($array = $this->getAllEventPlaces($event)) { |
|
329 | + return $array; |
|
330 | + } |
|
331 | + } |
|
332 | + |
|
333 | + return array(); |
|
334 | + } |
|
335 | + |
|
336 | + /** |
|
337 | + * Derived classes should redefine this function, otherwise the object will have no name |
|
338 | + * |
|
339 | + * @return string[][] |
|
340 | + */ |
|
341 | + public function getAllNames() { |
|
342 | + if (is_null($this->_getAllNames)) { |
|
343 | + // Check the script used by each name, so we can match cyrillic with cyrillic, greek with greek, etc. |
|
344 | + $husb_names = array(); |
|
345 | + if ($this->husb) { |
|
346 | + $husb_names = array_filter($this->husb->getAllNames(), function(array $x) { return $x['type'] !== '_MARNM'; } ); |
|
347 | + } |
|
348 | + // If the individual only has married names, create a dummy birth name. |
|
349 | + if (empty($husb_names)) { |
|
350 | + $husb_names[] = array( |
|
351 | + 'type' => 'BIRT', |
|
352 | + 'sort' => '@N.N.', |
|
353 | + 'full' => I18N::translateContext('Unknown given name', '…') . ' ' . I18N::translateContext('Unknown surname', '…'), |
|
354 | + ); |
|
355 | + } |
|
356 | + foreach ($husb_names as $n => $husb_name) { |
|
357 | + $husb_names[$n]['script'] = I18N::textScript($husb_name['full']); |
|
358 | + } |
|
359 | + |
|
360 | + $wife_names = array(); |
|
361 | + if ($this->wife) { |
|
362 | + $wife_names = array_filter($this->wife->getAllNames(), function(array $x) { return $x['type'] !== '_MARNM'; } ); |
|
363 | + } |
|
364 | + // If the individual only has married names, create a dummy birth name. |
|
365 | + if (empty($wife_names)) { |
|
366 | + $wife_names[] = array( |
|
367 | + 'type' => 'BIRT', |
|
368 | + 'sort' => '@N.N.', |
|
369 | + 'full' => I18N::translateContext('Unknown given name', '…') . ' ' . I18N::translateContext('Unknown surname', '…'), |
|
370 | + ); |
|
371 | + } |
|
372 | + foreach ($wife_names as $n => $wife_name) { |
|
373 | + $wife_names[$n]['script'] = I18N::textScript($wife_name['full']); |
|
374 | + } |
|
375 | + |
|
376 | + // Add the matched names first |
|
377 | + foreach ($husb_names as $husb_name) { |
|
378 | + foreach ($wife_names as $wife_name) { |
|
379 | + if ($husb_name['script'] == $wife_name['script']) { |
|
380 | + $this->_getAllNames[] = array( |
|
381 | + 'type' => $husb_name['type'], |
|
382 | + 'sort' => $husb_name['sort'] . ' + ' . $wife_name['sort'], |
|
383 | + 'full' => $husb_name['full'] . ' + ' . $wife_name['full'], |
|
384 | + // No need for a fullNN entry - we do not currently store FAM names in the database |
|
385 | + ); |
|
386 | + } |
|
387 | + } |
|
388 | + } |
|
389 | + |
|
390 | + // Add the unmatched names second (there may be no matched names) |
|
391 | + foreach ($husb_names as $husb_name) { |
|
392 | + foreach ($wife_names as $wife_name) { |
|
393 | + if ($husb_name['script'] != $wife_name['script']) { |
|
394 | + $this->_getAllNames[] = array( |
|
395 | + 'type' => $husb_name['type'], |
|
396 | + 'sort' => $husb_name['sort'] . ' + ' . $wife_name['sort'], |
|
397 | + 'full' => $husb_name['full'] . ' + ' . $wife_name['full'], |
|
398 | + // No need for a fullNN entry - we do not currently store FAM names in the database |
|
399 | + ); |
|
400 | + } |
|
401 | + } |
|
402 | + } |
|
403 | + } |
|
404 | + |
|
405 | + return $this->_getAllNames; |
|
406 | + } |
|
407 | + |
|
408 | + /** |
|
409 | + * This function should be redefined in derived classes to show any major |
|
410 | + * identifying characteristics of this record. |
|
411 | + * |
|
412 | + * @return string |
|
413 | + */ |
|
414 | + public function formatListDetails() { |
|
415 | + return |
|
416 | + $this->formatFirstMajorFact(WT_EVENTS_MARR, 1) . |
|
417 | + $this->formatFirstMajorFact(WT_EVENTS_DIV, 1); |
|
418 | + } |
|
419 | 419 | } |
@@ -21,33 +21,33 @@ |
||
21 | 21 | * Was the individual born in "foreign parts". |
22 | 22 | */ |
23 | 23 | class CensusColumnBornForeignParts extends AbstractCensusColumn implements CensusColumnInterface { |
24 | - /** |
|
25 | - * Generate the likely value of this census column, based on available information. |
|
26 | - * |
|
27 | - * @param Individual $individual |
|
28 | - * @param Individual|null $head |
|
29 | - * |
|
30 | - * @return string |
|
31 | - */ |
|
32 | - public function generate(Individual $individual, Individual $head = null) { |
|
33 | - $birth_place = explode(', ', $individual->getBirthPlace()); |
|
34 | - $birth_place = end($birth_place); |
|
35 | - $census_place = $this->place(); |
|
24 | + /** |
|
25 | + * Generate the likely value of this census column, based on available information. |
|
26 | + * |
|
27 | + * @param Individual $individual |
|
28 | + * @param Individual|null $head |
|
29 | + * |
|
30 | + * @return string |
|
31 | + */ |
|
32 | + public function generate(Individual $individual, Individual $head = null) { |
|
33 | + $birth_place = explode(', ', $individual->getBirthPlace()); |
|
34 | + $birth_place = end($birth_place); |
|
35 | + $census_place = $this->place(); |
|
36 | 36 | |
37 | - if ($birth_place === 'Wales') { |
|
38 | - $birth_place = 'England'; |
|
39 | - } |
|
37 | + if ($birth_place === 'Wales') { |
|
38 | + $birth_place = 'England'; |
|
39 | + } |
|
40 | 40 | |
41 | - if ($census_place === 'Wales') { |
|
42 | - $census_place = 'England'; |
|
43 | - } |
|
41 | + if ($census_place === 'Wales') { |
|
42 | + $census_place = 'England'; |
|
43 | + } |
|
44 | 44 | |
45 | - if ($birth_place === $census_place || $birth_place === '') { |
|
46 | - return ''; |
|
47 | - } elseif ($birth_place === 'England' || $birth_place === 'Scotland' || $birth_place === 'Ireland') { |
|
48 | - return substr($birth_place, 0, 1); |
|
49 | - } else { |
|
50 | - return 'F'; |
|
51 | - } |
|
52 | - } |
|
45 | + if ($birth_place === $census_place || $birth_place === '') { |
|
46 | + return ''; |
|
47 | + } elseif ($birth_place === 'England' || $birth_place === 'Scotland' || $birth_place === 'Ireland') { |
|
48 | + return substr($birth_place, 0, 1); |
|
49 | + } else { |
|
50 | + return 'F'; |
|
51 | + } |
|
52 | + } |
|
53 | 53 | } |
@@ -19,27 +19,27 @@ |
||
19 | 19 | * Definitions for a census |
20 | 20 | */ |
21 | 21 | class CensusOfDenmark1801 extends CensusOfDenmark implements CensusInterface { |
22 | - /** |
|
23 | - * When did this census occur. |
|
24 | - * |
|
25 | - * @return string |
|
26 | - */ |
|
27 | - public function censusDate() { |
|
28 | - return '01 FEB 1801'; |
|
29 | - } |
|
22 | + /** |
|
23 | + * When did this census occur. |
|
24 | + * |
|
25 | + * @return string |
|
26 | + */ |
|
27 | + public function censusDate() { |
|
28 | + return '01 FEB 1801'; |
|
29 | + } |
|
30 | 30 | |
31 | - /** |
|
32 | - * The columns of the census. |
|
33 | - * |
|
34 | - * @return CensusColumnInterface[] |
|
35 | - */ |
|
36 | - public function columns() { |
|
37 | - return array( |
|
38 | - new CensusColumnFullName($this, 'Navn', ''), |
|
39 | - new CensusColumnRelationToHead($this, 'Stilling i familien', ''), |
|
40 | - new CensusColumnAge($this, 'Alder', ''), |
|
41 | - new CensusColumnConditionDanish($this, 'Civilstand', ''), |
|
42 | - new CensusColumnOccupation($this, 'Erhverv', ''), |
|
43 | - ); |
|
44 | - } |
|
31 | + /** |
|
32 | + * The columns of the census. |
|
33 | + * |
|
34 | + * @return CensusColumnInterface[] |
|
35 | + */ |
|
36 | + public function columns() { |
|
37 | + return array( |
|
38 | + new CensusColumnFullName($this, 'Navn', ''), |
|
39 | + new CensusColumnRelationToHead($this, 'Stilling i familien', ''), |
|
40 | + new CensusColumnAge($this, 'Alder', ''), |
|
41 | + new CensusColumnConditionDanish($this, 'Civilstand', ''), |
|
42 | + new CensusColumnOccupation($this, 'Erhverv', ''), |
|
43 | + ); |
|
44 | + } |
|
45 | 45 | } |
@@ -19,23 +19,23 @@ |
||
19 | 19 | * Marital status. |
20 | 20 | */ |
21 | 21 | class CensusColumnConditionFrenchHomme extends AbstractCensusColumnCondition { |
22 | - /* Text to display for married individuals */ |
|
23 | - protected $husband = '1'; |
|
24 | - protected $wife = ''; |
|
22 | + /* Text to display for married individuals */ |
|
23 | + protected $husband = '1'; |
|
24 | + protected $wife = ''; |
|
25 | 25 | |
26 | - /* Text to display for unmarried individuals */ |
|
27 | - protected $bachelor = ''; |
|
28 | - protected $spinster = ''; |
|
26 | + /* Text to display for unmarried individuals */ |
|
27 | + protected $bachelor = ''; |
|
28 | + protected $spinster = ''; |
|
29 | 29 | |
30 | - /* Text to display for children */ |
|
31 | - protected $boy = ''; |
|
32 | - protected $girl = ''; |
|
30 | + /* Text to display for children */ |
|
31 | + protected $boy = ''; |
|
32 | + protected $girl = ''; |
|
33 | 33 | |
34 | - /* Text to display for divorced individuals */ |
|
35 | - protected $divorce = '1'; |
|
36 | - protected $divorcee = ''; |
|
34 | + /* Text to display for divorced individuals */ |
|
35 | + protected $divorce = '1'; |
|
36 | + protected $divorcee = ''; |
|
37 | 37 | |
38 | - /* Text to display for widowed individuals (not yet implemented) */ |
|
39 | - protected $widower = ''; |
|
40 | - protected $widow = ''; |
|
38 | + /* Text to display for widowed individuals (not yet implemented) */ |
|
39 | + protected $widower = ''; |
|
40 | + protected $widow = ''; |
|
41 | 41 | } |
@@ -21,15 +21,15 @@ |
||
21 | 21 | * The individual's father's birth place. |
22 | 22 | */ |
23 | 23 | class CensusColumnFatherBirthPlaceSimple extends CensusColumnFatherBirthPlace implements CensusColumnInterface { |
24 | - /** |
|
25 | - * Generate the likely value of this census column, based on available information. |
|
26 | - * |
|
27 | - * @param Individual $individual |
|
28 | - * @param Individual|null $head |
|
29 | - * |
|
30 | - * @return string |
|
31 | - */ |
|
32 | - public function generate(Individual $individual, Individual $head = null) { |
|
33 | - return $this->lastPartOfPlace(parent::generate($individual, $head)); |
|
34 | - } |
|
24 | + /** |
|
25 | + * Generate the likely value of this census column, based on available information. |
|
26 | + * |
|
27 | + * @param Individual $individual |
|
28 | + * @param Individual|null $head |
|
29 | + * |
|
30 | + * @return string |
|
31 | + */ |
|
32 | + public function generate(Individual $individual, Individual $head = null) { |
|
33 | + return $this->lastPartOfPlace(parent::generate($individual, $head)); |
|
34 | + } |
|
35 | 35 | } |
@@ -19,31 +19,31 @@ |
||
19 | 19 | * Definitions for a census |
20 | 20 | */ |
21 | 21 | class CensusOfEngland extends Census implements CensusPlaceInterface { |
22 | - /** |
|
23 | - * All available censuses for this census place. |
|
24 | - * |
|
25 | - * @return CensusInterface[] |
|
26 | - */ |
|
27 | - public function allCensusDates() { |
|
28 | - return array( |
|
29 | - new CensusOfEngland1841(), |
|
30 | - new CensusOfEngland1851(), |
|
31 | - new CensusOfEngland1861(), |
|
32 | - new CensusOfEngland1871(), |
|
33 | - new CensusOfEngland1881(), |
|
34 | - new CensusOfEngland1891(), |
|
35 | - new CensusOfEngland1901(), |
|
36 | - new CensusOfEngland1911(), |
|
37 | - new RegisterOfEngland1939(), |
|
38 | - ); |
|
39 | - } |
|
22 | + /** |
|
23 | + * All available censuses for this census place. |
|
24 | + * |
|
25 | + * @return CensusInterface[] |
|
26 | + */ |
|
27 | + public function allCensusDates() { |
|
28 | + return array( |
|
29 | + new CensusOfEngland1841(), |
|
30 | + new CensusOfEngland1851(), |
|
31 | + new CensusOfEngland1861(), |
|
32 | + new CensusOfEngland1871(), |
|
33 | + new CensusOfEngland1881(), |
|
34 | + new CensusOfEngland1891(), |
|
35 | + new CensusOfEngland1901(), |
|
36 | + new CensusOfEngland1911(), |
|
37 | + new RegisterOfEngland1939(), |
|
38 | + ); |
|
39 | + } |
|
40 | 40 | |
41 | - /** |
|
42 | - * Where did this census occur, in GEDCOM format. |
|
43 | - * |
|
44 | - * @return string |
|
45 | - */ |
|
46 | - public function censusPlace() { |
|
47 | - return 'England'; |
|
48 | - } |
|
41 | + /** |
|
42 | + * Where did this census occur, in GEDCOM format. |
|
43 | + * |
|
44 | + * @return string |
|
45 | + */ |
|
46 | + public function censusPlace() { |
|
47 | + return 'England'; |
|
48 | + } |
|
49 | 49 | } |
@@ -19,29 +19,29 @@ |
||
19 | 19 | * Definitions for a census |
20 | 20 | */ |
21 | 21 | class CensusOfDenmark1845 extends CensusOfDenmark implements CensusInterface { |
22 | - /** |
|
23 | - * When did this census occur. |
|
24 | - * |
|
25 | - * @return string |
|
26 | - */ |
|
27 | - public function censusDate() { |
|
28 | - return '01 FEB 1845'; |
|
29 | - } |
|
22 | + /** |
|
23 | + * When did this census occur. |
|
24 | + * |
|
25 | + * @return string |
|
26 | + */ |
|
27 | + public function censusDate() { |
|
28 | + return '01 FEB 1845'; |
|
29 | + } |
|
30 | 30 | |
31 | - /** |
|
32 | - * The columns of the census. |
|
33 | - * |
|
34 | - * @return CensusColumnInterface[] |
|
35 | - */ |
|
36 | - public function columns() { |
|
37 | - return array( |
|
38 | - new CensusColumnFullName($this, 'Navn', ''), |
|
39 | - new CensusColumnAge($this, 'Alder', ''), |
|
40 | - new CensusColumnConditionDanish($this, 'Civilstand', ''), |
|
41 | - new CensusColumnOccupation($this, 'Erhverv', ''), |
|
42 | - new CensusColumnRelationToHead($this, 'Stilling i familien', ''), |
|
43 | - new CensusColumnNull($this, '', ''), |
|
44 | - new CensusColumnNull($this, '', ''), |
|
45 | - ); |
|
46 | - } |
|
31 | + /** |
|
32 | + * The columns of the census. |
|
33 | + * |
|
34 | + * @return CensusColumnInterface[] |
|
35 | + */ |
|
36 | + public function columns() { |
|
37 | + return array( |
|
38 | + new CensusColumnFullName($this, 'Navn', ''), |
|
39 | + new CensusColumnAge($this, 'Alder', ''), |
|
40 | + new CensusColumnConditionDanish($this, 'Civilstand', ''), |
|
41 | + new CensusColumnOccupation($this, 'Erhverv', ''), |
|
42 | + new CensusColumnRelationToHead($this, 'Stilling i familien', ''), |
|
43 | + new CensusColumnNull($this, '', ''), |
|
44 | + new CensusColumnNull($this, '', ''), |
|
45 | + ); |
|
46 | + } |
|
47 | 47 | } |