Indefero

Indefero Commit Details


Date:2011-12-10 18:38:56 (13 years 11 days ago)
Author:Thomas Keller
Branch:develop, release-1.3
Commit:95faf0468a4fb1b495553b46701990cd8404e468
Parents: 14be87272441d956fa4d08e7b34165d8f192ca38
Message:Add a relation between IDF_Project and IDF_Tag (again), this time its a many-to-many. We store project tags in IDF_Tag with a project id "0" (this has minimal to no impact on existing code) and therefor only need to ensure that the new relation table exists in the migration.

Then just the project summary configuration and the admin's project
create and project update forms and views needed to be adapted to
be able to render, create and update project tags.
Changes:

File differences

src/IDF/Form/Admin/ProjectCreate.php
134134
135135
136136
137
138
139
140
141
142
143
144
145
146
147
148
137149
138150
139151
......
290302
291303
292304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
293322
294323
295324
296325
297326
327
298328
299329
300330
......
302332
303333
304334
335
336
337
338
305339
306340
307341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
308357
309358
359
360
310361
311362
312363
'widget' => 'Pluf_Form_Widget_TextareaInput',
));
for ($i=1;$i<7;$i++) {
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('Labels'),
'initial' => '',
'widget_attrs' => array(
'maxlength' => 50,
'size' => 20,
),
));
}
$projects = array('--' => '--');
foreach (Pluf::factory('IDF_Project')->getList(array('order' => 'name ASC')) as $proj) {
$projects[$proj->name] = $proj->shortname;
if (!$this->isValid()) {
throw new Exception(__('Cannot save the model from an invalid form.'));
}
// Add a tag for each label
$tagids = array();
for ($i=1;$i<7;$i++) {
if (strlen($this->cleaned_data['label'.$i]) > 0) {
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
list($class, $name) = array(trim($class), trim($name));
} else {
$class = 'Other';
$name = trim($this->cleaned_data['label'.$i]);
}
$tag = IDF_Tag::addGlobal($name, $class);
$tagids[] = $tag->id;
}
}
$project = new IDF_Project();
$project->name = $this->cleaned_data['name'];
$project->shortname = $this->cleaned_data['shortname'];
$project->shortdesc = $this->cleaned_data['shortdesc'];
$tagids = array();
if ($this->cleaned_data['template'] != '--') {
// Find the template project
$sql = new Pluf_SQL('shortname=%s',
$tmpl = Pluf::factory('IDF_Project')->getOne(array('filter' => $sql->gen()));
$project->private = $tmpl->private;
$project->description = $tmpl->description;
foreach ($tmpl->get_tags_list() as $tag) {
$tagids[] = $tag->id;
}
} else {
$project->private = $this->cleaned_data['private_project'];
$project->description = __('Click on the Project Management tab to set the description of your project.');
// Add a tag for each label
for ($i=1;$i<7;$i++) {
if (strlen($this->cleaned_data['label'.$i]) > 0) {
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
list($class, $name) = array(trim($class), trim($name));
} else {
$class = 'Other';
$name = trim($this->cleaned_data['label'.$i]);
}
$tag = IDF_Tag::addGlobal($name, $class);
$tagids[] = $tag->id;
}
}
}
$project->create();
$project->batchAssoc('IDF_Tag', $tagids);
$conf = new IDF_Conf();
$conf->setProject($project);
$keys = array('scm', 'svn_remote_url', 'svn_username',
src/IDF/Form/Admin/ProjectUpdate.php
7070
7171
7272
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
7393
7494
7595
......
132152
133153
134154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
135173
136174
137175
176
138177
139178
140179
));
}
$tags = $this->project->get_tags_list();
for ($i=1;$i<7;$i++) {
$initial = '';
if (isset($tags[$i-1])) {
if ($tags[$i-1]->class != 'Other') {
$initial = (string) $tags[$i-1];
} else {
$initial = $tags[$i-1]->name;
}
}
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('Labels'),
'initial' => $initial,
'widget_attrs' => array(
'maxlength' => 50,
'size' => 20,
),
));
}
$this->fields['owners'] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('Project owners'),
if (!$this->isValid()) {
throw new Exception(__('Cannot save the model from an invalid form.'));
}
// Add a tag for each label
$tagids = array();
for ($i=1;$i<7;$i++) {
if (strlen($this->cleaned_data['label'.$i]) > 0) {
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
list($class, $name) = array(trim($class), trim($name));
} else {
$class = 'Other';
$name = trim($this->cleaned_data['label'.$i]);
}
$tag = IDF_Tag::addGlobal($name, $class);
$tagids[] = $tag->id;
}
}
$this->project->batchAssoc('IDF_Tag', $tagids);
IDF_Form_MembersConf::updateMemberships($this->project,
$this->cleaned_data);
$this->project->membershipsUpdated();
$this->project->name = $this->cleaned_data['name'];
$this->project->shortdesc = $this->cleaned_data['shortdesc'];
$this->project->update();
src/IDF/Form/ProjectConf.php
5858
5959
6060
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
6182
6283
6384
......
148169
149170
150171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
151188
152189
153190
154191
192
155193
156194
157195
'initial' => $conf->getVal('external_project_url'),
));
$tags = $this->project->get_tags_list();
for ($i=1;$i<7;$i++) {
$initial = '';
if (isset($tags[$i-1])) {
if ($tags[$i-1]->class != 'Other') {
$initial = (string) $tags[$i-1];
} else {
$initial = $tags[$i-1]->name;
}
}
$this->fields['label'.$i] = new Pluf_Form_Field_Varchar(
array('required' => false,
'label' => __('Labels'),
'initial' => $initial,
'widget_attrs' => array(
'maxlength' => 50,
'size' => 20,
),
));
}
// Logo part
$upload_path = Pluf::f('upload_path', false);
if (false === $upload_path) {
public function save($commit=true)
{
// Add a tag for each label
$tagids = array();
for ($i=1;$i<7;$i++) {
if (strlen($this->cleaned_data['label'.$i]) > 0) {
if (strpos($this->cleaned_data['label'.$i], ':') !== false) {
list($class, $name) = explode(':', $this->cleaned_data['label'.$i], 2);
list($class, $name) = array(trim($class), trim($name));
} else {
$class = 'Other';
$name = trim($this->cleaned_data['label'.$i]);
}
$tag = IDF_Tag::addGlobal($name, $class);
$tagids[] = $tag->id;
}
}
// Basic part
$this->project->name = $this->cleaned_data['name'];
$this->project->shortdesc = $this->cleaned_data['shortdesc'];
$this->project->description = $this->cleaned_data['description'];
$this->project->batchAssoc('IDF_Tag', $tagids);
$this->project->update();
$conf = $this->project->getConf();
src/IDF/Migrations/22ProjectTagRelationTable.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?php
/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
# ***** BEGIN LICENSE BLOCK *****
# This file is part of InDefero, an open source project management application.
# Copyright (C) 2008-2011 Céondo Ltd and contributors.
#
# InDefero is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# InDefero is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ***** END LICENSE BLOCK ***** */
function IDF_Migrations_22ProjectTagRelationTable_up($params=null)
{
$db = Pluf::db();
$table = $db->pfx.'idf_project_idf_tag_assoc';
if (!in_array($db->engine, array('MySQL', 'PostgreSQL'))) {
throw new Exception('unsupported engine '.$engine);
}
$intro = new Pluf_DB_Introspect($db);
if (in_array($table, $intro->listTables())) {
echo '21 skipping up migration - table already exists'."\n";
return;
}
$schema = Pluf::factory('Pluf_DB_Schema_'.$db->engine, $db);
$sql = $schema->getSqlCreate(new IDF_Project());
$db->execute($sql[$table]);
}
function IDF_Migrations_22ProjectTagRelationTable_down($params=null)
{
$db = Pluf::db();
$table = $db->pfx.'idf_project_idf_tag_assoc';
if (!in_array($db->engine, array('MySQL', 'PostgreSQL'))) {
throw new Exception('unsupported engine '.$engine);
}
$intro = new Pluf_DB_Introspect($db);
if (!in_array($table, $intro->listTables())) {
echo '22 skipping down migration - table does not exist'."\n";
return;
}
$schema = Pluf::factory('Pluf_DB_Schema_'.$db->engine, $db);
$sql = $schema->getSqlDelete(new IDF_Project());
$db->execute($sql[$table]);
}
src/IDF/Project.php
8686
8787
8888
89
90
91
92
93
94
95
8996
9097
9198
'verbose' => __('description'),
'help_text' => __('The description can be extended using the Markdown syntax.'),
),
'tags' =>
array(
'type' => 'Pluf_DB_Field_Manytomany',
'blank' => true,
'model' => 'IDF_Tag',
'verbose' => __('labels'),
),
'private' =>
array(
'type' => 'Pluf_DB_Field_Integer',
src/IDF/Tag.php
4242
4343
4444
45
45
4646
47
47
4848
4949
5050
5151
5252
5353
54
54
5555
5656
5757
......
5959
6060
6161
62
62
6363
6464
6565
6666
6767
68
68
6969
7070
7171
......
9595
9696
9797
98
98
9999
100100
101101
......
107107
108108
109109
110
110
111111
112112
113113
......
122122
123123
124124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
125151
126152
127153
array(
'type' => 'Pluf_DB_Field_Sequence',
//It is automatically added.
'blank' => true,
'blank' => true,
),
'project' =>
'project' =>
array(
'type' => 'Pluf_DB_Field_Foreignkey',
'model' => 'IDF_Project',
'blank' => false,
'verbose' => __('project'),
),
'class' =>
'class' =>
array(
'type' => 'Pluf_DB_Field_Varchar',
'blank' => false,
'verbose' => __('tag class'),
'help_text' => __('The class of the tag.'),
),
'name' =>
'name' =>
array(
'type' => 'Pluf_DB_Field_Varchar',
'blank' => false,
'verbose' => __('name'),
),
'lcname' =>
'lcname' =>
array(
'type' => 'Pluf_DB_Field_Varchar',
'blank' => false,
}
/**
* Add a tag if not already existing.
* Add a project-specific tag if not already existing.
*
* @param string Name of the tag.
* @param IDF_Project Project of the tag.
$class = trim($class);
$name = trim($name);
$gtag = new IDF_Tag();
$sql = new Pluf_SQL('class=%s AND lcname=%s AND project=%s',
$sql = new Pluf_SQL('class=%s AND lcname=%s AND project=%s',
array($class, mb_strtolower($name), $project->id));
$tags = $gtag->getList(array('filter' => $sql->gen()));
if ($tags->count() < 1) {
return $tags[0];
}
/**
* Add a global tag if not already existing
*
* @param string Name of the tag.
* @param string Class of the tag (IDF_TAG_DEFAULT_CLASS)
* @return IDF_Tag The tag.
*/
public static function addGlobal($name, $class=IDF_TAG_DEFAULT_CLASS)
{
$class = trim($class);
$name = trim($name);
$gtag = new IDF_Tag();
$sql = new Pluf_SQL('class=%s AND lcname=%s AND project=0',
array($class, mb_strtolower($name)));
$tags = $gtag->getList(array('filter' => $sql->gen()));
if ($tags->count() < 1) {
// create a new tag
$tag = new IDF_Tag();
$tag->name = $name;
$tag->class = $class;
$tag->create();
return $tag;
}
return $tags[0];
}
function __toString()
{
if ($this->class != IDF_TAG_DEFAULT_CLASS) {
src/IDF/Views/Admin.php
140140
141141
142142
143
143144
144
145
146
147
148
145
146
147
148
149
150
151
152
149153
150154
151155
......
173177
174178
175179
180
181
176182
177
178
179
180
181
183
184
185
186
187
188
189
190
182191
183192
184193
} else {
$form = new IDF_Form_Admin_ProjectUpdate(null, $params);
}
$arrays = IDF_Views_Project::autoCompleteArrays();
return Pluf_Shortcuts_RenderToResponse('idf/gadmin/projects/update.html',
array(
'page_title' => $title,
'project' => $project,
'form' => $form,
),
array_merge(
array(
'page_title' => $title,
'project' => $project,
'form' => $form,
),
$arrays
),
$request);
}
$form = new IDF_Form_Admin_ProjectCreate(null, $extra);
}
$base = Pluf::f('url_base').Pluf::f('idf_base').'/p/';
$arrays = IDF_Views_Project::autoCompleteArrays();
return Pluf_Shortcuts_RenderToResponse('idf/gadmin/projects/create.html',
array(
'page_title' => $title,
'form' => $form,
'base_url' => $base,
),
array_merge(
array(
'page_title' => $title,
'form' => $form,
'base_url' => $base,
),
$arrays
),
$request);
}
src/IDF/Views/Project.php
311311
312312
313313
314
314315
315
316
317
318
319
320
316
317
318
319
320
321
322
323
324
321325
322326
323327
......
616620
617621
618622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
619655
}
$logo = $prj->getConf()->getVal('logo');
$arrays = self::autoCompleteArrays();
return Pluf_Shortcuts_RenderToResponse('idf/admin/summary.html',
array(
'page_title' => $title,
'form' => $form,
'project' => $prj,
'logo' => $logo,
),
array_merge(
array(
'page_title' => $title,
'form' => $form,
'project' => $prj,
'logo' => $logo,
),
$arrays
),
$request);
}
),
$request);
}
/**
* Create the autocomplete arrays for the little AJAX stuff.
*/
public static function autoCompleteArrays()
{
$forge = IDF_Forge::instance();
$labels = $forge->getProjectLabels(IDF_Form_Admin_LabelConf::init_project_labels);
$auto = array('auto_labels' => '');
$auto_raw = array('auto_labels' => $labels);
foreach ($auto_raw as $key => $st) {
$st = preg_split("/\015\012|\015|\012/", $st, -1, PREG_SPLIT_NO_EMPTY);
foreach ($st as $s) {
$v = '';
$d = '';
$_s = explode('=', $s, 2);
if (count($_s) > 1) {
$v = trim($_s[0]);
$d = trim($_s[1]);
} else {
$v = trim($_s[0]);
}
$auto[$key] .= sprintf('{ name: "%s", to: "%s" }, ',
Pluf_esc($d),
Pluf_esc($v));
}
$auto[$key] = substr($auto[$key], 0, -2);
}
return $auto;
}
}
src/IDF/relations.php
2222
2323
2424
25
25
26
2627
2728
2829
# ***** END LICENSE BLOCK ***** */
$m = array();
$m['IDF_Tag'] = array('relate_to' => array('IDF_Project'));
$m['IDF_Tag'] = array('relate_to' => array('IDF_Project'),
'relate_to_many' => array('IDF_Project'));
$m['IDF_Issue'] = array('relate_to' => array('IDF_Project', 'Pluf_User', 'IDF_Tag'),
'relate_to_many' => array('IDF_Tag', 'Pluf_User'));
$m['IDF_IssueComment'] = array('relate_to' => array('IDF_Issue', 'Pluf_User'));
src/IDF/templates/idf/admin/summary.html
3737
3838
3939
40
41
42
43
44
45
46
47
48
49
50
4051
4152
4253
......
6677
6778
6879
80
6981
7082
7183
</td>
</tr>
<tr>
<th>{$form.f.label1.labelTag}:</th>
<td>
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
{if $form.f.label2.errors}{$form.f.label2.fieldErrors}{/if}{$form.f.label2|unsafe}
{if $form.f.label3.errors}{$form.f.label3.fieldErrors}{/if}{$form.f.label3|unsafe}<br />
{if $form.f.label4.errors}{$form.f.label4.fieldErrors}{/if}{$form.f.label4|unsafe}
{if $form.f.label5.errors}{$form.f.label5.fieldErrors}{/if}{$form.f.label5|unsafe}
{if $form.f.label6.errors}{$form.f.label6.fieldErrors}{/if}{$form.f.label6|unsafe}
</td>
</tr>
<tr>
<th><strong>{trans 'Current logo'}:</strong></th>
<td>
{if $logo}
</td>
</table>
</form>
{include 'idf/project/js-autocomplete.html'}{/block}
{/block}
{block context}
src/IDF/templates/idf/gadmin/projects/create.html
3737
3838
3939
40
40
4141
4242
4343
......
8181
8282
8383
84
85
86
87
88
89
90
91
92
93
94
8495
8596
8697
......
109120
110121
111122
112
123
113124
114125
115126
......
157168
158169
159170
160
171
161172
162173
163174
</td>
</tr>
<tr>
<th><strong>{$form.f.external_project_url.labelTag}:</strong></th>
<th>{$form.f.external_project_url.labelTag}:</th>
<td>{if $form.f.external_project_url.errors}{$form.f.external_project_url.fieldErrors}{/if}
{$form.f.external_project_url|unsafe}
</td>
</td>
</tr>
<tr class="no-template">
<th>{$form.f.label1.labelTag}:</th>
<td>
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
{if $form.f.label2.errors}{$form.f.label2.fieldErrors}{/if}{$form.f.label2|unsafe}<br />
{if $form.f.label3.errors}{$form.f.label3.fieldErrors}{/if}{$form.f.label3|unsafe}
{if $form.f.label4.errors}{$form.f.label4.fieldErrors}{/if}{$form.f.label4|unsafe}<br />
{if $form.f.label5.errors}{$form.f.label5.fieldErrors}{/if}{$form.f.label5|unsafe}
{if $form.f.label6.errors}{$form.f.label6.fieldErrors}{/if}{$form.f.label6|unsafe}
</td>
</tr>
<tr class="no-template">
<th><strong>{$form.f.owners.labelTag}:</strong></th>
<td>
{if $form.f.owners.errors}{$form.f.owners.fieldErrors}{/if}
</tr>
</table>
</form>
{include 'idf/project/js-autocomplete.html'}{/block}
{/block}
{block context}
}
});
// Hide if not svn
// Hide if not templated
if ($("#id_template option:selected").val() == "--") {
$(".no-template").show();
} else {
src/IDF/templates/idf/gadmin/projects/update.html
2626
2727
2828
29
29
3030
3131
3232
......
4141
4242
4343
44
45
46
47
48
49
50
51
52
53
54
4455
4556
4657
......
6677
6778
6879
80
6981
82
7083
7184
7285
</td>
</tr>
<tr>
<th><strong>{$form.f.external_project_url.labelTag}:</strong></th>
<th>{$form.f.external_project_url.labelTag}:</th>
<td>{if $form.f.external_project_url.errors}{$form.f.external_project_url.fieldErrors}{/if}
{$form.f.external_project_url|unsafe}
</td>
</tr>
{/if}
<tr>
<th>{$form.f.label1.labelTag}:</th>
<td>
{if $form.f.label1.errors}{$form.f.label1.fieldErrors}{/if}{$form.f.label1|unsafe}
{if $form.f.label2.errors}{$form.f.label2.fieldErrors}{/if}{$form.f.label2|unsafe}<br />
{if $form.f.label3.errors}{$form.f.label3.fieldErrors}{/if}{$form.f.label3|unsafe}
{if $form.f.label4.errors}{$form.f.label4.fieldErrors}{/if}{$form.f.label4|unsafe}<br />
{if $form.f.label5.errors}{$form.f.label5.fieldErrors}{/if}{$form.f.label5|unsafe}
{if $form.f.label6.errors}{$form.f.label6.fieldErrors}{/if}{$form.f.label6|unsafe}
</td>
</tr>
<tr>
<th><strong>{$form.f.owners.labelTag}:</strong></th>
<td>
{if $form.f.owners.errors}{$form.f.owners.fieldErrors}{/if}
</tr>
</table>
</form>
{include 'idf/project/js-autocomplete.html'}{/block}
{/block}
{block context}
<div class="issue-submit-info">
{blocktrans}
src/IDF/templates/idf/project/js-autocomplete.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script type="text/javascript" src="{media '/idf/js/jquery.bgiframe.min.js'}"></script>
<script type="text/javascript" src="{media '/idf/js/jquery.autocomplete.min.js'}"></script>
<script type="text/javascript" charset="utf-8">
// <!-- {literal}
$(document).ready(function(){
var auto_labels = [{/literal}{$auto_labels|safe}{literal}];
for (j=1;j<7;j++) {
$("#id_label"+j).autocomplete(auto_labels, {
minChars: 0,
width: 310,
matchContains: true,
max: 50,
highlightItem: false,
formatItem: function(row, i, max, term) {
return row.to.replace(new RegExp("(" + term + ")", "gi"), "<strong>$1</strong>") + " <span style='font-size: 80%;'>" + row.name + "</span>";
},
formatResult: function(row) {
return row.to;
}
});
}
});
{/literal} //-->
</script>

Archive Download the corresponding diff file

Page rendered in 0.12383s using 13 queries.