我的个人博客:逐步前行STEP

示例:
1、将文章按类型的分组,并获取类型分组中最新的一篇文章

select author,max(`updated_at`) as updated_at from articles 
    group by category_id
    order by updated_at desc

2、将文章按类型的分组,并获取类型分组中阅读量最小的一篇文章

select author,min(`read_cnt`) as read_cnt from articles 
    group by category_id
    order by read_cnt

我的个人博客:逐步前行STEP

1、执行单例测试

./vendor/bin/phpunit

2、执行指定单例测试文件

./vendor/bin/phpunit   tests/BlogTest.php

3、执行指定测试函数

./vendor/bin/phpunit  --filter testPostArticle

4、执行指定文件的指定测试函数

./vendor/bin/phpunit  --filter testPostArticle  tests/BlogTest.php

我的个人博客:逐步前行STEP

1、first

返回集合第一个通过指定测试的元素:

collect([1, 2, 3, 4])->first();

// 1
collect([1, 2, 3, 4])->first(function ($value, $key) {
    return $value > 2;
});

// 3

2、last

返回集合中,最后一个通过指定测试的元素:

collect([1, 2, 3, 4])->last(function ($value, $key) {
    return $value < 3;
});

// 2
collect([1, 2, 3, 4])->last();

// 4

3、keyBy

以指定键的值作为集合项目的键。如果几个数据项有相同的键,那在新集合中只显示最后一项:

$collection = collect([
    ['product_id' => 'prod-100', 'name' => 'desk'],
    ['product_id' => 'prod-200', 'name' => 'chair'],
]);

$keyed = $collection->keyBy('product_id');

$keyed->all();

/*
    [
        'prod-100' => ['product_id' => 'prod-100', 'name' => 'Desk'],
        'prod-200' => ['product_id' => 'prod-200', 'name' => 'Chair'],
    ]
*/
$keyed = $collection->keyBy(function ($item) {
    return strtoupper($item['product_id']);
});

$keyed->all();

/*
    [
        'PROD-100' => ['product_id' => 'prod-100', 'name' => 'Desk'],
        'PROD-200' => ['product_id' => 'prod-200', 'name' => 'Chair'],
    ]
*/

4、map

遍历整个集合并将每一个数值传入回调函数。回调函数可以任意修改并返回项目,形成修改过的项目组成的新集合

$collection = collect([1, 2, 3, 4, 5]);

$multiplied = $collection->map(function ($item, $key) {
    return $item * 2;
});

$multiplied->all();

// [2, 4, 6, 8, 10]

5、mapWithKeys

遍历整个集合并将每一个数值传入回调函数。回调函数返回包含一个键值对的关联数组

$collection = collect([
    [
        'name' => 'John',
        'department' => 'Sales',
        'email' => 'john@example.com'
    ],
    [
        'name' => 'Jane',
        'department' => 'Marketing',
        'email' => 'jane@example.com'
    ]
]);

$keyed = $collection->mapWithKeys(function ($item) {
    return [$item['email'] => $item['name']];
});

$keyed->all();

/*
    [
        'john@example.com' => 'John',
        'jane@example.com' => 'Jane',
    ]
*/

6、merge

合并数组进集合。数组「键」对应的数值会覆盖集合「键」对应的数值:

$collection = collect(['product_id' => 1, 'price' => 100]);

$merged = $collection->merge(['price' => 200, 'discount' => false]);

$merged->all();

// ['product_id' => 1, 'price' => 200, 'discount' => false]

7、only

返回集合中指定键的所有项目

$collection = collect(['product_id' => 1, 'name' => 'Desk', 'price' => 100, 'discount' => false]);

$filtered = $collection->only(['product_id', 'name']);

$filtered->all();

// ['product_id' => 1, 'name' => 'Desk']

8、pluck

获取集合中指定「键」所有对应的值

$collection = collect([
    ['product_id' => 'prod-100', 'name' => 'Desk'],
    ['product_id' => 'prod-200', 'name' => 'Chair'],
]);

$plucked = $collection->pluck('name');

$plucked->all();

// ['Desk', 'Chair']
$plucked = $collection->pluck('name', 'product_id');

$plucked->all();

// ['prod-100' => 'Desk', 'prod-200' => 'Chair']

9、reduce

reduce 方法将集合缩减到单个数值,该方法会将每次迭代的结果传入到下一次迭代

$collection = collect([1, 2, 3]);

$total = $collection->reduce(function ($carry, $item) {
    return $carry + $item;
});

// 6
第一次迭代时 $carry 的数值为 null;然而你也可以传入第二个参数进 reduce 以指定它的初始值:

$collection->reduce(function ($carry, $item) {
    return $carry + $item;
}, 4);

// 10

10、search

search 方法在集合内搜索指定的数值并返回找到的键。假如找不到项目,则返回 false

$collection = collect([2, 4, 6, 8]);

$collection->search(4);

// 1
$collection->search(function ($item, $key) {
    return $item > 5;
});

// 2

我的个人博客:逐步前行STEP

安装MongoDB

1、下载源码

在mongodb官方下载自己需要的版本:https://www.mongodb.com/download-center/community

2、解压

tar -zxvf mongodb-linux-x86_64-4.0.6.tgz

3、创建配置文件

