-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
2121 lines (1793 loc) · 79.6 KB
/
atom.xml
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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
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
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<id>http://xiewxin.github.io/</id>
<title>xiewixn blog</title>
<updated>2020-08-23T07:42:12.623Z</updated>
<generator>https://github.com/jpmonette/feed</generator>
<link rel="alternate" href="http://xiewxin.github.io/"/>
<link rel="self" href="http://xiewxin.github.io/atom.xml"/>
<subtitle>闲庭若步</subtitle>
<logo>http://xiewxin.github.io/images/avatar.png</logo>
<icon>http://xiewxin.github.io/favicon.ico</icon>
<rights>All rights reserved 2020, xiewixn blog</rights>
<entry>
<title type="html"><![CDATA[ES - 地理查询和分析特性]]></title>
<id>http://xiewxin.github.io/post/es-di-li-cha-xun-he-fen-xi-te-xing/</id>
<link href="http://xiewxin.github.io/post/es-di-li-cha-xun-he-fen-xi-te-xing/">
</link>
<updated>2020-08-15T13:03:50.000Z</updated>
<content type="html"><![CDATA[<p>相信大家对 <code>elasticsearch</code> (后面简称 <code>ES</code>) ,不管是前端还是后端,甚至是产品的小伙伴都不会陌生。它是时下流行的搜索引擎解决方案,他能干什么呢?</p>
<p> 1 提供快速的查询</p>
<p> 2 确保结果的相关性</p>
<p> 3 非常精确的匹配</p>
<p> 这一切的一切带来了了强大的搜索效率和精度以及良好的体验,再加上它开源,容易上手,适用性广,社区交流活跃文档齐全等等等等,所以迅速的流行了起来。</p>
<p> 我们知道 <code>ES</code> 其实适用于许多场景,像大家最常接触的文档存储查询,再比如日志存储和索引等,今天向大家介绍的是 <code>ES</code> 地理数据存储和分析特性,这块大家可能接触的相对没有这么多,本人也是因为行情的实价登录功能的契机才开始用到一些,用了之后觉得体验还是不错的,相信结合大家的才智可以用到更多有意思的地方。</p>
<p> 在开始之前,先给大家看一下,我们的实价登录长得是这样的,这个模块将社区的行情交易信息,地理信息于 <code>ES</code> 的地理查询和分析特性结合了起来,让用户直观的了解不同地区的房价情况。这是我们使用 <code>ES</code> 的地理特性完成的事情,让大家对他能做什么心里有个数,具体见 https://market.591.com.tw 。下面我们将从 [地理查询] 和 [地理数据聚合] 两个方面向大家介绍 <code>ES</code> 的地理特性。</p>
<figure data-type="image" tabindex="1"><img src="http://xiewxin.github.io//post-images/1597497366768.png" alt="591 实价登录" loading="lazy"></figure>
<h3 id="一-地理查询相关">一、地理查询相关</h3>
<p> 结合场景也许大家能够更直观的了解,假设大家的数据单位都有地理经纬度信息,在这个前提下我提出下面几个场景</p>
<h4 id="1-地理边界框查询">1. 地理边界框查询</h4>
<p> 我们想要筛选出地图中某个地理边界框的数据,我们只要使用 <code>ES</code> 的 [地理边界框查询] <code>geo_bounding_box</code> 就可以轻松实现,我们需要做的就是把边界框的左上坐标 <code>top_left</code> 和右下坐标 <code>bottom_right</code> 给到 <code>ES</code> 就可以过滤出该边界框的数据。</p>
<p>语句如下:</p>
<pre><code>GET /market-community/_search
{
"query": {
"bool" : {
"must" : {
"match_all" : {}
},
"filter" : {
"geo_bounding_box" : {
"search.location" : {
"top_left" : { // 左上坐标
"lat" : 25.03635457300217,
"lon" : 121.55181610152857
},
"bottom_right" : { // 右下坐标
"lat" : 25.03413425895166,
"lon" : 121.5612842657818
}
}
}
}
}
}
}
</code></pre>
<p>然后我们就能得到想要的数据啦~</p>
<figure data-type="image" tabindex="2"><img src="http://xiewxin.github.io//post-images/1597497322151.png" alt="地理边界框查询" loading="lazy"></figure>
<h4 id="2-地理多边形查询">2. 地理多边形查询</h4>
<p> 我们想要筛选出任意多边形地理边界内的数据,那我们就可以使用 <code>ES</code> 的 [地理多边形查询] <code>geo_polygon</code> ,把我们的绘制的多边形的坐标点按绘制顺序都给到 <code>ES</code> 就可以了,但这里需要注意坐标点一定要按绘制顺序给到 <code>ES</code>,因为 <code>ES</code> 是按顺序将点连接成图形的,否则结果可能就不是我们想要的了~,语句如下:</p>
<pre><code class="language-console">GET /market-community/_search
{
"query": {
"bool" : {
"must" : {
"match_all" : {}
},
"filter" : {
"geo_polygon" : {
"search.location" : { // 注意坐标点要按顺序,顺时针逆时针均可
"points" : [
[121.55823134507727, 25.03582564975867],
[121.55819379415107, 25.035840230943773],
[121.5589394482572, 25.035786766589958],
[121.55828498925757, 25.035840230943773],
....
[121.55826889600348, 25.035840230943773],
[121.5582528027494, 25.035835370548934],
[121.55824207391333, 25.035835370548934],
[121.55823134507727, 25.035835370548934]
]
}
}
}
}
}
}
</code></pre>
<p>结果当然显而易见:</p>
<figure data-type="image" tabindex="3"><img src="http://xiewxin.github.io//post-images/1597497401496.png" alt="地理多边形查询" loading="lazy"></figure>
<h4 id="3-地理距离查询">3. 地理距离查询</h4>
<p> 我们想要得到坐标点方圆一公里的社区呢?要做的也很简单,只需要使用 [地理距离查询] <code>geo_distance</code> ,比如获取坐标 lat:25.036593627652884, lng:121.5577666374389 方圆100m的的社区。</p>
<p>语句:</p>
<pre><code class="language-console">GET /market-community/_search
{
"query": {
"bool" : {
"must" : {
"match_all" : {}
},
"filter" : {
"geo_distance" : {
"distance" : "100m",
"search.location" : {
"lat" : 25.036593627652884,
"lon" : 121.5577666374389
}
}
}
}
}
}
</code></pre>
<p>结果示意:</p>
<figure data-type="image" tabindex="4"><img src="http://xiewxin.github.io//post-images/1597497442041.png" alt="地理距离查询" loading="lazy"></figure>
<p>是不是很简单呢~~只要使用 <code>ES</code> 我们就能轻松完成各种基于地理位置的查询,让我们的数据更具代表性和说服力。</p>
<h3 id="二-地理数据聚合">二、地理数据聚合</h3>
<p> 地理数据聚合 <code>ES</code> 提供了挺多有意思的聚合查询,[地理边界聚合] 可以为数据集合计算地理边界框,把你的数据框起来;[地理距离聚合] 可以获取坐标点不同范围距离数据区分出来,比如0~1km ,1km~2km。这里只做抛砖引玉的举两个例子。</p>
<h4 id="1-geohash网格聚合">1. GeoHash网格聚合</h4>
<p> 如果我们想将我们的数据分成若干个地理方块,比如 152.9mx 152.4m ,那我们就可以使用 [GeoHash网格聚合] <code>geohash_grid</code> 的特性,它能帮我们的数据计算出若干个 152.9mx 152.4m 范围的集合。 152.9mx 152.4m 在网格聚合精度级别表里是7(精度后面再说明)。语句如下:</p>
<pre><code class="language-console">POST /market-community/_search?size=0
{
"aggregations" : {
"large-grid" : {
"geohash_grid" : {
"field" : "search.location",
"precision" : 7
}
}
}
}
</code></pre>
<p>返回结果如下:</p>
<pre><code class="language-js">{
...
"aggregations": {
"large-grid": {
"buckets": [
{
"key":"wsqqqn4",
"doc_count":5,
},
{
"key":"wsqqqn1",
"doc_count":5,
},
{
"key":"wsqqqje",
"doc_count":5,
},
...
]
}
}
}
</code></pre>
<p> 这样我们就能比较方便的从数据中知道哪个 152.9mx 152.4m 范围方块里数据最多,延伸的话可以知道平均每个地理方块里有多少数据,或者只根据这个范围进行下一步操作。注意在默认的情况该聚合返回10000条数据,请在使用过程中留意该特性。</p>
<p> 目前该聚合支持12个精度,虽然它也能自定义,但实际还是根据这12个精度计算数据,所以与其自定义还是老实使用这12个精度吧...精度说明如下。</p>
<table>
<thead>
<tr>
<th><strong>GeoHash长度</strong></th>
<th><strong>区域宽度x高度</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>1个</td>
<td>5,009.4公里x 4,992.6公里</td>
</tr>
<tr>
<td>2</td>
<td>1,252.3公里x 624.1公里</td>
</tr>
<tr>
<td>3</td>
<td>156.5公里x 156公里</td>
</tr>
<tr>
<td>4</td>
<td>39.1公里x 19.5公里</td>
</tr>
<tr>
<td>5</td>
<td>4.9公里x 4.9公里</td>
</tr>
<tr>
<td>6</td>
<td>1.2公里x 609.4m</td>
</tr>
<tr>
<td>7</td>
<td>152.9mx 152.4m</td>
</tr>
<tr>
<td>8</td>
<td>38.2mx 19m</td>
</tr>
<tr>
<td>9</td>
<td>4.8mx 4.8m</td>
</tr>
<tr>
<td>10</td>
<td>1.2mx 59.5厘米</td>
</tr>
<tr>
<td>11</td>
<td>14.9厘米x 14.9厘米</td>
</tr>
<tr>
<td>12</td>
<td>3.7厘米x 1.9厘米</td>
</tr>
</tbody>
</table>
<h4 id="2-地心聚集">2. 地心聚集</h4>
<p> [地心聚集] <code>geo_centroid</code> 是计算数据集合的加权质心,解决诸如方圆五公里社区最多的点在哪里?大家最喜欢在哪里吃麻辣烫?等问题,他能将你收集的大数据在地理层面有用武之地。在 591实际登陆 功能中就有计算每个 152.9mx 152.4m 地理方块的质心用于地图展示,也算是 [GeoHash网格聚合] 的延伸,语句如下:</p>
<pre><code class="language-console">POST /market-community/_search
{
"aggs" : {
"_point_aggs" : {
"geohash_grid" : {
"field" : "search.location",
"precision" : 7,
"size" : 500,
},
"aggs" : {
"_centroid" : {
"geo_centroid" : {
"field" : "search.location"
}
}
}
}
}
}
</code></pre>
<p>返回结果如下</p>
<pre><code>{
...
"aggregations": {
"_point_aggs": {
"buckets": [
{
"key":"wsqqqn4",
"doc_count":5,
"_centroid":{
"location":{
"lat":25.038318903185427,
"lon":121.55637344531715
},
"count":5
}
},
{
"key":"wsqqqn1",
"doc_count":5,
"_centroid":{
"location":{
"lat":25.03880675509572,
"lon":121.55491943657398
},
"count":5
}
},
{
"key":"wsqqqje",
"doc_count":5,
"_centroid":{
"location":{
"lat":25.035851379856467,
"lon":121.5575652513653
},
"count":5
}
},
...
]
}
}
}
</code></pre>
<p>我们可以将其展示到地图上:</p>
<figure data-type="image" tabindex="5"><img src="http://xiewxin.github.io//post-images/1597497481109.png" alt="地心聚集" loading="lazy"></figure>
<p> <code>ES</code> 的地理特性还有许多,结合不同的场景也有许多的可能性,能让你辛辛苦苦收集大数据不再那么”干“,让数据更直观更有趣更有用,这就是本次分享的内容,希望能给大家带来一点启发和帮助。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[ORM]]></title>
<id>http://xiewxin.github.io/post/eloquent/</id>
<link href="http://xiewxin.github.io/post/eloquent/">
</link>
<updated>2020-08-02T17:25:15.000Z</updated>
<content type="html"><![CDATA[<h1 id="eloquent">Eloquent</h1>
<h3 id="集合">集合</h3>
<p>Eloquent 的 <code>all</code> 和 <code>get</code> 方法可以查询到多个结果,返回一个 <code>Illuminate\Database\Eloquent\Collection</code> 实例。<code>Collection</code> 类提供了 [大量的辅助函数] 来处理 Eloquent 结果:</p>
<pre><code>$flights = $flights->reject(function ($flight) {
return $flight->cancelled;
});
</code></pre>
<p>你可以像数组一样遍历集合:</p>
<pre><code>foreach ($flights as $flight) {
echo $flight->name;
}
</code></pre>
<h3 id="分块结果">分块结果</h3>
<p>如果你需要处理数以千计的 Eloquent 结果,使用 <code>chunk</code> 命令。 <code>chunk</code> 方法会检索 Eloquent 模型中的『分块』将他们提供给指定的 <code>Closure</code> 处理。在处理大型结果集时,使用 <code>chunk</code> 方法可以节省内存:</p>
<pre><code>Flight::chunk(200, function ($flights) {
foreach ($flights as $flight) {
//
}
});
</code></pre>
<p>传递到方法的第一个参数是希望每个『分块』接收的数据量。闭包作为第二个参数传递,它在每次从数据库中检索分块的时候调用。它将执行数据库查询把检索分块的结果传递给闭包方法。</p>
<h4 id="使用游标">使用游标</h4>
<p><code>cursor</code> 方法允许你使用游标遍历数据库,它只执行一次查询。处理大量的数据时, <code>cursor</code> 方法可以大大减少内存的使用量:</p>
<pre><code>foreach (Flight::where('foo', 'bar')->cursor() as $flight) {
//
}
</code></pre>
<p><code>cursor</code> 返回 <code>Illuminate\Support\LazyCollection</code> 实例。 [Lazy collections] 允许你使用 Laravel 集合中大多数集合方法,而且每次只会加载单个模型到内存中:</p>
<pre><code>$users = App\User::cursor()->filter(function ($user) {
return $user->id > 500;
});
foreach ($users as $user) {
echo $user->id;
}
</code></pre>
<h3 id="高级子查询">高级子查询</h3>
<h4 id="selects-子查询">Selects 子查询</h4>
<p>Eloquent 提供了高级子查询支持,你可以用单条查询语句从相关表中提取信息。举个例子,假设我们有一个目的地表 <code>destinations</code> 和一个到目的地的航班表 <code>flights</code>。<code>flights</code> 表包含一个 <code>arrival_at</code> 字段,表示航班何时到达目的地。</p>
<p>使用子查询功能提供的 <code>select</code> 和 <code>addSelect</code> 方法,我们可以用单条语句查询全部目的地 <code>destinations</code>,以及抵达各目的地最后一班飞机的名称:</p>
<pre><code>use App\Destination;
use App\Flight;
return Destination::addSelect(['last_flight' => Flight::select('name')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
])->get();
</code></pre>
<h4 id="根据子查询进行排序">根据子查询进行排序</h4>
<p>此外,查询构建器的 <code>orderBy</code> 函数也支持子查询。我们可以使用此功能根据最后一班航班到达目的地的时间对所有目的地排序。 同样,这可以只对数据库执行单个查询:</p>
<pre><code>return Destination::orderByDesc(
Flight::select('arrived_at')
->whereColumn('destination_id', 'destinations.id')
->orderBy('arrived_at', 'desc')
->limit(1)
)->get();
</code></pre>
<h2 id="检索单个模型-集合">检索单个模型 / 集合</h2>
<p>除了从指定的数据表检索所有记录外,你可以使用 <code>find</code>、 <code>first</code> 或 <code>firstWhere</code> 方法来检索单条记录。这些方法返回单个模型实例,而不是返回模型集合:</p>
<pre><code>// 通过主键查找一个模型...
$flight = App\Flight::find(1);
// 查找符合查询条件的首个模型...
$flight = App\Flight::where('active', 1)->first();
// 查找符合查询条件的首个模型的快速实现...
$flight = App\Flight::firstWhere('active', 1);
</code></pre>
<p>你也可以使用主键数组作为参数调用 <code>find</code> 方法,它将返回匹配记录的集合:</p>
<pre><code>$flights = App\Flight::find([1, 2, 3]);
</code></pre>
<p>有时你可能希望在查找首个结果但找不到值时执行其他动作。<code>firstOr</code> 方法将会在查找到结果时返回首个结果,如果没有结果,将会执行给定的回调。回调的返回值将会作为 <code>firstOr</code> 方法的返回值:</p>
<pre><code>$model = App\Flight::where('legs', '>', 100)->firstOr(function () {
// ...
});
</code></pre>
<h4 id="检查属性变化">检查属性变化</h4>
<p>Eloquent 提供了 <code>isDirty</code>, <code>isClean</code> 和 <code>wasChanged</code> 方法,以检查模型的内部状态并确定其属性从最初加载时如何变化。</p>
<p><code>isDirty</code> 方法确定自加载模型以来是否已更改任何属性。 您可以传递特定的属性名称来确定特定的属性是否变脏。<code>isClean</code> 方法与 <code>isDirty</code> 相反,它也接受可选的属性参数:</p>
<pre><code>$user = User::create([
'first_name' => 'Taylor',
'last_name' => 'Otwell',
'title' => 'Developer',
]);
$user->title = 'Painter';
$user->isDirty(); // true
$user->isDirty('title'); // true
$user->isDirty('first_name'); // false
$user->isClean(); // false
$user->isClean('title'); // false
$user->isClean('first_name'); // true
$user->save();
$user->isDirty(); // false
$user->isClean(); // true
</code></pre>
<p><code>wasChanged</code> 方法确定在当前请求周期内最后一次保存模型时是否更改了任何属性。 你还可以传递属性名称以查看特定属性是否已更改:</p>
<pre><code>$user = User::create([
'first_name' => 'Taylor',
'last_name' => 'Otwell',
'title' => 'Developer',
]);
$user->title = 'Painter';
$user->save();
$user->wasChanged(); // true
$user->wasChanged('title'); // true
$user->wasChanged('first_name'); // false
</code></pre>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[响应]]></title>
<id>http://xiewxin.github.io/post/xiang-ying/</id>
<link href="http://xiewxin.github.io/post/xiang-ying/">
</link>
<updated>2020-07-26T13:44:54.000Z</updated>
<content type="html"><![CDATA[<h2 id="创建响应">创建响应</h2>
<h4 id="字符串-数组">字符串 & 数组</h4>
<p>所有路由和控制器处理完业务逻辑之后都会返回一个发送到用户浏览器的响应,Laravel 提供了多种不同的方式来返回响应,最基本的响应就是从路由或控制器返回一个简单的字符串,框架会自动将这个字符串转化为一个完整的 HTTP 响应:</p>
<pre><code>Route::get('/', function () {
return 'Hello World';
});
</code></pre>
<p>除了从路由或控制器返回字符串之外,还可以返回数组。框架会自动将数组转化为一个 JSON 响应:</p>
<pre><code>Route::get('/', function () {
return [1, 2, 3];
});
</code></pre>
<h4 id="response-对象">Response 对象</h4>
<p>通常,我们并不只是从路由动作简单返回字符串和数组,大多数情况下,都会返回一个完整的 <code>Illuminate\Http\Response</code> 实例或 视图。</p>
<p>返回完整的 <code>Response</code> 实例允许你自定义响应的 HTTP 状态码和响应头信息。</p>
<p><code>Response</code> 实例 继承自 <code>Symfony\Component\HttpFoundation\Response</code> 类, 该类提供了各种构建 HTTP 响应的方法:</p>
<pre><code>Route::get('home', function () {
return response('Hello World', 200)
->header('Content-Type', 'text/plain');
});
</code></pre>
<h4 id="添加响应头">添加响应头</h4>
<p>大部分的响应方法都是可链式调用的,使得创建响应实例的过程更具可读性。例如,你可以在响应返回给用户前使用 <code>header</code> 方法为其添加一系列的头信息:</p>
<pre><code>return response($content)
->header('Content-Type', $type)
->header('X-Header-One', 'Header Value')
->header('X-Header-Two', 'Header Value');
</code></pre>
<p>或者,你可以使用 <code>withHeaders</code> 方法来指定要添加到响应的头信息数组:</p>
<h5 id="缓存控制中间件">缓存控制中间件</h5>
<p>Laravel 内置了一个 <code>cache.headers</code> 中间件,可以用来快速地为路由组设置 <code>Cache-Control</code> 头信息。如果在指令集中声明了 <code>etag</code>,Laravel 会自动将 ETag 标识符设置为响应内容的 MD5 哈希值:</p>
<pre><code>Route::middleware('cache.headers:public;max_age=2628000;etag')->group(function () {
Route::get('privacy', function () {
// ...
});
Route::get('terms', function () {
// ...
});
});
</code></pre>
<h4 id="添加-cookies-到响应">添加 Cookies 到响应</h4>
<p>你可以使用响应上的 <code>cookie</code> 方法轻松地将为响应增加 Cookies。例如,你可以像这样使用 <code>cookie</code> 方法生成一个 cookie 并轻松地将其附加到响应上:</p>
<pre><code>return response($content)
->header('Content-Type', $type)
->cookie('name', 'value', $minutes);
</code></pre>
<p><code>cookie</code> 方法还接受一些不太频繁使用的参数。通常,这些参数与原生 PHP 的 setcookie方法的参数有着相同的目的和含义:</p>
<pre><code>->cookie($name, $value, $minutes, $path, $domain, $secure, $httpOnly)
</code></pre>
<p>或者,你可以使用 <code>Cookie</code> facade 「队列」, <code>Cookie</code> 以附加到应用程序的传出响应。 <code>queue</code> 方法接受一个 <code>Cookie</code> 实例或创建 <code>Cookie</code> 实例所需的参数。 这些 cookie 在发送到浏览器之前会附加到传出响应中:</p>
<pre><code>Cookie::queue(Cookie::make('name', 'value', $minutes));
Cookie::queue('name', 'value', $minutes);
</code></pre>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[請求1]]></title>
<id>http://xiewxin.github.io/post/qing-qiu-1/</id>
<link href="http://xiewxin.github.io/post/qing-qiu-1/">
</link>
<updated>2020-07-18T08:51:19.000Z</updated>
<content type="html"><![CDATA[<p>要通过依赖注入获取当前 HTTP 请求实例,你应该在控制器上引入 <code>Illuminate\Http\Request</code> 类。传入的请求实例将会由 服务容器 自动注入:</p>
<pre><code><?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Store a new user.
*
* @param Request $request
* @return Response
*/
public function store(Request $request)
{
$name = $request->input('name');
//
}
}
</code></pre>
<h4 id="检索请求路径">检索请求路径</h4>
<p><code>path</code> 方法返回请求的路径信息。因此,如果接收到的请求目标是 <code>http://xiewxin.lv.com/home/request</code>,则 <code>path</code> 方法会返回 <code>home/request</code>:</p>
<pre><code>// 1. path 方法返回请求的路径信息。因此,如果接收到的请求
// 目标是 http://xiewxin.lv.com/home/request,
// 则 path 方法会返回 home/request
$res['path'] = $request->path();
</code></pre>
<p><code>is</code> 方法验证请求的路径是否与给定的模式匹配。使用此方法时,可以将 <code>*</code> 字符作为通配符:</p>
<pre><code>if ($request->is('admin/*')) {
//
}
</code></pre>
<h4 id="获取请求-url">获取请求 URL</h4>
<p>要获取完整的请求 URL,你可以使用 <code>url</code> 或 <code>fullUrl</code> 方法。 <code>url</code> 方法返回不带查询条件的 URL,而 <code>fullUrl</code> 方法的返回包含查询条件字符串。</p>
<pre><code>// 没有包含查询条件字符串
$url = $request->url();
// 包含查询条件字符串
$url = $request->fullUrl();
</code></pre>
<h4 id="获取请求方法">获取请求方法</h4>
<p><code>method</code> 方法将会返回请求的 HTTP 动词。 你也可以使用 <code>isMethod</code> 方法去验证 HTTP 动词与所给定的字符串是否匹配</p>
<pre><code>$method = $request->method();
if ($request->isMethod('post')) {
//
}
</code></pre>
<h3 id="psr-7-请求">PSR-7 请求</h3>
<p>PSR-7 标准指定了包括请求与响应在内的 HTTP 的消息接口。如果你想要获取 PSR-7 请求实例而不是 Laravel 请求, 那么你首先需要安装几个库。Laravel 使用 <em>Symfony HTTP Message Bridge</em> 组件将典型的 Laravel 请求和响应转换为 PSR-7 的兼容实现:</p>
<pre><code>composer require symfony/psr-http-message-bridge
composer require nyholm/psr7
</code></pre>
<p>安装这些库后,可以通过路由闭包和控制器方法的请求接口类型提示来获取 PSR-7 请求:</p>
<pre><code>use Psr\Http\Message\ServerRequestInterface;
Route::get('/', function (ServerRequestInterface $request) {
//
});
</code></pre>
<h2 id="输入过滤-规范化">输入过滤 & 规范化</h2>
<p>默认情况下,Laravel 应用程序的全局中间件堆栈中包含了 <code>TrimStrings</code> 和 <code>ConvertEmptyStringsToNull</code> 中间件。 它们被放在 <code>App\Http\Kernel</code> 类的栈列表中。这些中间件将自动过滤掉请求中的字符串字段,并将空字符串字段转换为 <code>null</code>。 这样一来,你将不用担心路由和控制器的约束规范问题。</p>
<p>如果你想禁用这些行为, 你可以在应用程序中 <code>App\Http\Kernel</code> 类的 <code>$middleware</code> 属性中移除这两个中间件。</p>
<h2 id="获取输入">获取输入</h2>
<p>当处理包含数组的表单时,可以使用 「.」 运算符来访问数组的数据:</p>
<pre><code>$name = $request->input('products.0.name');
$names = $request->input('products.*.name');
</code></pre>
<h4 id="从查询字符串获取输入">从查询字符串获取输入</h4>
<p><code>input</code> 方法可以从整个请求体中获取数据(包括查询字符串), 而 <code>query</code> 方法仅仅从查询字符串中获取输入值:</p>
<pre><code>$name = $request->query('name');
</code></pre>
<h4 id="通过动态属性获取输入">通过动态属性获取输入</h4>
<p>你也可以通过 <code>Illuminate\Http\Request</code> 接口实例的动态属性访问用户的输入。例如你的一个表单中包含 <code>name</code> 字段,则可以通过下面这种方式获取:</p>
<pre><code>$name = $request->name;
</code></pre>
<h4 id="获取-json-输入">获取 JSON 输入</h4>
<p>当向应用传递 JSON 请求时,只要将请求头中的 Content-Type 设置为 <code>application/json</code> 后你便可以使用 <code>input</code>方法来获取 JSON 数据。你也可以使用「.」语法获取 JSON 数组内容:</p>
<pre><code>$name = $request->input('user.name');
</code></pre>
<h4 id="获取部分输入数据">获取部分输入数据</h4>
<p>如果需要获取输入数据的子集,你可以使用 <code>only</code> 或 <code>except</code> 方法。它们接受单个 <code>array</code> 或者动态参数列表:</p>
<pre><code>$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
</code></pre>
<h4 id="判断输入值是否存在">判断输入值是否存在</h4>
<p>你可以使用 <code>has</code> 来判断当前请求中是否含有指定的值。如果请求中存在该值则 <code>has</code> 方法将会返回 <code>true</code>:</p>
<pre><code>if ($request->has('name')) {
//
}
</code></pre>
<p>当给定一个数组时,<code>has</code> 将会判断指定的值是否全部存在:</p>
<pre><code>if ($request->has(['name', 'email'])) {
//
}
</code></pre>
<p><code>hasAny</code> 方法将会在指定的值有一个存在的情况下返回 <code>true</code>:</p>
<pre><code>if ($request->hasAny(['name', 'email'])) {
//
}
</code></pre>
<p>如果你想要判断一个值在请求中是否存在,并且不为空,可以使用 <code>filled</code> 方法:</p>
<pre><code>if ($request->filled('name')) {
//
}
</code></pre>
<p>如果你想要判断一个值在请求中是否缺失,可以使用 missing 方法:</p>
<pre><code>if ($request->missing('name')) {
//
}
</code></pre>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[集合]]></title>
<id>http://xiewxin.github.io/post/ji-he/</id>
<link href="http://xiewxin.github.io/post/ji-he/">
</link>
<updated>2020-06-21T15:17:52.000Z</updated>
<content type="html"><![CDATA[<h1 id="集合">集合</h1>
<h3 id="扩展集合">扩展集合</h3>
<p>集合都是「可宏扩展」(macroable) 的,它允许你在执行时将其它方法添加到 Collection 类。例如,通过下面的代码在 <code>Collection</code> 类中添加一个 <code>toUpper</code> 方法:</p>
<pre><code>use Illuminate\Support\Collection;
use Illuminate\Support\Str;
Collection::macro('toUpper', function () {
return $this->map(function ($value) {
return Str::upper($value);
});
});
$collection = collect(['first', 'second']);
$upper = $collection->toUpper();
// ['FIRST', 'SECOND']
</code></pre>
<p>通常,你应该在 服务提供者 内声明集合宏。</p>
<h2 id="可用方法">可用方法</h2>
<p>我们将讨论每个 <code>Collection</code> 类可用的方法。记住,所有这些方法都可以链式调用以流畅地操作底层数组。此外,几乎所有方法都返回一个新的 <code>Collection</code> 实例,允许你在需要时保存集合的原始副本:</p>
<p>all<br>
average<br>
avg<br>
chunk<br>
collapse<br>
collect<br>
combine<br>
concat<br>
contains<br>
containsStrict<br>
count<br>
countBy<br>
crossJoin<br>
dd<br>
diff<br>
diffAssoc<br>
diffKeys<br>
dump<br>
duplicates<br>
duplicatesStrict<br>
each<br>
eachSpread<br>
every<br>
except<br>
filter<br>
first<br>
firstWhere<br>
flatMap<br>
flatten<br>
flip<br>
forget<br>
forPage<br>
get<br>
groupBy<br>
has<br>
implode<br>
intersect<br>
intersectByKeys<br>
isEmpty<br>
isNotEmpty<br>
join<br>
keyBy<br>
keys<br>
last<br>
macro<br>
make<br>
map<br>
mapInto<br>
mapSpread<br>
mapToGroups<br>
mapWithKeys<br>
max<br>
median<br>
merge<br>
mergeRecursive<br>
min<br>
mode<br>
nth<br>
only<br>
pad<br>
partition<br>
pipe<br>
pluck<br>
pop<br>
prepend<br>
pull<br>
push<br>
put<br>
random<br>
reduce<br>
reject<br>
replace<br>
replaceRecursive<br>
reverse<br>
search<br>
shift<br>
shuffle<br>
skip<br>
slice<br>
some<br>
sort<br>
sortBy<br>
sortByDesc<br>
sortDesc<br>
sortKeys<br>
sortKeysDesc<br>
splice<br>
split<br>
sum<br>
take<br>
tap<br>
times<br>
toArray<br>
toJson<br>
transform<br>
union<br>
unique<br>
uniqueStrict<br>
unless<br>
unlessEmpty<br>
unlessNotEmpty<br>
unwrap<br>
values<br>
when<br>
whenEmpty<br>
whenNotEmpty<br>
where<br>
whereStrict<br>
whereBetween<br>
whereIn<br>
whereInStrict<br>
whereInstanceOf<br>
whereNotBetween<br>
whereNotIn<br>
whereNotInStrict<br>
whereNotNull<br>
whereNull<br>
wrap<br>
zip</p>
<h2 id="方法列表">方法列表</h2>
<h4 id="all"><code>all()</code></h4>
<p><code>all</code> 方法返回代表集合的底层数组:</p>
<pre><code>collect([1, 2, 3])->all();
// [1, 2, 3]
</code></pre>
<h4 id="average"><code>average()</code></h4>
<p><code>avg</code> 方法的别名。</p>
<h4 id="avg"><code>avg()</code></h4>
<p><code>avg</code> 方法返回指定键的 平均值:</p>
<pre><code>$average = collect([['foo' => 10], ['foo' => 10], ['foo' => 20], ['foo' => 40]])->avg('foo');
// 20
$average = collect([1, 1, 2, 4])->avg();
// 2
</code></pre>
<h4 id="chunk"><code>chunk()</code></h4>
<p><code>chunk</code> 方法把集合分割成多个指定大小的较小集合:</p>
<pre><code>$collection = collect([1, 2, 3, 4, 5, 6, 7]);
$chunks = $collection->chunk(4);
$chunks->toArray();
// [[1, 2, 3, 4], [5, 6, 7]]
</code></pre>
<p>当使用如 Bootstrap 那样的栅格系统时,该方法在 视图 中相当有用。想象一下你有个想在栅格显示的Eloquent 模型:</p>
<pre><code>@foreach ($products->chunk(3) as $chunk)
<div class="row">
@foreach ($chunk as $product)
<div class="col-xs-4">{{ $product->name }}</div>
@endforeach
</div>
@endforeach
</code></pre>
<h4 id="collapse"><code>collapse()</code></h4>
<p><code>collapse</code> 方法把一个多数组集合坍缩为单个扁平的集合:</p>
<pre><code>$collection = collect([[1, 2, 3], [4, 5, 6], [7, 8, 9]]);
$collapsed = $collection->collapse();
$collapsed->all();
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
</code></pre>
<h4 id="combine"><code>combine()</code></h4>
<p><code>combine</code> 方法将一个集合的值作为键,与另一个数组或集合的值进行结合:</p>
<pre><code>$collection = collect(['name', 'age']);
$combined = $collection->combine(['George', 29]);
$combined->all();
// ['name' => 'George', 'age' => 29]
</code></pre>
<h4 id="collect"><code>collect()</code></h4>
<p><code>collect</code> 方法返回一个包含当前集合所含元素的新 <code>Collection</code> 实例:</p>
<pre><code>$collectionA = collect([1, 2, 3]);
$collectionB = $collectionA->collect();
$collectionB->all();
// [1, 2, 3]
</code></pre>
<p><code>collect</code> 方法从根本上对将 懒集合 转换为标准 <code>Collection</code> 实例有用:</p>
<pre><code>$lazyCollection = LazyCollection::make(function () {
yield 1;
yield 2;
yield 3;
});
$collection = $lazyCollection->collect();
get_class($collection);
// 'Illuminate\Support\Collection'
$collection->all();
// [1, 2, 3]
</code></pre>
<h4 id="concat"><code>concat()</code></h4>
<p><code>concat</code> 方法在集合的末端附加指定的 <code>数组</code> 或集合值:</p>
<pre><code>$collection = collect(['John Doe']);
$concatenated = $collection->concat(['Jane Doe'])->concat(['name' => 'Johnny Doe']);
$concatenated->all();
// ['John Doe', 'Jane Doe', 'Johnny Doe']
</code></pre>
<h4 id="contains"><code>contains()</code></h4>
<p><code>contains</code> 方法检查集合有否包含指定的元素:</p>
<pre><code>$collection = collect(['name' => 'Desk', 'price' => 100]);
$collection->contains('Desk');
// true
$collection->contains('New York');
// false
</code></pre>
<p>你也可以传递一个键 / 值对给 <code>contains</code> 方法,它将检查集合有否存在指定的键 / 值对:</p>
<pre><code>$collection = collect([
['product' => 'Desk', 'price' => 200],
['product' => 'Chair', 'price' => 100],
]);
$collection->contains('product', 'Bookcase');
// false
</code></pre>
<p>最后,你也可以传递一个回调函数给 <code>contains</code> 方法去执行你的真值检验:</p>
<pre><code>$collection = collect([1, 2, 3, 4, 5]);
$collection->contains(function ($value, $key) {
return $value > 5;
});
// false
</code></pre>
<p><code>contains</code> 方法用 “松散” 比较检查元素值,意味着整数值的字符串会被视同等值的整数。用 <code>containsStrict</code> 方法使用 “严格” 比较过滤。</p>
<h4 id="containsstrict"><code>containsStrict()</code></h4>
<p>这个方法和 <code>contains</code> 方法类似;但是它却是使用了「严格」比较来比较所有的值。</p>
<h4 id="count"><code>count()</code></h4>
<p><code>count</code> 方法返回这个集合内集合项的总数量:</p>
<pre><code>$collection = collect([1, 2, 3, 4]);
$collection->count();
// 4
</code></pre>
<h4 id="countby"><code>countBy()</code></h4>
<p><code>countBy</code> 方法计算集合中每个值的出现次数。默认情况下,该方法计算每个元素的出现次数:</p>
<pre><code>$collection = collect([1, 2, 2, 2, 3]);
$counted = $collection->countBy();
$counted->all();
// [1 => 1, 2 => 3, 3 => 1]
</code></pre>
<p>但是,你也可以向 <code>countBy</code> 传递一个回调函数来计算自定义的值出现的次数:</p>
$counted = $collection->countBy(function ($email) {
return substr(strrchr($email, "@"), 1);
});
$counted->all();
// ['gmail.com' => 2, 'yahoo.com' => 1]
</code></pre>
<h4 id="crossjoin"><code>crossJoin()</code></h4>
<p><code>crossJoin</code> 方法交叉连接指定数组或集合的值,返回所有可能排列的笛卡尔积:</p>
<pre><code>$collection = collect([1, 2]);
$matrix = $collection->crossJoin(['a', 'b']);
$matrix->all();
/*
[
[1, 'a'],
[1, 'b'],
[2, 'a'],
[2, 'b'],
]
*/
$collection = collect([1, 2]);
$matrix = $collection->crossJoin(['a', 'b'], ['I', 'II']);
$matrix->all();
/*
[
[1, 'a', 'I'],
[1, 'a', 'II'],
[1, 'b', 'I'],
[1, 'b', 'II'],
[2, 'a', 'I'],
[2, 'a', 'II'],
[2, 'b', 'I'],
[2, 'b', 'II'],
]
*/
</code></pre>
<h4 id="dd"><code>dd()</code></h4>
<p><code>dd</code> 方法用于打印集合元素并中断脚本执行:</p>
<pre><code>$collection = collect(['John Doe', 'Jane Doe']);
$collection->dd();
/*
Collection {
#items: array:2 [
0 => "John Doe"
1 => "Jane Doe"
]
}
*/
</code></pre>
<p>如果你不想中断执行脚本,请使用 <code>dump</code> 方法替代。</p>
<h4 id="diff"><code>diff()</code></h4>
<p><code>diff</code> 方法将集合与其它集合或者 PHP 数组进行值的比较。然后返回原集合中存在而指定集合中不存在的值:</p>
<pre><code>$collection = collect([1, 2, 3, 4, 5]);
$diff = $collection->diff([2, 4, 6, 8]);
$diff->all();
// [1, 3, 5]
</code></pre>
<h4 id="diffassoc"><code>diffAssoc()</code></h4>
<p><code>diffAssoc</code> 方法与另外一个集合或基于 PHP 数组的键 / 值对(<code>keys and values</code>)进行比较。这个方法将会返回原集合不存在于指定集合的键 / 值对:</p>
<pre><code>$collection = collect([
'color' => 'orange',
'type' => 'fruit',
'remain' => 6
]);
$diff = $collection->diffAssoc([
'color' => 'yellow',
'type' => 'fruit',
'remain' => 3,
'used' => 6,
]);
$diff->all();
// ['color' => 'orange', 'remain' => 6]
</code></pre>
<h4 id="diffkeys"><code>diffKeys()</code></h4>
<p><code>diffKeys</code> 方法和另外一个集合或 PHP 数组的键(<code>keys</code>)进行比较,然后返回原集合中存在而指定集合中不存在键所对应的键 / 值对:</p>
<pre><code>$collection = collect([
'one' => 10,
'two' => 20,
'three' => 30,
'four' => 40,
'five' => 50,
]);
$diff = $collection->diffKeys([