回答編集履歴

5

PHP修正

2017/08/03 07:14

投稿

yambejp
yambejp

スコア114863

test CHANGED
@@ -258,8 +258,16 @@
258
258
 
259
259
 
260
260
 
261
+ ※PHP修正
262
+
263
+
264
+
261
265
  ```PHP
262
266
 
267
+
268
+
269
+
270
+
263
271
  try{
264
272
 
265
273
  /* PDOの接続は自身の環境に合わせて下さい */
@@ -330,8 +338,6 @@
330
338
 
331
339
  if($row["link"]==1 and $row["url"]!==""){
332
340
 
333
- /* item-arrowクラスの付け方がおかしかったので修正 */
334
-
335
341
  $class=$row["child"]>0?" class=\"item-arrow\"":"";
336
342
 
337
343
  print "<a href=\"{$row["url"]}\"{$class}>{$row["name"]}</a>";
@@ -354,13 +360,13 @@
354
360
 
355
361
  print "</li>".PHP_EOL;
356
362
 
357
- for($i=$l2-$l3-1;$i>0;$i--){
363
+ for($i=0;$i<$l2-$l3-1;$i++){
358
-
364
+
359
- print str_repeat(" ",($i)*$indent);
365
+ print str_repeat(" ",($l2-$i-1)*$indent);
360
366
 
361
367
  print "</ul>".PHP_EOL;
362
368
 
363
- print str_repeat(" ",($i-1)*$indent);
369
+ print str_repeat(" ",($l2-$i-2)*$indent);
364
370
 
365
371
  print "</li>".PHP_EOL;
366
372
 
@@ -370,6 +376,14 @@
370
376
 
371
377
  print "</ul>".PHP_EOL;
372
378
 
379
+ if($l3>0){
380
+
381
+ print str_repeat(" ",($l3-1)*$indent);
382
+
383
+ print "</li>".PHP_EOL;
384
+
385
+ }
386
+
373
387
  }
374
388
 
375
389
  $l1=$l2;

4

typo

2017/08/03 07:14

投稿

yambejp
yambejp

スコア114863

test CHANGED
@@ -262,29 +262,27 @@
262
262
 
263
263
  try{
264
264
 
265
- $dsn = 'mysql:host=localhost; dbname=mydb;charset=utf8;';
266
-
267
- $user = 'root';
268
-
269
- $password = '*****';
265
+ /* PDOの接続は自身の環境に合わせて下さい */
270
266
 
271
267
  $pdo = new PDO($dsn, $user,$password);
272
268
 
273
- $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
274
-
275
- $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
276
-
277
- $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
278
-
279
269
  $sql ='SELECT name,level,url,link,(SELECT COUNT(*) FROM tbl AS t2 WHERE t2.l BETWEEN t1.l AND t1.r AND t2.level=t1.level+1) AS child FROM tbl AS t1 ORDER BY l';
280
270
 
271
+ /* 今回prepare処理は不要なのでqueryに変更しておきます
272
+
281
273
  $stmt = $pdo->prepare($sql);
282
274
 
283
275
  $stmt->execute([]);
284
276
 
277
+ */
278
+
279
+ $stmt = $pdo->query($sql);
280
+
285
281
  $rows=$stmt->fetchAll(PDO::FETCH_ASSOC);
286
282
 
283
+ /*当初gett_reeになっていたので修正します*/
284
+
287
- print gett_ree($rows);
285
+ print get_tree($rows);
288
286
 
289
287
  }catch(PDOException $e){
290
288
 

3

修正

2017/08/02 04:41

投稿

yambejp
yambejp

スコア114863

test CHANGED
@@ -332,7 +332,11 @@
332
332
 
333
333
  if($row["link"]==1 and $row["url"]!==""){
334
334
 
335
+ /* item-arrowクラスの付け方がおかしかったので修正 */
336
+
337
+ $class=$row["child"]>0?" class=\"item-arrow\"":"";
338
+
335
- print "<a href=\"{$row["url"]}\" class=\"item-arrow\">{$row["name"]}</a>";
339
+ print "<a href=\"{$row["url"]}\"{$class}>{$row["name"]}</a>";
336
340
 
337
341
  }else{
338
342
 

2

PHP

2017/08/02 02:59

投稿

yambejp
yambejp

スコア114863

test CHANGED
@@ -227,3 +227,165 @@
227
227
  ORDER BY l
228
228
 
229
229
  ```