#vi mongodb.conf
写入:
port=27017 #端口
dbpath=/usr/local/mongodb/data #数据库存文件存放目录
logpath=/usr/local/mongodb/log/mongodb.log #日志文件存放路径
logappend=true #使用追加的方式写日志
fork=true #以守护进程的方式运行,创建服务器进程
maxConns=100 #最大同时连接数
noauth=true #不启用验证
journal=true #每次写入会记录一条操作日志(通过journal可以重新构造出写入的数据)。
#即使宕机,启动时wiredtiger会先将数据恢复到最近一次的checkpoint点,然后重放后续的journal日志来恢复。
storageEngine=wiredTiger  #存储引擎有mmapv1、wiretiger、mongorocks
bind_ip = 0.0.0.0  #这样就可外部访问了,例如从win10中去连虚拟机中的MongoDB

5、配置环境变量

#vi /etc/profile
写入:export PATH=/usr/local/mongodb/bin:$PATH
#source /etc/profile

6、使用配置文件启动mongo

mongo -f /usr/local/mongo/mongodb.conf

7、将mongodb配置成服务

vi /etc/init.d/mongodb
写入:
#!/bin/sh
#
#mongod - Startup script for mongod
#
# chkconfig: - 85 15
# description: Mongodb database.
# processname: mongod
# Source function library

. /etc/rc.d/init.d/functions
# things from mongod.conf get there by mongod reading it
# OPTIONS
OPTIONS=" -f /usr/local/mongodb/mongodb.conf  &"
#mongod
mongod="/usr/local/mongodb/bin/mongod"
lockfile=/var/lock/subsys/mongod
start()
{
  echo -n $"Starting mongod: "
  daemon $mongod $OPTIONS
  RETVAL=$?
  echo
  [ $RETVAL -eq 0 ] && touch $lockfile
}

stop()
{
  echo -n $"Stopping mongod: "
  killproc $mongod -QUIT
  RETVAL=$?
  echo
  [ $RETVAL -eq 0 ] && rm -f $lockfile
}

restart () {
        stop
        start
}
ulimit -n 12000
RETVAL=0

case "$1" in
  start)
    start
    ;;
  stop)
    stop
    ;;
  restart|reload|force-reload)
    restart
    ;;
  condrestart)
    [ -f $lockfile ] && restart || :
    ;;
  status)
    status $mongod
    RETVAL=$?
    ;;
  *)
    echo "Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
    RETVAL=1
esac
exit $RETVAL

将启动脚本设置可执行权限

chmod +x /etc/init.d/mongodb

8、设置开机启动

chkconfig   --add  mongodb
chkconfig mongodb on

9、开启、关闭mongodb服务

service mongodb start
service mongodb stop
service mongodb restart

我的个人博客:逐步前行STEP

有时候我们使用Laravel-admin管理数据时,需要保存一些通过程序运算出来的数据,而不只是存储写在表单中的数据,也就是需要在保存数据前可以设置或改变数据。
比如存在这么个需求:

为了快速创建\管理一些测试数据,在Admin管理端创建一个用户账户的同时,创建相关的用户信息,用户订单、地址库等等一系列信息。

以这个需求中用户关联的数据量来说,每个数据都手动输入的话,效率太低了,所以只能自动创建。
所以实现的思路是这样的,表单中只有用户的基本信息,其它的订单、地址都是在执行store函数前自动生成的,然后关联保存即可。
先看Form.php的store函数源码:

public function store()
    {
        $data = Input::all();
        ......
    }

数据来源是request对象,所以,轻而易举地想到:

在store之前往request中塞入订单、地址的关联数据

这个数据的格式在我的另一篇博文中有详细解释:laravel-admin grid中使用switch操作一对一关联属性,但是执行提交后发现并没有成功保存,于是走一波源码调试。
首先看到更新关联模型数据的代码:

 public function store()
    {
......

        DB::transaction(function () {
            $inserts = $this->prepareInsert($this->updates);

            foreach ($inserts as $column => $value) {
                $this->model->setAttribute($column, $value);
            }
            $this->model->save();

            //在这里保更新关联模型
            $this->updateRelation($this->relations);
        });
......
    }

继续进入updateRelation方法跟踪:

protected function updateRelation($relationsData)
    {
        foreach ($relationsData as $name => $values) {

            if (!method_exists($this->model, $name)) {
                continue;
            }
            $relation = $this->model->$name();

            //在这里判定是否是一对一
            $oneToOneRelation = $relation instanceof Relations\HasOne
                || $relation instanceof Relations\MorphOne
                || $relation instanceof Relations\BelongsTo;

            //在这里做一个预处理
            $prepared = $this->prepareUpdate([$name => $values], $oneToOneRelation);
            //预处理的结果为空则没有后续处理
            if (empty($prepared)) {
                continue;
            }

经过打断点调试,发现我在store之前插入的订单、地址关联数据并没有通过预处理,所以再来看看prepareUpdate预处理是什么鬼:

protected function prepareUpdate(array $updates, $oneToOneRelation = false)
    {
        $prepared = [];

        /** @var Field $field */
        //$this->builder->fields() 就是表单字段相关属性
        foreach ($this->builder->fields() as $field) {
            $columns = $field->column();//这个是字段名称了

            // If column not in input array data, then continue.
            if (!array_has($updates, $columns)) {//关键在这,如果表单字段不在request的数据中就过滤掉
                continue;
            }

      ......

    }

在上面的注释中,清楚地表明了一个状况:

form表单的提交保存只能保存表单中有的字段,不然都会被过滤掉。

所以,我们需要让Laravel-admin认为我们表单中有订单、地址关联字段,根据我们的需求,很容易想到使用hidden组件:

只要把所有关联关系需要更新的字段都使用hidden列出来即可,不需要赋值

而且在store前,如果根据某些条件不需要保存这个关联关系的话,直接使用request的offsetUnset将那个关联关系整体删除即可。