230
+
231
+
232
+
233
+ # PHPへの書き出し
234
+
235
+ 以前作った分の流用なので若干インデントのバグがありますが
236
+
237
+ 出力するHTML文としてはさほど問題ないはずです
238
+
239
+ ※ポイント
240
+
241
+ - classの指定など最大限当初例示いただいたHTMLにあわせたつもりですが
242
+
243
+ おかしかったらうまく調整してください
244
+
245
+ - linkが1でURLが空でなければアンカーが貼られます
246
+
247
+ あえてリンクを表示したくない場合レコードのlinkを0にするなどテストしてみてください
248
+
249
+ - ただしhtmlspecialcharやurlencodeなどかけてないので注意
250
+
251
+ - 一応直下の要素数をカウントして表示しておきました
252
+
253
+ ちなみに、以下SQL文にすればカテゴリを含むすべての子要素数が表示されます
254
+
255
+
256
+
257
+ SELECT name,level,url,link,(SELECT COUNT(*)-1 FROM tbl AS t2 WHERE t2.l BETWEEN t1.l AND t1.r ) AS child FROM tbl AS t1 ORDER BY l
258
+
259
+
260
+
261
+ ```PHP
262
+
263
+ try{
264
+
265
+ $dsn = 'mysql:host=localhost; dbname=mydb;charset=utf8;';
266
+
267
+ $user = 'root';
268
+
269
+ $password = '*****';
270
+
271
+ $pdo = new PDO($dsn, $user,$password);
272
+
273
+ $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
274
+
275
+ $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
276
+
277
+ $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES,false);
278
+
279
+ $sql ='SELECT name,level,url,link,(SELECT COUNT(*) FROM tbl AS t2 WHERE t2.l BETWEEN t1.l AND t1.r AND t2.level=t1.level+1) AS child FROM tbl AS t1 ORDER BY l';
280
+
281
+ $stmt = $pdo->prepare($sql);
282
+
283
+ $stmt->execute([]);
284
+
285
+ $rows=$stmt->fetchAll(PDO::FETCH_ASSOC);
286
+
287
+ print gett_ree($rows);
288
+
289
+ }catch(PDOException $e){
290
+
291
+ die($e->getMessage());
292
+
293
+ }
294
+
295
+
296
+
297
+ function get_tree($rows){
298
+
299
+ $indent=3;
300
+
301
+ $l1=0;
302
+
303
+ ob_start();
304
+
305
+ foreach($rows as $key=>$row){
306
+
307
+ $l2=$row["level"];
308
+
309
+ $l3=($key<count($rows)-1)?$rows[$key+1]["level"]:0;
310
+
311
+ if($l1>=$l2){
312
+
313
+ print str_repeat(" ",($l2-1)*$indent);
314
+
315
+ }
316
+
317
+ if($l1<$l2){
318
+
319
+ print PHP_EOL;
320
+
321
+ print str_repeat(" ",($l2-1)*$indent);
322
+
323
+ $class=$row["level"]>1?" class=\"level{$row["level"]}\"":"";
324
+
325
+ print "<ul{$class}>".PHP_EOL;
326
+
327
+ print str_repeat(" ",($l2-1)*$indent);
328
+
329
+ }
330
+
331
+ print "<li>";
332
+
333
+ if($row["link"]==1 and $row["url"]!==""){
334
+
335
+ print "<a href=\"{$row["url"]}\" class=\"item-arrow\">{$row["name"]}</a>";
336
+
337
+ }else{
338
+
339
+ print $row["name"];
340
+
341
+ }
342
+
343
+ if($row["child"]>0) print "(".$row["child"].")";
344
+
345
+ if($l2==$l3){
346
+
347
+ print "</li>".PHP_EOL;;
348
+
349
+ }
350
+
351
+ if($l2>$l3){
352
+
353
+ print "</li>".PHP_EOL;
354
+
355
+ for($i=$l2-$l3-1;$i>0;$i--){
356
+
357
+ print str_repeat(" ",($i)*$indent);
358
+
359
+ print "</ul>".PHP_EOL;
360
+
361
+ print str_repeat(" ",($i-1)*$indent);
362
+
363
+ print "</li>".PHP_EOL;
364
+
365
+ }
366
+
367
+ print str_repeat(" ",($l3)*$indent);
368
+
369
+ print "</ul>".PHP_EOL;
370
+
371
+ }
372
+
373
+ $l1=$l2;
374
+
375
+ }
376
+
377
+ $str=ob_get_contents();
378
+
379
+ ob_end_clean();
380
+
381
+ return $str;
382
+
383
+ }
384
+
385
+
386
+
387
+ ```
388
+
389
+
390
+
391
+

1

別テーブル

2017/08/02 02:25

投稿

yambejp
yambejp

スコア114863

test CHANGED
@@ -9,3 +9,221 @@
9
9
 
10
10
 
11
11
  今回のテーブル構成はマストでしょうか?
12
+
13
+
14
+
15
+ # 隣接リストモデルから入れ子集合モデルへ
16
+
17
+
18
+
19
+ - 隣接リストモデル
20
+
21
+ ```SQL
22
+
23
+ create table tbl(
24
+
25
+ id int not null unique,
26
+
27
+ parent_id int null,
28
+
29
+ name varchar(30),
30
+
31
+ url varchar(100),
32
+
33
+ link tinyint,
34
+
35
+ level int not null default 0,
36
+
37
+ l int null,
38
+
39
+ r int null
40
+
41
+ );
42
+
43
+ ```
44
+
45
+ - 入れ子集合モデルへのコンバータ
46
+
47
+ ```SQL
48
+
49
+ DROP PROCEDURE IF EXISTS SET_LR;
50
+
51
+ DELIMITER //
52
+
53
+ CREATE PROCEDURE SET_LR()
54
+
55
+ BEGIN
56
+
57
+ DECLARE a INT DEFAULT 0;
58
+
59
+ DECLARE done INT DEFAULT 0;
60
+
61
+ DECLARE CUR CURSOR FOR
62
+
63
+ SELECT id FROM tbl WHERE level=0 ORDER BY parent_id ASC,id DESC;
64
+
65
+ DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;
66
+
67
+ UPDATE tbl SET level=0,l=0,r=0;
68
+
69
+ /* level,l,rを初期化*/
70
+
71
+
72
+
73
+ UPDATE tbl SET level=1,l=(SELECT @a:=@a+1 FROM (SELECT @a:=0) AS sub),r=@a:=@a+1
74
+
75
+ WHERE parent_id IS NULL
76
+
77
+ ORDER BY id;
78
+
79
+ /* 先頭データのlevelを1とし、l,rを1ずつ足していく*/
80
+
81
+
82
+
83
+ OPEN CUR;
84
+
85
+ REPEAT
86
+
87
+ FETCH CUR INTO a;
88
+
89
+ IF NOT done THEN
90
+
91
+ SET @id=a;
92
+
93
+ SET @sql='UPDATE tbl as a1,tbl as a2,tbl as a3 SET a1.l=a2.l+1,a1.r=a2.l+2,a1.level=a2.level+1,a2.r=a2.r+2,a3.r=a3.r+2 WHERE a1.parent_id=a2.id AND a2.l<a3.r AND a1.id=?';
94
+
95
+ /* 子のlに親の1+1、子のrに親のl+2,子のlevelに親のlevel+1親のrを2増やす、親のlより大きいrを2増やす */
96
+
97
+
98
+
99
+ PREPARE stmt from @sql;
100
+
101
+ EXECUTE stmt USING @id;
102
+
103
+ SET @sql='UPDATE tbl as a1,tbl as a2,tbl as a3 SET a3.l=a3.l+2 WHERE a1.parent_id=a2.id AND a2.l<a3.l and a3.id!=a1.id AND a1.id=?';
104
+
105
+ /* 親の1より大きいlの内、子以外のものを2増やす */
106
+
107
+
108
+
109
+ PREPARE stmt from @sql;
110
+
111
+ EXECUTE stmt USING @id;
112
+
113
+ END IF;
114
+
115
+ UNTIL done END REPEAT;
116
+
117
+ CLOSE CUR;
118
+
119
+ END
120
+
121
+ //
122
+
123
+ DELIMITER ;
124
+
125
+ ```
126
+
127
+ - データ投入
128
+
129
+ ```SQL
130
+
131
+ insert into tbl(id,parent_id,name,url,link) values
132
+
133
+ ( 1,null,'A','#',1),
134
+
135
+ ( 2,null,'B','#',1),
136
+
137
+ ( 3,1,'AA','#',1),
138
+
139
+ ( 4,1,'BB','#',1),
140
+
141
+ ( 5,2,'AA','#',1),
142
+
143
+ ( 6,2,'BB','#',1),
144
+
145
+ ( 7,3,'AAA','#',1),
146
+
147
+ ( 8,3,'BBB','#',1),
148
+
149
+ ( 9,3,'CCC','#',1),
150
+
151
+ (10,4,'BBB','#',1),
152
+
153
+ (11,4,'CCC','#',1),
154
+
155
+ (12,5,'AAA','#',1),
156
+
157
+ (13,6,'AAA','#',1),
158
+
159
+ (14,6,'BBB','#',1),
160
+
161
+ (15,7,'A-ct4','#',1),
162
+
163
+ (16,8,'A-ct4','#',1),
164
+
165
+ (17,8,'B-ct4','#',1),
166
+
167
+ (18,9,'A-ct4','#',1),
168
+
169
+ (19,10,'A-ct4','#',1),
170
+
171
+ (20,11,'B-ct4','#',1),
172
+
173
+ (21,12,'A-ct4','#',1),
174
+
175
+ (22,13,'B-ct4','#',1),
176
+
177
+ (23,14,'A-ct4','#',1),
178
+
179
+ (24,21,'A-ct5','#',1),
180
+
181
+ (25,22,'B-ct5','#',1),
182
+
183
+ (26,23,'C-ct5','#',1),
184
+
185
+ (27,24,'A-ct6','#',1),
186
+
187
+ (28,15,'name1001','www',1),
188
+
189
+ (29,16,'name1002','www',1),
190
+
191
+ (30,17,'name1003','www',1),
192
+
193
+ (31,18,'name1004','www',1),
194
+
195
+ (32,19,'name1005','www',1),
196
+
197
+ (33,19,'name1006','www',1),
198
+
199
+ (34,20,'name1007','www',1),
200
+
201
+ (35,27,'name1008','www',1),
202
+
203
+ (36,25,'name1009','www',1),
204
+
205
+ (37,26,'name1010','www',1);
206
+
207
+ ```
208
+
209
+ - コンバート
210
+
211
+ ```SQL
212
+
213
+ CALL SET_LR;
214
+
215
+ ```
216
+
217
+ # 階層状況の確認
218
+
219
+
220
+
221
+ ```SQL
222
+
223
+ SELECT CONCAT( REPEAT( "__", LEVEL -1 ) , name ) AS name
224
+
225
+ FROM area
226
+
227
+ ORDER BY l
228
+
229
+ ```